~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/isa/es1688/es1688_lib.c

Version: ~ [ linux-5.14-rc3 ] ~ [ linux-5.13.5 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.53 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.135 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.198 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.240 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.276 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.276 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
  3  *  Routines for control of ESS ES1688/688/488 chip
  4  *
  5  *
  6  *   This program is free software; you can redistribute it and/or modify
  7  *   it under the terms of the GNU General Public License as published by
  8  *   the Free Software Foundation; either version 2 of the License, or
  9  *   (at your option) any later version.
 10  *
 11  *   This program is distributed in the hope that it will be useful,
 12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  *   GNU General Public License for more details.
 15  *
 16  *   You should have received a copy of the GNU General Public License
 17  *   along with this program; if not, write to the Free Software
 18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 19  *
 20  */
 21 
 22 #include <linux/init.h>
 23 #include <linux/interrupt.h>
 24 #include <linux/delay.h>
 25 #include <linux/slab.h>
 26 #include <linux/ioport.h>
 27 #include <sound/core.h>
 28 #include <sound/es1688.h>
 29 #include <sound/initval.h>
 30 
 31 #include <asm/io.h>
 32 #include <asm/dma.h>
 33 
 34 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 35 MODULE_DESCRIPTION("ESS ESx688 lowlevel module");
 36 MODULE_LICENSE("GPL");
 37 
 38 static int snd_es1688_dsp_command(struct snd_es1688 *chip, unsigned char val)
 39 {
 40         int i;
 41 
 42         for (i = 10000; i; i--)
 43                 if ((inb(ES1688P(chip, STATUS)) & 0x80) == 0) {
 44                         outb(val, ES1688P(chip, COMMAND));
 45                         return 1;
 46                 }
 47 #ifdef CONFIG_SND_DEBUG
 48         printk(KERN_DEBUG "snd_es1688_dsp_command: timeout (0x%x)\n", val);
 49 #endif
 50         return 0;
 51 }
 52 
 53 static int snd_es1688_dsp_get_byte(struct snd_es1688 *chip)
 54 {
 55         int i;
 56 
 57         for (i = 1000; i; i--)
 58                 if (inb(ES1688P(chip, DATA_AVAIL)) & 0x80)
 59                         return inb(ES1688P(chip, READ));
 60         snd_printd("es1688 get byte failed: 0x%lx = 0x%x!!!\n", ES1688P(chip, DATA_AVAIL), inb(ES1688P(chip, DATA_AVAIL)));
 61         return -ENODEV;
 62 }
 63 
 64 static int snd_es1688_write(struct snd_es1688 *chip,
 65                             unsigned char reg, unsigned char data)
 66 {
 67         if (!snd_es1688_dsp_command(chip, reg))
 68                 return 0;
 69         return snd_es1688_dsp_command(chip, data);
 70 }
 71 
 72 static int snd_es1688_read(struct snd_es1688 *chip, unsigned char reg)
 73 {
 74         /* Read a byte from an extended mode register of ES1688 */
 75         if (!snd_es1688_dsp_command(chip, 0xc0))
 76                 return -1;
 77         if (!snd_es1688_dsp_command(chip, reg))
 78                 return -1;
 79         return snd_es1688_dsp_get_byte(chip);
 80 }
 81 
 82 void snd_es1688_mixer_write(struct snd_es1688 *chip,
 83                             unsigned char reg, unsigned char data)
 84 {
 85         outb(reg, ES1688P(chip, MIXER_ADDR));
 86         udelay(10);
 87         outb(data, ES1688P(chip, MIXER_DATA));
 88         udelay(10);
 89 }
 90 
 91 static unsigned char snd_es1688_mixer_read(struct snd_es1688 *chip, unsigned char reg)
 92 {
 93         unsigned char result;
 94 
 95         outb(reg, ES1688P(chip, MIXER_ADDR));
 96         udelay(10);
 97         result = inb(ES1688P(chip, MIXER_DATA));
 98         udelay(10);
 99         return result;
100 }
101 
102 static int snd_es1688_reset(struct snd_es1688 *chip)
103 {
104         int i;
105 
106         outb(3, ES1688P(chip, RESET));          /* valid only for ESS chips, SB -> 1 */
107         udelay(10);
108         outb(0, ES1688P(chip, RESET));
109         udelay(30);
110         for (i = 0; i < 1000 && !(inb(ES1688P(chip, DATA_AVAIL)) & 0x80); i++);
111         if (inb(ES1688P(chip, READ)) != 0xaa) {
112                 snd_printd("ess_reset at 0x%lx: failed!!!\n", chip->port);
113                 return -ENODEV;
114         }
115         snd_es1688_dsp_command(chip, 0xc6);     /* enable extended mode */
116         return 0;
117 }
118 
119 static int snd_es1688_probe(struct snd_es1688 *chip)
120 {
121         unsigned long flags;
122         unsigned short major, minor, hw;
123         int i;
124 
125         /*
126          *  initialization sequence
127          */
128 
129         spin_lock_irqsave(&chip->reg_lock, flags);      /* Some ESS1688 cards need this */
130         inb(ES1688P(chip, ENABLE1));    /* ENABLE1 */
131         inb(ES1688P(chip, ENABLE1));    /* ENABLE1 */
132         inb(ES1688P(chip, ENABLE1));    /* ENABLE1 */
133         inb(ES1688P(chip, ENABLE2));    /* ENABLE2 */
134         inb(ES1688P(chip, ENABLE1));    /* ENABLE1 */
135         inb(ES1688P(chip, ENABLE2));    /* ENABLE2 */
136         inb(ES1688P(chip, ENABLE1));    /* ENABLE1 */
137         inb(ES1688P(chip, ENABLE1));    /* ENABLE1 */
138         inb(ES1688P(chip, ENABLE2));    /* ENABLE2 */
139         inb(ES1688P(chip, ENABLE1));    /* ENABLE1 */
140         inb(ES1688P(chip, ENABLE0));    /* ENABLE0 */
141 
142         if (snd_es1688_reset(chip) < 0) {
143                 snd_printdd("ESS: [0x%lx] reset failed... 0x%x\n", chip->port, inb(ES1688P(chip, READ)));
144                 spin_unlock_irqrestore(&chip->reg_lock, flags);
145                 return -ENODEV;
146         }
147         snd_es1688_dsp_command(chip, 0xe7);     /* return identification */
148 
149         for (i = 1000, major = minor = 0; i; i--) {
150                 if (inb(ES1688P(chip, DATA_AVAIL)) & 0x80) {
151                         if (major == 0) {
152                                 major = inb(ES1688P(chip, READ));
153                         } else {
154                                 minor = inb(ES1688P(chip, READ));
155                         }
156                 }
157         }
158 
159         spin_unlock_irqrestore(&chip->reg_lock, flags);
160 
161         snd_printdd("ESS: [0x%lx] found.. major = 0x%x, minor = 0x%x\n", chip->port, major, minor);
162 
163         chip->version = (major << 8) | minor;
164         if (!chip->version)
165                 return -ENODEV; /* probably SB */
166 
167         hw = ES1688_HW_AUTO;
168         switch (chip->version & 0xfff0) {
169         case 0x4880:
170                 snd_printk(KERN_ERR "[0x%lx] ESS: AudioDrive ES488 detected, "
171                            "but driver is in another place\n", chip->port);
172                 return -ENODEV;
173         case 0x6880:
174                 hw = (chip->version & 0x0f) >= 8 ? ES1688_HW_1688 : ES1688_HW_688;
175                 break;
176         default:
177                 snd_printk(KERN_ERR "[0x%lx] ESS: unknown AudioDrive chip "
178                            "with version 0x%x (Jazz16 soundcard?)\n",
179                            chip->port, chip->version);
180                 return -ENODEV;
181         }
182 
183         spin_lock_irqsave(&chip->reg_lock, flags);
184         snd_es1688_write(chip, 0xb1, 0x10);     /* disable IRQ */
185         snd_es1688_write(chip, 0xb2, 0x00);     /* disable DMA */
186         spin_unlock_irqrestore(&chip->reg_lock, flags);
187 
188         /* enable joystick, but disable OPL3 */
189         spin_lock_irqsave(&chip->mixer_lock, flags);
190         snd_es1688_mixer_write(chip, 0x40, 0x01);
191         spin_unlock_irqrestore(&chip->mixer_lock, flags);
192 
193         return 0;
194 }
195 
196 static int snd_es1688_init(struct snd_es1688 * chip, int enable)
197 {
198         static int irqs[16] = {-1, -1, 0, -1, -1, 1, -1, 2, -1, 0, 3, -1, -1, -1, -1, -1};
199         unsigned long flags;
200         int cfg, irq_bits, dma, dma_bits, tmp, tmp1;
201 
202         /* ok.. setup MPU-401 port and joystick and OPL3 */
203         cfg = 0x01;             /* enable joystick, but disable OPL3 */
204         if (enable && chip->mpu_port >= 0x300 && chip->mpu_irq > 0 && chip->hardware != ES1688_HW_688) {
205                 tmp = (chip->mpu_port & 0x0f0) >> 4;
206                 if (tmp <= 3) {
207                         switch (chip->mpu_irq) {
208                         case 9:
209                                 tmp1 = 4;
210                                 break;
211                         case 5:
212                                 tmp1 = 5;
213                                 break;
214                         case 7:
215                                 tmp1 = 6;
216                                 break;
217                         case 10:
218                                 tmp1 = 7;
219                                 break;
220                         default:
221                                 tmp1 = 0;
222                         }
223                         if (tmp1) {
224                                 cfg |= (tmp << 3) | (tmp1 << 5);
225                         }
226                 }
227         }
228 #if 0
229         snd_printk(KERN_DEBUG "mpu cfg = 0x%x\n", cfg);
230 #endif
231         spin_lock_irqsave(&chip->reg_lock, flags);
232         snd_es1688_mixer_write(chip, 0x40, cfg);
233         spin_unlock_irqrestore(&chip->reg_lock, flags);
234         /* --- */
235         spin_lock_irqsave(&chip->reg_lock, flags);
236         snd_es1688_read(chip, 0xb1);
237         snd_es1688_read(chip, 0xb2);
238         spin_unlock_irqrestore(&chip->reg_lock, flags);
239         if (enable) {
240                 cfg = 0xf0;     /* enable only DMA counter interrupt */
241                 irq_bits = irqs[chip->irq & 0x0f];
242                 if (irq_bits < 0) {
243                         snd_printk(KERN_ERR "[0x%lx] ESS: bad IRQ %d "
244                                    "for ES1688 chip!!\n",
245                                    chip->port, chip->irq);
246 #if 0
247                         irq_bits = 0;
248                         cfg = 0x10;
249 #endif
250                         return -EINVAL;
251                 }
252                 spin_lock_irqsave(&chip->reg_lock, flags);
253                 snd_es1688_write(chip, 0xb1, cfg | (irq_bits << 2));
254                 spin_unlock_irqrestore(&chip->reg_lock, flags);
255                 cfg = 0xf0;     /* extended mode DMA enable */
256                 dma = chip->dma8;
257                 if (dma > 3 || dma == 2) {
258                         snd_printk(KERN_ERR "[0x%lx] ESS: bad DMA channel %d "
259                                    "for ES1688 chip!!\n", chip->port, dma);
260 #if 0
261                         dma_bits = 0;
262                         cfg = 0x00;     /* disable all DMA */
263 #endif
264                         return -EINVAL;
265                 } else {
266                         dma_bits = dma;
267                         if (dma != 3)
268                                 dma_bits++;
269                 }
270                 spin_lock_irqsave(&chip->reg_lock, flags);
271                 snd_es1688_write(chip, 0xb2, cfg | (dma_bits << 2));
272                 spin_unlock_irqrestore(&chip->reg_lock, flags);
273         } else {
274                 spin_lock_irqsave(&chip->reg_lock, flags);
275                 snd_es1688_write(chip, 0xb1, 0x10);     /* disable IRQ */
276                 snd_es1688_write(chip, 0xb2, 0x00);     /* disable DMA */
277                 spin_unlock_irqrestore(&chip->reg_lock, flags);
278         }
279         spin_lock_irqsave(&chip->reg_lock, flags);
280         snd_es1688_read(chip, 0xb1);
281         snd_es1688_read(chip, 0xb2);
282         snd_es1688_reset(chip);
283         spin_unlock_irqrestore(&chip->reg_lock, flags);
284         return 0;
285 }
286 
287 /*
288 
289  */
290 
291 static struct snd_ratnum clocks[2] = {
292         {
293                 .num = 795444,
294                 .den_min = 1,
295                 .den_max = 128,
296                 .den_step = 1,
297         },
298         {
299                 .num = 397722,
300                 .den_min = 1,
301                 .den_max = 128,
302                 .den_step = 1,
303         }
304 };
305 
306 static struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks  = {
307         .nrats = 2,
308         .rats = clocks,
309 };
310 
311 static void snd_es1688_set_rate(struct snd_es1688 *chip, struct snd_pcm_substream *substream)
312 {
313         struct snd_pcm_runtime *runtime = substream->runtime;
314         unsigned int bits, divider;
315 
316         if (runtime->rate_num == clocks[0].num)
317                 bits = 256 - runtime->rate_den;
318         else
319                 bits = 128 - runtime->rate_den;
320         /* set filter register */
321         divider = 256 - 7160000*20/(8*82*runtime->rate);
322         /* write result to hardware */
323         snd_es1688_write(chip, 0xa1, bits);
324         snd_es1688_write(chip, 0xa2, divider);
325 }
326 
327 static int snd_es1688_ioctl(struct snd_pcm_substream *substream,
328                             unsigned int cmd, void *arg)
329 {
330         return snd_pcm_lib_ioctl(substream, cmd, arg);
331 }
332 
333 static int snd_es1688_trigger(struct snd_es1688 *chip, int cmd, unsigned char value)
334 {
335         int val;
336 
337         if (cmd == SNDRV_PCM_TRIGGER_STOP) {
338                 value = 0x00;
339         } else if (cmd != SNDRV_PCM_TRIGGER_START) {
340                 return -EINVAL;
341         }
342         spin_lock(&chip->reg_lock);
343         chip->trigger_value = value;
344         val = snd_es1688_read(chip, 0xb8);
345         if ((val < 0) || (val & 0x0f) == value) {
346                 spin_unlock(&chip->reg_lock);
347                 return -EINVAL; /* something is wrong */
348         }
349 #if 0
350         printk(KERN_DEBUG "trigger: val = 0x%x, value = 0x%x\n", val, value);
351         printk(KERN_DEBUG "trigger: pointer = 0x%x\n",
352                snd_dma_pointer(chip->dma8, chip->dma_size));
353 #endif
354         snd_es1688_write(chip, 0xb8, (val & 0xf0) | value);
355         spin_unlock(&chip->reg_lock);
356         return 0;
357 }
358 
359 static int snd_es1688_hw_params(struct snd_pcm_substream *substream,
360                                 struct snd_pcm_hw_params *hw_params)
361 {
362         return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
363 }
364 
365 static int snd_es1688_hw_free(struct snd_pcm_substream *substream)
366 {
367         return snd_pcm_lib_free_pages(substream);
368 }
369 
370 static int snd_es1688_playback_prepare(struct snd_pcm_substream *substream)
371 {
372         unsigned long flags;
373         struct snd_es1688 *chip = snd_pcm_substream_chip(substream);
374         struct snd_pcm_runtime *runtime = substream->runtime;
375         unsigned int size = snd_pcm_lib_buffer_bytes(substream);
376         unsigned int count = snd_pcm_lib_period_bytes(substream);
377 
378         chip->dma_size = size;
379         spin_lock_irqsave(&chip->reg_lock, flags);
380         snd_es1688_reset(chip);
381         snd_es1688_set_rate(chip, substream);
382         snd_es1688_write(chip, 0xb8, 4);        /* auto init DMA mode */
383         snd_es1688_write(chip, 0xa8, (snd_es1688_read(chip, 0xa8) & ~0x03) | (3 - runtime->channels));
384         snd_es1688_write(chip, 0xb9, 2);        /* demand mode (4 bytes/request) */
385         if (runtime->channels == 1) {
386                 if (snd_pcm_format_width(runtime->format) == 8) {
387                         /* 8. bit mono */
388                         snd_es1688_write(chip, 0xb6, 0x80);
389                         snd_es1688_write(chip, 0xb7, 0x51);
390                         snd_es1688_write(chip, 0xb7, 0xd0);
391                 } else {
392                         /* 16. bit mono */
393                         snd_es1688_write(chip, 0xb6, 0x00);
394                         snd_es1688_write(chip, 0xb7, 0x71);
395                         snd_es1688_write(chip, 0xb7, 0xf4);
396                 }
397         } else {
398                 if (snd_pcm_format_width(runtime->format) == 8) {
399                         /* 8. bit stereo */
400                         snd_es1688_write(chip, 0xb6, 0x80);
401                         snd_es1688_write(chip, 0xb7, 0x51);
402                         snd_es1688_write(chip, 0xb7, 0x98);
403                 } else {
404                         /* 16. bit stereo */
405                         snd_es1688_write(chip, 0xb6, 0x00);
406                         snd_es1688_write(chip, 0xb7, 0x71);
407                         snd_es1688_write(chip, 0xb7, 0xbc);
408                 }
409         }
410         snd_es1688_write(chip, 0xb1, (snd_es1688_read(chip, 0xb1) & 0x0f) | 0x50);
411         snd_es1688_write(chip, 0xb2, (snd_es1688_read(chip, 0xb2) & 0x0f) | 0x50);
412         snd_es1688_dsp_command(chip, ES1688_DSP_CMD_SPKON);
413         spin_unlock_irqrestore(&chip->reg_lock, flags);
414         /* --- */
415         count = -count;
416         snd_dma_program(chip->dma8, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
417         spin_lock_irqsave(&chip->reg_lock, flags);
418         snd_es1688_write(chip, 0xa4, (unsigned char) count);
419         snd_es1688_write(chip, 0xa5, (unsigned char) (count >> 8));
420         spin_unlock_irqrestore(&chip->reg_lock, flags);
421         return 0;
422 }
423 
424 static int snd_es1688_playback_trigger(struct snd_pcm_substream *substream,
425                                        int cmd)
426 {
427         struct snd_es1688 *chip = snd_pcm_substream_chip(substream);
428         return snd_es1688_trigger(chip, cmd, 0x05);
429 }
430 
431 static int snd_es1688_capture_prepare(struct snd_pcm_substream *substream)
432 {
433         unsigned long flags;
434         struct snd_es1688 *chip = snd_pcm_substream_chip(substream);
435         struct snd_pcm_runtime *runtime = substream->runtime;
436         unsigned int size = snd_pcm_lib_buffer_bytes(substream);
437         unsigned int count = snd_pcm_lib_period_bytes(substream);
438 
439         chip->dma_size = size;
440         spin_lock_irqsave(&chip->reg_lock, flags);
441         snd_es1688_reset(chip);
442         snd_es1688_set_rate(chip, substream);
443         snd_es1688_dsp_command(chip, ES1688_DSP_CMD_SPKOFF);
444         snd_es1688_write(chip, 0xb8, 0x0e);     /* auto init DMA mode */
445         snd_es1688_write(chip, 0xa8, (snd_es1688_read(chip, 0xa8) & ~0x03) | (3 - runtime->channels));
446         snd_es1688_write(chip, 0xb9, 2);        /* demand mode (4 bytes/request) */
447         if (runtime->channels == 1) {
448                 if (snd_pcm_format_width(runtime->format) == 8) {
449                         /* 8. bit mono */
450                         snd_es1688_write(chip, 0xb7, 0x51);
451                         snd_es1688_write(chip, 0xb7, 0xd0);
452                 } else {
453                         /* 16. bit mono */
454                         snd_es1688_write(chip, 0xb7, 0x71);
455                         snd_es1688_write(chip, 0xb7, 0xf4);
456                 }
457         } else {
458                 if (snd_pcm_format_width(runtime->format) == 8) {
459                         /* 8. bit stereo */
460                         snd_es1688_write(chip, 0xb7, 0x51);
461                         snd_es1688_write(chip, 0xb7, 0x98);
462                 } else {
463                         /* 16. bit stereo */
464                         snd_es1688_write(chip, 0xb7, 0x71);
465                         snd_es1688_write(chip, 0xb7, 0xbc);
466                 }
467         }
468         snd_es1688_write(chip, 0xb1, (snd_es1688_read(chip, 0xb1) & 0x0f) | 0x50);
469         snd_es1688_write(chip, 0xb2, (snd_es1688_read(chip, 0xb2) & 0x0f) | 0x50);
470         spin_unlock_irqrestore(&chip->reg_lock, flags);
471         /* --- */
472         count = -count;
473         snd_dma_program(chip->dma8, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
474         spin_lock_irqsave(&chip->reg_lock, flags);
475         snd_es1688_write(chip, 0xa4, (unsigned char) count);
476         snd_es1688_write(chip, 0xa5, (unsigned char) (count >> 8));
477         spin_unlock_irqrestore(&chip->reg_lock, flags);
478         return 0;
479 }
480 
481 static int snd_es1688_capture_trigger(struct snd_pcm_substream *substream,
482                                       int cmd)
483 {
484         struct snd_es1688 *chip = snd_pcm_substream_chip(substream);
485         return snd_es1688_trigger(chip, cmd, 0x0f);
486 }
487 
488 static irqreturn_t snd_es1688_interrupt(int irq, void *dev_id)
489 {
490         struct snd_es1688 *chip = dev_id;
491 
492         if (chip->trigger_value == 0x05)        /* ok.. playback is active */
493                 snd_pcm_period_elapsed(chip->playback_substream);
494         if (chip->trigger_value == 0x0f)        /* ok.. capture is active */
495                 snd_pcm_period_elapsed(chip->capture_substream);
496 
497         inb(ES1688P(chip, DATA_AVAIL)); /* ack interrupt */
498         return IRQ_HANDLED;
499 }
500 
501 static snd_pcm_uframes_t snd_es1688_playback_pointer(struct snd_pcm_substream *substream)
502 {
503         struct snd_es1688 *chip = snd_pcm_substream_chip(substream);
504         size_t ptr;
505         
506         if (chip->trigger_value != 0x05)
507                 return 0;
508         ptr = snd_dma_pointer(chip->dma8, chip->dma_size);
509         return bytes_to_frames(substream->runtime, ptr);
510 }
511 
512 static snd_pcm_uframes_t snd_es1688_capture_pointer(struct snd_pcm_substream *substream)
513 {
514         struct snd_es1688 *chip = snd_pcm_substream_chip(substream);
515         size_t ptr;
516         
517         if (chip->trigger_value != 0x0f)
518                 return 0;
519         ptr = snd_dma_pointer(chip->dma8, chip->dma_size);
520         return bytes_to_frames(substream->runtime, ptr);
521 }
522 
523 /*
524 
525  */
526 
527 static struct snd_pcm_hardware snd_es1688_playback =
528 {
529         .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
530                                  SNDRV_PCM_INFO_MMAP_VALID),
531         .formats =              SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
532         .rates =                SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
533         .rate_min =             4000,
534         .rate_max =             48000,
535         .channels_min =         1,
536         .channels_max =         2,
537         .buffer_bytes_max =     65536,
538         .period_bytes_min =     64,
539         .period_bytes_max =     65536,
540         .periods_min =          1,
541         .periods_max =          1024,
542         .fifo_size =            0,
543 };
544 
545 static struct snd_pcm_hardware snd_es1688_capture =
546 {
547         .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
548                                  SNDRV_PCM_INFO_MMAP_VALID),
549         .formats =              SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
550         .rates =                SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
551         .rate_min =             4000,
552         .rate_max =             48000,
553         .channels_min =         1,
554         .channels_max =         2,
555         .buffer_bytes_max =     65536,
556         .period_bytes_min =     64,
557         .period_bytes_max =     65536,
558         .periods_min =          1,
559         .periods_max =          1024,
560         .fifo_size =            0,
561 };
562 
563 /*
564 
565  */
566 
567 static int snd_es1688_playback_open(struct snd_pcm_substream *substream)
568 {
569         struct snd_es1688 *chip = snd_pcm_substream_chip(substream);
570         struct snd_pcm_runtime *runtime = substream->runtime;
571 
572         if (chip->capture_substream != NULL)
573                 return -EAGAIN;
574         chip->playback_substream = substream;
575         runtime->hw = snd_es1688_playback;
576         snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
577                                       &hw_constraints_clocks);
578         return 0;
579 }
580 
581 static int snd_es1688_capture_open(struct snd_pcm_substream *substream)
582 {
583         struct snd_es1688 *chip = snd_pcm_substream_chip(substream);
584         struct snd_pcm_runtime *runtime = substream->runtime;
585 
586         if (chip->playback_substream != NULL)
587                 return -EAGAIN;
588         chip->capture_substream = substream;
589         runtime->hw = snd_es1688_capture;
590         snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
591                                       &hw_constraints_clocks);
592         return 0;
593 }
594 
595 static int snd_es1688_playback_close(struct snd_pcm_substream *substream)
596 {
597         struct snd_es1688 *chip = snd_pcm_substream_chip(substream);
598 
599         chip->playback_substream = NULL;
600         return 0;
601 }
602 
603 static int snd_es1688_capture_close(struct snd_pcm_substream *substream)
604 {
605         struct snd_es1688 *chip = snd_pcm_substream_chip(substream);
606 
607         chip->capture_substream = NULL;
608         return 0;
609 }
610 
611 static int snd_es1688_free(struct snd_es1688 *chip)
612 {
613         if (chip->res_port) {
614                 snd_es1688_init(chip, 0);
615                 release_and_free_resource(chip->res_port);
616         }
617         if (chip->irq >= 0)
618                 free_irq(chip->irq, (void *) chip);
619         if (chip->dma8 >= 0) {
620                 disable_dma(chip->dma8);
621                 free_dma(chip->dma8);
622         }
623         kfree(chip);
624         return 0;
625 }
626 
627 static int snd_es1688_dev_free(struct snd_device *device)
628 {
629         struct snd_es1688 *chip = device->device_data;
630         return snd_es1688_free(chip);
631 }
632 
633 static const char *snd_es1688_chip_id(struct snd_es1688 *chip)
634 {
635         static char tmp[16];
636         sprintf(tmp, "ES%s688 rev %i", chip->hardware == ES1688_HW_688 ? "" : "1", chip->version & 0x0f);
637         return tmp;
638 }
639 
640 int snd_es1688_create(struct snd_card *card,
641                       unsigned long port,
642                       unsigned long mpu_port,
643                       int irq,
644                       int mpu_irq,
645                       int dma8,
646                       unsigned short hardware,
647                       struct snd_es1688 **rchip)
648 {
649         static struct snd_device_ops ops = {
650                 .dev_free =     snd_es1688_dev_free,
651         };
652                                 
653         struct snd_es1688 *chip;
654         int err;
655 
656         *rchip = NULL;
657         chip = kzalloc(sizeof(*chip), GFP_KERNEL);
658         if (chip == NULL)
659                 return -ENOMEM;
660         chip->irq = -1;
661         chip->dma8 = -1;
662         
663         if ((chip->res_port = request_region(port + 4, 12, "ES1688")) == NULL) {
664                 snd_printk(KERN_ERR "es1688: can't grab port 0x%lx\n", port + 4);
665                 snd_es1688_free(chip);
666                 return -EBUSY;
667         }
668         if (request_irq(irq, snd_es1688_interrupt, IRQF_DISABLED, "ES1688", (void *) chip)) {
669                 snd_printk(KERN_ERR "es1688: can't grab IRQ %d\n", irq);
670                 snd_es1688_free(chip);
671                 return -EBUSY;
672         }
673         chip->irq = irq;
674         if (request_dma(dma8, "ES1688")) {
675                 snd_printk(KERN_ERR "es1688: can't grab DMA8 %d\n", dma8);
676                 snd_es1688_free(chip);
677                 return -EBUSY;
678         }
679         chip->dma8 = dma8;
680 
681         spin_lock_init(&chip->reg_lock);
682         spin_lock_init(&chip->mixer_lock);
683         chip->card = card;
684         chip->port = port;
685         mpu_port &= ~0x000f;
686         if (mpu_port < 0x300 || mpu_port > 0x330)
687                 mpu_port = 0;
688         chip->mpu_port = mpu_port;
689         chip->mpu_irq = mpu_irq;
690         chip->hardware = hardware;
691 
692         if ((err = snd_es1688_probe(chip)) < 0) {
693                 snd_es1688_free(chip);
694                 return err;
695         }
696         if ((err = snd_es1688_init(chip, 1)) < 0) {
697                 snd_es1688_free(chip);
698                 return err;
699         }
700 
701         /* Register device */
702         if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
703                 snd_es1688_free(chip);
704                 return err;
705         }
706 
707         *rchip = chip;
708         return 0;
709 }
710 
711 static struct snd_pcm_ops snd_es1688_playback_ops = {
712         .open =                 snd_es1688_playback_open,
713         .close =                snd_es1688_playback_close,
714         .ioctl =                snd_es1688_ioctl,
715         .hw_params =            snd_es1688_hw_params,
716         .hw_free =              snd_es1688_hw_free,
717         .prepare =              snd_es1688_playback_prepare,
718         .trigger =              snd_es1688_playback_trigger,
719         .pointer =              snd_es1688_playback_pointer,
720 };
721 
722 static struct snd_pcm_ops snd_es1688_capture_ops = {
723         .open =                 snd_es1688_capture_open,
724         .close =                snd_es1688_capture_close,
725         .ioctl =                snd_es1688_ioctl,
726         .hw_params =            snd_es1688_hw_params,
727         .hw_free =              snd_es1688_hw_free,
728         .prepare =              snd_es1688_capture_prepare,
729         .trigger =              snd_es1688_capture_trigger,
730         .pointer =              snd_es1688_capture_pointer,
731 };
732 
733 int snd_es1688_pcm(struct snd_es1688 * chip, int device, struct snd_pcm ** rpcm)
734 {
735         struct snd_pcm *pcm;
736         int err;
737 
738         if ((err = snd_pcm_new(chip->card, "ESx688", device, 1, 1, &pcm)) < 0)
739                 return err;
740 
741         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_es1688_playback_ops);
742         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_es1688_capture_ops);
743 
744         pcm->private_data = chip;
745         pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
746         sprintf(pcm->name, snd_es1688_chip_id(chip));
747         chip->pcm = pcm;
748 
749         snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
750                                               snd_dma_isa_data(),
751                                               64*1024, 64*1024);
752 
753         if (rpcm)
754                 *rpcm = pcm;
755         return 0;
756 }
757 
758 /*
759  *  MIXER part
760  */
761 
762 static int snd_es1688_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
763 {
764         static char *texts[9] = {
765                 "Mic", "Mic Master", "CD", "AOUT",
766                 "Mic1", "Mix", "Line", "Master"
767         };
768 
769         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
770         uinfo->count = 1;
771         uinfo->value.enumerated.items = 8;
772         if (uinfo->value.enumerated.item > 7)
773                 uinfo->value.enumerated.item = 7;
774         strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
775         return 0;
776 }
777 
778 static int snd_es1688_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
779 {
780         struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);
781         ucontrol->value.enumerated.item[0] = snd_es1688_mixer_read(chip, ES1688_REC_DEV) & 7;
782         return 0;
783 }
784 
785 static int snd_es1688_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
786 {
787         struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);
788         unsigned long flags;
789         unsigned char oval, nval;
790         int change;
791         
792         if (ucontrol->value.enumerated.item[0] > 8)
793                 return -EINVAL;
794         spin_lock_irqsave(&chip->reg_lock, flags);
795         oval = snd_es1688_mixer_read(chip, ES1688_REC_DEV);
796         nval = (ucontrol->value.enumerated.item[0] & 7) | (oval & ~15);
797         change = nval != oval;
798         if (change)
799                 snd_es1688_mixer_write(chip, ES1688_REC_DEV, nval);
800         spin_unlock_irqrestore(&chip->reg_lock, flags);
801         return change;
802 }
803 
804 #define ES1688_SINGLE(xname, xindex, reg, shift, mask, invert) \
805 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
806   .info = snd_es1688_info_single, \
807   .get = snd_es1688_get_single, .put = snd_es1688_put_single, \
808   .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
809 
810 static int snd_es1688_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
811 {
812         int mask = (kcontrol->private_value >> 16) & 0xff;
813 
814         uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
815         uinfo->count = 1;
816         uinfo->value.integer.min = 0;
817         uinfo->value.integer.max = mask;
818         return 0;
819 }
820 
821 static int snd_es1688_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
822 {
823         struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);
824         unsigned long flags;
825         int reg = kcontrol->private_value & 0xff;
826         int shift = (kcontrol->private_value >> 8) & 0xff;
827         int mask = (kcontrol->private_value >> 16) & 0xff;
828         int invert = (kcontrol->private_value >> 24) & 0xff;
829         
830         spin_lock_irqsave(&chip->reg_lock, flags);
831         ucontrol->value.integer.value[0] = (snd_es1688_mixer_read(chip, reg) >> shift) & mask;
832         spin_unlock_irqrestore(&chip->reg_lock, flags);
833         if (invert)
834                 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
835         return 0;
836 }
837 
838 static int snd_es1688_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
839 {
840         struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);
841         unsigned long flags;
842         int reg = kcontrol->private_value & 0xff;
843         int shift = (kcontrol->private_value >> 8) & 0xff;
844         int mask = (kcontrol->private_value >> 16) & 0xff;
845         int invert = (kcontrol->private_value >> 24) & 0xff;
846         int change;
847         unsigned char oval, nval;
848         
849         nval = (ucontrol->value.integer.value[0] & mask);
850         if (invert)
851                 nval = mask - nval;
852         nval <<= shift;
853         spin_lock_irqsave(&chip->reg_lock, flags);
854         oval = snd_es1688_mixer_read(chip, reg);
855         nval = (oval & ~(mask << shift)) | nval;
856         change = nval != oval;
857         if (change)
858                 snd_es1688_mixer_write(chip, reg, nval);
859         spin_unlock_irqrestore(&chip->reg_lock, flags);
860         return change;
861 }
862 
863 #define ES1688_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
864 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
865   .info = snd_es1688_info_double, \
866   .get = snd_es1688_get_double, .put = snd_es1688_put_double, \
867   .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
868 
869 static int snd_es1688_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
870 {
871         int mask = (kcontrol->private_value >> 24) & 0xff;
872 
873         uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
874         uinfo->count = 2;
875         uinfo->value.integer.min = 0;
876         uinfo->value.integer.max = mask;
877         return 0;
878 }
879 
880 static int snd_es1688_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
881 {
882         struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);
883         unsigned long flags;
884         int left_reg = kcontrol->private_value & 0xff;
885         int right_reg = (kcontrol->private_value >> 8) & 0xff;
886         int shift_left = (kcontrol->private_value >> 16) & 0x07;
887         int shift_right = (kcontrol->private_value >> 19) & 0x07;
888         int mask = (kcontrol->private_value >> 24) & 0xff;
889         int invert = (kcontrol->private_value >> 22) & 1;
890         unsigned char left, right;
891         
892         spin_lock_irqsave(&chip->reg_lock, flags);
893         if (left_reg < 0xa0)
894                 left = snd_es1688_mixer_read(chip, left_reg);
895         else
896                 left = snd_es1688_read(chip, left_reg);
897         if (left_reg != right_reg) {
898                 if (right_reg < 0xa0) 
899                         right = snd_es1688_mixer_read(chip, right_reg);
900                 else
901                         right = snd_es1688_read(chip, right_reg);
902         } else
903                 right = left;
904         spin_unlock_irqrestore(&chip->reg_lock, flags);
905         ucontrol->value.integer.value[0] = (left >> shift_left) & mask;
906         ucontrol->value.integer.value[1] = (right >> shift_right) & mask;
907         if (invert) {
908                 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
909                 ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
910         }
911         return 0;
912 }
913 
914 static int snd_es1688_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
915 {
916         struct snd_es1688 *chip = snd_kcontrol_chip(kcontrol);
917         unsigned long flags;
918         int left_reg = kcontrol->private_value & 0xff;
919         int right_reg = (kcontrol->private_value >> 8) & 0xff;
920         int shift_left = (kcontrol->private_value >> 16) & 0x07;
921         int shift_right = (kcontrol->private_value >> 19) & 0x07;
922         int mask = (kcontrol->private_value >> 24) & 0xff;
923         int invert = (kcontrol->private_value >> 22) & 1;
924         int change;
925         unsigned char val1, val2, oval1, oval2;
926         
927         val1 = ucontrol->value.integer.value[0] & mask;
928         val2 = ucontrol->value.integer.value[1] & mask;
929         if (invert) {
930                 val1 = mask - val1;
931                 val2 = mask - val2;
932         }
933         val1 <<= shift_left;
934         val2 <<= shift_right;
935         spin_lock_irqsave(&chip->reg_lock, flags);
936         if (left_reg != right_reg) {
937                 if (left_reg < 0xa0)
938                         oval1 = snd_es1688_mixer_read(chip, left_reg);
939                 else
940                         oval1 = snd_es1688_read(chip, left_reg);
941                 if (right_reg < 0xa0)
942                         oval2 = snd_es1688_mixer_read(chip, right_reg);
943                 else
944                         oval2 = snd_es1688_read(chip, right_reg);
945                 val1 = (oval1 & ~(mask << shift_left)) | val1;
946                 val2 = (oval2 & ~(mask << shift_right)) | val2;
947                 change = val1 != oval1 || val2 != oval2;
948                 if (change) {
949                         if (left_reg < 0xa0)
950                                 snd_es1688_mixer_write(chip, left_reg, val1);
951                         else
952                                 snd_es1688_write(chip, left_reg, val1);
953                         if (right_reg < 0xa0)
954                                 snd_es1688_mixer_write(chip, right_reg, val1);
955                         else
956                                 snd_es1688_write(chip, right_reg, val1);
957                 }
958         } else {
959                 if (left_reg < 0xa0)
960                         oval1 = snd_es1688_mixer_read(chip, left_reg);
961                 else
962                         oval1 = snd_es1688_read(chip, left_reg);
963                 val1 = (oval1 & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
964                 change = val1 != oval1;
965                 if (change) {
966                         if (left_reg < 0xa0)
967                                 snd_es1688_mixer_write(chip, left_reg, val1);
968                         else
969                                 snd_es1688_write(chip, left_reg, val1);
970                 }
971                         
972         }
973         spin_unlock_irqrestore(&chip->reg_lock, flags);
974         return change;
975 }
976 
977 static struct snd_kcontrol_new snd_es1688_controls[] = {
978 ES1688_DOUBLE("Master Playback Volume", 0, ES1688_MASTER_DEV, ES1688_MASTER_DEV, 4, 0, 15, 0),
979 ES1688_DOUBLE("PCM Playback Volume", 0, ES1688_PCM_DEV, ES1688_PCM_DEV, 4, 0, 15, 0),
980 ES1688_DOUBLE("Line Playback Volume", 0, ES1688_LINE_DEV, ES1688_LINE_DEV, 4, 0, 15, 0),
981 ES1688_DOUBLE("CD Playback Volume", 0, ES1688_CD_DEV, ES1688_CD_DEV, 4, 0, 15, 0),
982 ES1688_DOUBLE("FM Playback Volume", 0, ES1688_FM_DEV, ES1688_FM_DEV, 4, 0, 15, 0),
983 ES1688_DOUBLE("Mic Playback Volume", 0, ES1688_MIC_DEV, ES1688_MIC_DEV, 4, 0, 15, 0),
984 ES1688_DOUBLE("Aux Playback Volume", 0, ES1688_AUX_DEV, ES1688_AUX_DEV, 4, 0, 15, 0),
985 ES1688_SINGLE("PC Speaker Playback Volume", 0, ES1688_SPEAKER_DEV, 0, 7, 0),
986 ES1688_DOUBLE("Capture Volume", 0, ES1688_RECLEV_DEV, ES1688_RECLEV_DEV, 4, 0, 15, 0),
987 ES1688_SINGLE("Capture Switch", 0, ES1688_REC_DEV, 4, 1, 1),
988 {
989         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
990         .name = "Capture Source",
991         .info = snd_es1688_info_mux,
992         .get = snd_es1688_get_mux,
993         .put = snd_es1688_put_mux,
994 },
995 };
996 
997 #define ES1688_INIT_TABLE_SIZE (sizeof(snd_es1688_init_table)/2)
998 
999 static unsigned char snd_es1688_init_table[][2] = {
1000         { ES1688_MASTER_DEV, 0 },
1001         { ES1688_PCM_DEV, 0 },
1002         { ES1688_LINE_DEV, 0 },
1003         { ES1688_CD_DEV, 0 },
1004         { ES1688_FM_DEV, 0 },
1005         { ES1688_MIC_DEV, 0 },
1006         { ES1688_AUX_DEV, 0 },
1007         { ES1688_SPEAKER_DEV, 0 },
1008         { ES1688_RECLEV_DEV, 0 },
1009         { ES1688_REC_DEV, 0x17 }
1010 };
1011                                         
1012 int snd_es1688_mixer(struct snd_es1688 *chip)
1013 {
1014         struct snd_card *card;
1015         unsigned int idx;
1016         int err;
1017         unsigned char reg, val;
1018 
1019         if (snd_BUG_ON(!chip || !chip->card))
1020                 return -EINVAL;
1021 
1022         card = chip->card;
1023 
1024         strcpy(card->mixername, snd_es1688_chip_id(chip));
1025 
1026         for (idx = 0; idx < ARRAY_SIZE(snd_es1688_controls); idx++) {
1027                 if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es1688_controls[idx], chip))) < 0)
1028                         return err;
1029         }
1030         for (idx = 0; idx < ES1688_INIT_TABLE_SIZE; idx++) {
1031                 reg = snd_es1688_init_table[idx][0];
1032                 val = snd_es1688_init_table[idx][1];
1033                 if (reg < 0xa0)
1034                         snd_es1688_mixer_write(chip, reg, val);
1035                 else
1036                         snd_es1688_write(chip, reg, val);
1037         }
1038         return 0;
1039 }
1040 
1041 EXPORT_SYMBOL(snd_es1688_mixer_write);
1042 EXPORT_SYMBOL(snd_es1688_create);
1043 EXPORT_SYMBOL(snd_es1688_pcm);
1044 EXPORT_SYMBOL(snd_es1688_mixer);
1045 
1046 /*
1047  *  INIT part
1048  */
1049 
1050 static int __init alsa_es1688_init(void)
1051 {
1052         return 0;
1053 }
1054 
1055 static void __exit alsa_es1688_exit(void)
1056 {
1057 }
1058 
1059 module_init(alsa_es1688_init)
1060 module_exit(alsa_es1688_exit)
1061 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp