1 /* 2 * linux/sound/oss/soundcard.c 3 * 4 * Sound card driver for Linux 5 * 6 * 7 * Copyright (C) by Hannu Savolainen 1993-1997 8 * 9 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) 10 * Version 2 (June 1991). See the "COPYING" file distributed with this software 11 * for more info. 12 * 13 * 14 * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) 15 * integrated sound_switch.c 16 * Stefan Reinauer : integrated /proc/sound (equals to /dev/sndstat, 17 * which should disappear in the near future) 18 * Eric Dumas : devfs support (22-Jan-98) <dumas@linux.eu.org> with 19 * fixups by C. Scott Ananian <cananian@alumni.princeton.edu> 20 * Richard Gooch : moved common (non OSS-specific) devices to sound_core.c 21 * Rob Riggs : Added persistent DMA buffers support (1998/10/17) 22 * Christoph Hellwig : Some cleanup work (2000/03/01) 23 */ 24 25 26 #include "sound_config.h" 27 #include <linux/init.h> 28 #include <linux/types.h> 29 #include <linux/errno.h> 30 #include <linux/signal.h> 31 #include <linux/fcntl.h> 32 #include <linux/ctype.h> 33 #include <linux/stddef.h> 34 #include <linux/kmod.h> 35 #include <linux/kernel.h> 36 #include <asm/dma.h> 37 #include <asm/io.h> 38 #include <linux/wait.h> 39 #include <linux/ioport.h> 40 #include <linux/major.h> 41 #include <linux/delay.h> 42 #include <linux/proc_fs.h> 43 #include <linux/mutex.h> 44 #include <linux/module.h> 45 #include <linux/mm.h> 46 #include <linux/device.h> 47 48 /* 49 * This ought to be moved into include/asm/dma.h 50 */ 51 #ifndef valid_dma 52 #define valid_dma(n) ((n) >= 0 && (n) < MAX_DMA_CHANNELS && (n) != 4) 53 #endif 54 55 /* 56 * Table for permanently allocated memory (used when unloading the module) 57 */ 58 void * sound_mem_blocks[MAX_MEM_BLOCKS]; 59 static DEFINE_MUTEX(soundcard_mutex); 60 int sound_nblocks = 0; 61 62 /* Persistent DMA buffers */ 63 #ifdef CONFIG_SOUND_DMAP 64 int sound_dmap_flag = 1; 65 #else 66 int sound_dmap_flag = 0; 67 #endif 68 69 static char dma_alloc_map[MAX_DMA_CHANNELS]; 70 71 #define DMA_MAP_UNAVAIL 0 72 #define DMA_MAP_FREE 1 73 #define DMA_MAP_BUSY 2 74 75 76 unsigned long seq_time = 0; /* Time for /dev/sequencer */ 77 extern struct class *sound_class; 78 79 /* 80 * Table for configurable mixer volume handling 81 */ 82 static mixer_vol_table mixer_vols[MAX_MIXER_DEV]; 83 static int num_mixer_volumes; 84 85 int *load_mixer_volumes(char *name, int *levels, int present) 86 { 87 int i, n; 88 89 for (i = 0; i < num_mixer_volumes; i++) { 90 if (strncmp(name, mixer_vols[i].name, 32) == 0) { 91 if (present) 92 mixer_vols[i].num = i; 93 return mixer_vols[i].levels; 94 } 95 } 96 if (num_mixer_volumes >= MAX_MIXER_DEV) { 97 printk(KERN_ERR "Sound: Too many mixers (%s)\n", name); 98 return levels; 99 } 100 n = num_mixer_volumes++; 101 102 strncpy(mixer_vols[n].name, name, 32); 103 104 if (present) 105 mixer_vols[n].num = n; 106 else 107 mixer_vols[n].num = -1; 108 109 for (i = 0; i < 32; i++) 110 mixer_vols[n].levels[i] = levels[i]; 111 return mixer_vols[n].levels; 112 } 113 EXPORT_SYMBOL(load_mixer_volumes); 114 115 static int set_mixer_levels(void __user * arg) 116 { 117 /* mixer_vol_table is 174 bytes, so IMHO no reason to not allocate it on the stack */ 118 mixer_vol_table buf; 119 120 if (__copy_from_user(&buf, arg, sizeof(buf))) 121 return -EFAULT; 122 load_mixer_volumes(buf.name, buf.levels, 0); 123 if (__copy_to_user(arg, &buf, sizeof(buf))) 124 return -EFAULT; 125 return 0; 126 } 127 128 static int get_mixer_levels(void __user * arg) 129 { 130 int n; 131 132 if (__get_user(n, (int __user *)(&(((mixer_vol_table __user *)arg)->num)))) 133 return -EFAULT; 134 if (n < 0 || n >= num_mixer_volumes) 135 return -EINVAL; 136 if (__copy_to_user(arg, &mixer_vols[n], sizeof(mixer_vol_table))) 137 return -EFAULT; 138 return 0; 139 } 140 141 /* 4K page size but our output routines use some slack for overruns */ 142 #define PROC_BLOCK_SIZE (3*1024) 143 144 static ssize_t sound_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) 145 { 146 int dev = iminor(file_inode(file)); 147 int ret = -EINVAL; 148 149 /* 150 * The OSS drivers aren't remotely happy without this locking, 151 * and unless someone fixes them when they are about to bite the 152 * big one anyway, we might as well bandage here.. 153 */ 154 155 mutex_lock(&soundcard_mutex); 156 157 switch (dev & 0x0f) { 158 case SND_DEV_DSP: 159 case SND_DEV_DSP16: 160 case SND_DEV_AUDIO: 161 ret = audio_read(dev, file, buf, count); 162 break; 163 164 case SND_DEV_SEQ: 165 case SND_DEV_SEQ2: 166 ret = sequencer_read(dev, file, buf, count); 167 break; 168 169 case SND_DEV_MIDIN: 170 ret = MIDIbuf_read(dev, file, buf, count); 171 } 172 mutex_unlock(&soundcard_mutex); 173 return ret; 174 } 175 176 static ssize_t sound_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 177 { 178 int dev = iminor(file_inode(file)); 179 int ret = -EINVAL; 180 181 mutex_lock(&soundcard_mutex); 182 switch (dev & 0x0f) { 183 case SND_DEV_SEQ: 184 case SND_DEV_SEQ2: 185 ret = sequencer_write(dev, file, buf, count); 186 break; 187 188 case SND_DEV_DSP: 189 case SND_DEV_DSP16: 190 case SND_DEV_AUDIO: 191 ret = audio_write(dev, file, buf, count); 192 break; 193 194 case SND_DEV_MIDIN: 195 ret = MIDIbuf_write(dev, file, buf, count); 196 break; 197 } 198 mutex_unlock(&soundcard_mutex); 199 return ret; 200 } 201 202 static int sound_open(struct inode *inode, struct file *file) 203 { 204 int dev = iminor(inode); 205 int retval; 206 207 if ((dev >= SND_NDEVS) || (dev < 0)) { 208 printk(KERN_ERR "Invalid minor device %d\n", dev); 209 return -ENXIO; 210 } 211 mutex_lock(&soundcard_mutex); 212 switch (dev & 0x0f) { 213 case SND_DEV_CTL: 214 dev >>= 4; 215 if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) { 216 request_module("mixer%d", dev); 217 } 218 retval = -ENXIO; 219 if (dev && (dev >= num_mixers || mixer_devs[dev] == NULL)) 220 break; 221 222 if (!try_module_get(mixer_devs[dev]->owner)) 223 break; 224 225 retval = 0; 226 break; 227 228 case SND_DEV_SEQ: 229 case SND_DEV_SEQ2: 230 retval = sequencer_open(dev, file); 231 break; 232 233 case SND_DEV_MIDIN: 234 retval = MIDIbuf_open(dev, file); 235 break; 236 237 case SND_DEV_DSP: 238 case SND_DEV_DSP16: 239 case SND_DEV_AUDIO: 240 retval = audio_open(dev, file); 241 break; 242 243 default: 244 printk(KERN_ERR "Invalid minor device %d\n", dev); 245 retval = -ENXIO; 246 } 247 248 mutex_unlock(&soundcard_mutex); 249 return retval; 250 } 251 252 static int sound_release(struct inode *inode, struct file *file) 253 { 254 int dev = iminor(inode); 255 256 mutex_lock(&soundcard_mutex); 257 switch (dev & 0x0f) { 258 case SND_DEV_CTL: 259 module_put(mixer_devs[dev >> 4]->owner); 260 break; 261 262 case SND_DEV_SEQ: 263 case SND_DEV_SEQ2: 264 sequencer_release(dev, file); 265 break; 266 267 case SND_DEV_MIDIN: 268 MIDIbuf_release(dev, file); 269 break; 270 271 case SND_DEV_DSP: 272 case SND_DEV_DSP16: 273 case SND_DEV_AUDIO: 274 audio_release(dev, file); 275 break; 276 277 default: 278 printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); 279 } 280 mutex_unlock(&soundcard_mutex); 281 282 return 0; 283 } 284 285 static int get_mixer_info(int dev, void __user *arg) 286 { 287 mixer_info info; 288 memset(&info, 0, sizeof(info)); 289 strlcpy(info.id, mixer_devs[dev]->id, sizeof(info.id)); 290 strlcpy(info.name, mixer_devs[dev]->name, sizeof(info.name)); 291 info.modify_counter = mixer_devs[dev]->modify_counter; 292 if (__copy_to_user(arg, &info, sizeof(info))) 293 return -EFAULT; 294 return 0; 295 } 296 297 static int get_old_mixer_info(int dev, void __user *arg) 298 { 299 _old_mixer_info info; 300 memset(&info, 0, sizeof(info)); 301 strlcpy(info.id, mixer_devs[dev]->id, sizeof(info.id)); 302 strlcpy(info.name, mixer_devs[dev]->name, sizeof(info.name)); 303 if (copy_to_user(arg, &info, sizeof(info))) 304 return -EFAULT; 305 return 0; 306 } 307 308 static int sound_mixer_ioctl(int mixdev, unsigned int cmd, void __user *arg) 309 { 310 if (mixdev < 0 || mixdev >= MAX_MIXER_DEV) 311 return -ENXIO; 312 /* Try to load the mixer... */ 313 if (mixer_devs[mixdev] == NULL) { 314 request_module("mixer%d", mixdev); 315 } 316 if (mixdev >= num_mixers || !mixer_devs[mixdev]) 317 return -ENXIO; 318 if (cmd == SOUND_MIXER_INFO) 319 return get_mixer_info(mixdev, arg); 320 if (cmd == SOUND_OLD_MIXER_INFO) 321 return get_old_mixer_info(mixdev, arg); 322 if (_SIOC_DIR(cmd) & _SIOC_WRITE) 323 mixer_devs[mixdev]->modify_counter++; 324 if (!mixer_devs[mixdev]->ioctl) 325 return -EINVAL; 326 return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg); 327 } 328 329 static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 330 { 331 int len = 0, dtype; 332 int dev = iminor(file_inode(file)); 333 long ret = -EINVAL; 334 void __user *p = (void __user *)arg; 335 336 if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) { 337 /* 338 * Have to validate the address given by the process. 339 */ 340 len = _SIOC_SIZE(cmd); 341 if (len < 1 || len > 65536 || !p) 342 return -EFAULT; 343 if (_SIOC_DIR(cmd) & _SIOC_WRITE) 344 if (!access_ok(VERIFY_READ, p, len)) 345 return -EFAULT; 346 if (_SIOC_DIR(cmd) & _SIOC_READ) 347 if (!access_ok(VERIFY_WRITE, p, len)) 348 return -EFAULT; 349 } 350 if (cmd == OSS_GETVERSION) 351 return __put_user(SOUND_VERSION, (int __user *)p); 352 353 mutex_lock(&soundcard_mutex); 354 if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ 355 (dev & 0x0f) != SND_DEV_CTL) { 356 dtype = dev & 0x0f; 357 switch (dtype) { 358 case SND_DEV_DSP: 359 case SND_DEV_DSP16: 360 case SND_DEV_AUDIO: 361 ret = sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev, 362 cmd, p); 363 break; 364 default: 365 ret = sound_mixer_ioctl(dev >> 4, cmd, p); 366 break; 367 } 368 mutex_unlock(&soundcard_mutex); 369 return ret; 370 } 371 372 switch (dev & 0x0f) { 373 case SND_DEV_CTL: 374 if (cmd == SOUND_MIXER_GETLEVELS) 375 ret = get_mixer_levels(p); 376 else if (cmd == SOUND_MIXER_SETLEVELS) 377 ret = set_mixer_levels(p); 378 else 379 ret = sound_mixer_ioctl(dev >> 4, cmd, p); 380 break; 381 382 case SND_DEV_SEQ: 383 case SND_DEV_SEQ2: 384 ret = sequencer_ioctl(dev, file, cmd, p); 385 break; 386 387 case SND_DEV_DSP: 388 case SND_DEV_DSP16: 389 case SND_DEV_AUDIO: 390 ret = audio_ioctl(dev, file, cmd, p); 391 break; 392 393 case SND_DEV_MIDIN: 394 ret = MIDIbuf_ioctl(dev, file, cmd, p); 395 break; 396 397 } 398 mutex_unlock(&soundcard_mutex); 399 return ret; 400 } 401 402 static unsigned int sound_poll(struct file *file, poll_table * wait) 403 { 404 struct inode *inode = file_inode(file); 405 int dev = iminor(inode); 406 407 switch (dev & 0x0f) { 408 case SND_DEV_SEQ: 409 case SND_DEV_SEQ2: 410 return sequencer_poll(dev, file, wait); 411 412 case SND_DEV_MIDIN: 413 return MIDIbuf_poll(dev, file, wait); 414 415 case SND_DEV_DSP: 416 case SND_DEV_DSP16: 417 case SND_DEV_AUDIO: 418 return DMAbuf_poll(file, dev >> 4, wait); 419 } 420 return 0; 421 } 422 423 static int sound_mmap(struct file *file, struct vm_area_struct *vma) 424 { 425 int dev_class; 426 unsigned long size; 427 struct dma_buffparms *dmap = NULL; 428 int dev = iminor(file_inode(file)); 429 430 dev_class = dev & 0x0f; 431 dev >>= 4; 432 433 if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO) { 434 printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n"); 435 return -EINVAL; 436 } 437 mutex_lock(&soundcard_mutex); 438 if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ 439 dmap = audio_devs[dev]->dmap_out; 440 else if (vma->vm_flags & VM_READ) 441 dmap = audio_devs[dev]->dmap_in; 442 else { 443 printk(KERN_ERR "Sound: Undefined mmap() access\n"); 444 mutex_unlock(&soundcard_mutex); 445 return -EINVAL; 446 } 447 448 if (dmap == NULL) { 449 printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n"); 450 mutex_unlock(&soundcard_mutex); 451 return -EIO; 452 } 453 if (dmap->raw_buf == NULL) { 454 printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n"); 455 mutex_unlock(&soundcard_mutex); 456 return -EIO; 457 } 458 if (dmap->mapping_flags) { 459 printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n"); 460 mutex_unlock(&soundcard_mutex); 461 return -EIO; 462 } 463 if (vma->vm_pgoff != 0) { 464 printk(KERN_ERR "Sound: mmap() offset must be 0.\n"); 465 mutex_unlock(&soundcard_mutex); 466 return -EINVAL; 467 } 468 size = vma->vm_end - vma->vm_start; 469 470 if (size != dmap->bytes_in_use) { 471 printk(KERN_WARNING "Sound: mmap() size = %ld. Should be %d\n", size, dmap->bytes_in_use); 472 } 473 if (remap_pfn_range(vma, vma->vm_start, 474 virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT, 475 vma->vm_end - vma->vm_start, vma->vm_page_prot)) { 476 mutex_unlock(&soundcard_mutex); 477 return -EAGAIN; 478 } 479 480 dmap->mapping_flags |= DMA_MAP_MAPPED; 481 482 if( audio_devs[dev]->d->mmap) 483 audio_devs[dev]->d->mmap(dev); 484 485 memset(dmap->raw_buf, 486 dmap->neutral_byte, 487 dmap->bytes_in_use); 488 mutex_unlock(&soundcard_mutex); 489 return 0; 490 } 491 492 const struct file_operations oss_sound_fops = { 493 .owner = THIS_MODULE, 494 .llseek = no_llseek, 495 .read = sound_read, 496 .write = sound_write, 497 .poll = sound_poll, 498 .unlocked_ioctl = sound_ioctl, 499 .mmap = sound_mmap, 500 .open = sound_open, 501 .release = sound_release, 502 }; 503 504 /* 505 * Create the required special subdevices 506 */ 507 508 static int create_special_devices(void) 509 { 510 int seq1,seq2; 511 seq1=register_sound_special(&oss_sound_fops, 1); 512 if(seq1==-1) 513 goto bad; 514 seq2=register_sound_special(&oss_sound_fops, 8); 515 if(seq2!=-1) 516 return 0; 517 unregister_sound_special(1); 518 bad: 519 return -1; 520 } 521 522 523 static int dmabuf; 524 static int dmabug; 525 526 module_param(dmabuf, int, 0444); 527 module_param(dmabug, int, 0444); 528 529 /* additional minors for compatibility */ 530 struct oss_minor_dev { 531 unsigned short minor; 532 unsigned int enabled; 533 } dev_list[] = { 534 { SND_DEV_DSP16 }, 535 { SND_DEV_AUDIO }, 536 }; 537 538 static int __init oss_init(void) 539 { 540 int err; 541 int i, j; 542 543 #ifdef CONFIG_PCI 544 if(dmabug) 545 isa_dma_bridge_buggy = dmabug; 546 #endif 547 548 err = create_special_devices(); 549 if (err) { 550 printk(KERN_ERR "sound: driver already loaded/included in kernel\n"); 551 return err; 552 } 553 554 /* Protecting the innocent */ 555 sound_dmap_flag = (dmabuf > 0 ? 1 : 0); 556 557 for (i = 0; i < ARRAY_SIZE(dev_list); i++) { 558 j = 0; 559 do { 560 unsigned short minor = dev_list[i].minor + j * 0x10; 561 if (!register_sound_special(&oss_sound_fops, minor)) 562 dev_list[i].enabled = (1 << j); 563 } while (++j < num_audiodevs); 564 } 565 566 if (sound_nblocks >= MAX_MEM_BLOCKS - 1) 567 printk(KERN_ERR "Sound warning: Deallocation table was too small.\n"); 568 569 return 0; 570 } 571 572 static void __exit oss_cleanup(void) 573 { 574 int i, j; 575 576 for (i = 0; i < ARRAY_SIZE(dev_list); i++) { 577 j = 0; 578 do { 579 if (dev_list[i].enabled & (1 << j)) 580 unregister_sound_special(dev_list[i].minor); 581 } while (++j < num_audiodevs); 582 } 583 584 unregister_sound_special(1); 585 unregister_sound_special(8); 586 587 sound_stop_timer(); 588 589 sequencer_unload(); 590 591 for (i = 0; i < MAX_DMA_CHANNELS; i++) 592 if (dma_alloc_map[i] != DMA_MAP_UNAVAIL) { 593 printk(KERN_ERR "Sound: Hmm, DMA%d was left allocated - fixed\n", i); 594 sound_free_dma(i); 595 } 596 597 for (i = 0; i < sound_nblocks; i++) 598 vfree(sound_mem_blocks[i]); 599 600 } 601 602 module_init(oss_init); 603 module_exit(oss_cleanup); 604 MODULE_LICENSE("GPL"); 605 MODULE_DESCRIPTION("OSS Sound subsystem"); 606 MODULE_AUTHOR("Hannu Savolainen, et al."); 607 608 609 int sound_alloc_dma(int chn, char *deviceID) 610 { 611 int err; 612 613 if ((err = request_dma(chn, deviceID)) != 0) 614 return err; 615 616 dma_alloc_map[chn] = DMA_MAP_FREE; 617 618 return 0; 619 } 620 EXPORT_SYMBOL(sound_alloc_dma); 621 622 int sound_open_dma(int chn, char *deviceID) 623 { 624 if (!valid_dma(chn)) { 625 printk(KERN_ERR "sound_open_dma: Invalid DMA channel %d\n", chn); 626 return 1; 627 } 628 629 if (dma_alloc_map[chn] != DMA_MAP_FREE) { 630 printk("sound_open_dma: DMA channel %d busy or not allocated (%d)\n", chn, dma_alloc_map[chn]); 631 return 1; 632 } 633 dma_alloc_map[chn] = DMA_MAP_BUSY; 634 return 0; 635 } 636 EXPORT_SYMBOL(sound_open_dma); 637 638 void sound_free_dma(int chn) 639 { 640 if (dma_alloc_map[chn] == DMA_MAP_UNAVAIL) { 641 /* printk( "sound_free_dma: Bad access to DMA channel %d\n", chn); */ 642 return; 643 } 644 free_dma(chn); 645 dma_alloc_map[chn] = DMA_MAP_UNAVAIL; 646 } 647 EXPORT_SYMBOL(sound_free_dma); 648 649 void sound_close_dma(int chn) 650 { 651 if (dma_alloc_map[chn] != DMA_MAP_BUSY) { 652 printk(KERN_ERR "sound_close_dma: Bad access to DMA channel %d\n", chn); 653 return; 654 } 655 dma_alloc_map[chn] = DMA_MAP_FREE; 656 } 657 EXPORT_SYMBOL(sound_close_dma); 658 659 static void do_sequencer_timer(unsigned long dummy) 660 { 661 sequencer_timer(0); 662 } 663 664 665 static DEFINE_TIMER(seq_timer, do_sequencer_timer, 0, 0); 666 667 void request_sound_timer(int count) 668 { 669 extern unsigned long seq_time; 670 671 if (count < 0) { 672 seq_timer.expires = (-count) + jiffies; 673 add_timer(&seq_timer); 674 return; 675 } 676 count += seq_time; 677 678 count -= jiffies; 679 680 if (count < 1) 681 count = 1; 682 683 seq_timer.expires = (count) + jiffies; 684 add_timer(&seq_timer); 685 } 686 687 void sound_stop_timer(void) 688 { 689 del_timer(&seq_timer); 690 } 691 692 void conf_printf(char *name, struct address_info *hw_config) 693 { 694 #ifndef CONFIG_SOUND_TRACEINIT 695 return; 696 #else 697 printk("<%s> at 0x%03x", name, hw_config->io_base); 698 699 if (hw_config->irq) 700 printk(" irq %d", (hw_config->irq > 0) ? hw_config->irq : -hw_config->irq); 701 702 if (hw_config->dma != -1 || hw_config->dma2 != -1) 703 { 704 printk(" dma %d", hw_config->dma); 705 if (hw_config->dma2 != -1) 706 printk(",%d", hw_config->dma2); 707 } 708 printk("\n"); 709 #endif 710 } 711 EXPORT_SYMBOL(conf_printf); 712 713 void conf_printf2(char *name, int base, int irq, int dma, int dma2) 714 { 715 #ifndef CONFIG_SOUND_TRACEINIT 716 return; 717 #else 718 printk("<%s> at 0x%03x", name, base); 719 720 if (irq) 721 printk(" irq %d", (irq > 0) ? irq : -irq); 722 723 if (dma != -1 || dma2 != -1) 724 { 725 printk(" dma %d", dma); 726 if (dma2 != -1) 727 printk(",%d", dma2); 728 } 729 printk("\n"); 730 #endif 731 } 732 EXPORT_SYMBOL(conf_printf2); 733 734
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.