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 DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count)); 158 switch (dev & 0x0f) { 159 case SND_DEV_DSP: 160 case SND_DEV_DSP16: 161 case SND_DEV_AUDIO: 162 ret = audio_read(dev, file, buf, count); 163 break; 164 165 case SND_DEV_SEQ: 166 case SND_DEV_SEQ2: 167 ret = sequencer_read(dev, file, buf, count); 168 break; 169 170 case SND_DEV_MIDIN: 171 ret = MIDIbuf_read(dev, file, buf, count); 172 } 173 mutex_unlock(&soundcard_mutex); 174 return ret; 175 } 176 177 static ssize_t sound_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 178 { 179 int dev = iminor(file_inode(file)); 180 int ret = -EINVAL; 181 182 mutex_lock(&soundcard_mutex); 183 DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count)); 184 switch (dev & 0x0f) { 185 case SND_DEV_SEQ: 186 case SND_DEV_SEQ2: 187 ret = sequencer_write(dev, file, buf, count); 188 break; 189 190 case SND_DEV_DSP: 191 case SND_DEV_DSP16: 192 case SND_DEV_AUDIO: 193 ret = audio_write(dev, file, buf, count); 194 break; 195 196 case SND_DEV_MIDIN: 197 ret = MIDIbuf_write(dev, file, buf, count); 198 break; 199 } 200 mutex_unlock(&soundcard_mutex); 201 return ret; 202 } 203 204 static int sound_open(struct inode *inode, struct file *file) 205 { 206 int dev = iminor(inode); 207 int retval; 208 209 DEB(printk("sound_open(dev=%d)\n", dev)); 210 if ((dev >= SND_NDEVS) || (dev < 0)) { 211 printk(KERN_ERR "Invalid minor device %d\n", dev); 212 return -ENXIO; 213 } 214 mutex_lock(&soundcard_mutex); 215 switch (dev & 0x0f) { 216 case SND_DEV_CTL: 217 dev >>= 4; 218 if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) { 219 request_module("mixer%d", dev); 220 } 221 retval = -ENXIO; 222 if (dev && (dev >= num_mixers || mixer_devs[dev] == NULL)) 223 break; 224 225 if (!try_module_get(mixer_devs[dev]->owner)) 226 break; 227 228 retval = 0; 229 break; 230 231 case SND_DEV_SEQ: 232 case SND_DEV_SEQ2: 233 retval = sequencer_open(dev, file); 234 break; 235 236 case SND_DEV_MIDIN: 237 retval = MIDIbuf_open(dev, file); 238 break; 239 240 case SND_DEV_DSP: 241 case SND_DEV_DSP16: 242 case SND_DEV_AUDIO: 243 retval = audio_open(dev, file); 244 break; 245 246 default: 247 printk(KERN_ERR "Invalid minor device %d\n", dev); 248 retval = -ENXIO; 249 } 250 251 mutex_unlock(&soundcard_mutex); 252 return retval; 253 } 254 255 static int sound_release(struct inode *inode, struct file *file) 256 { 257 int dev = iminor(inode); 258 259 mutex_lock(&soundcard_mutex); 260 DEB(printk("sound_release(dev=%d)\n", dev)); 261 switch (dev & 0x0f) { 262 case SND_DEV_CTL: 263 module_put(mixer_devs[dev >> 4]->owner); 264 break; 265 266 case SND_DEV_SEQ: 267 case SND_DEV_SEQ2: 268 sequencer_release(dev, file); 269 break; 270 271 case SND_DEV_MIDIN: 272 MIDIbuf_release(dev, file); 273 break; 274 275 case SND_DEV_DSP: 276 case SND_DEV_DSP16: 277 case SND_DEV_AUDIO: 278 audio_release(dev, file); 279 break; 280 281 default: 282 printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); 283 } 284 mutex_unlock(&soundcard_mutex); 285 286 return 0; 287 } 288 289 static int get_mixer_info(int dev, void __user *arg) 290 { 291 mixer_info info; 292 memset(&info, 0, sizeof(info)); 293 strlcpy(info.id, mixer_devs[dev]->id, sizeof(info.id)); 294 strlcpy(info.name, mixer_devs[dev]->name, sizeof(info.name)); 295 info.modify_counter = mixer_devs[dev]->modify_counter; 296 if (__copy_to_user(arg, &info, sizeof(info))) 297 return -EFAULT; 298 return 0; 299 } 300 301 static int get_old_mixer_info(int dev, void __user *arg) 302 { 303 _old_mixer_info info; 304 memset(&info, 0, sizeof(info)); 305 strlcpy(info.id, mixer_devs[dev]->id, sizeof(info.id)); 306 strlcpy(info.name, mixer_devs[dev]->name, sizeof(info.name)); 307 if (copy_to_user(arg, &info, sizeof(info))) 308 return -EFAULT; 309 return 0; 310 } 311 312 static int sound_mixer_ioctl(int mixdev, unsigned int cmd, void __user *arg) 313 { 314 if (mixdev < 0 || mixdev >= MAX_MIXER_DEV) 315 return -ENXIO; 316 /* Try to load the mixer... */ 317 if (mixer_devs[mixdev] == NULL) { 318 request_module("mixer%d", mixdev); 319 } 320 if (mixdev >= num_mixers || !mixer_devs[mixdev]) 321 return -ENXIO; 322 if (cmd == SOUND_MIXER_INFO) 323 return get_mixer_info(mixdev, arg); 324 if (cmd == SOUND_OLD_MIXER_INFO) 325 return get_old_mixer_info(mixdev, arg); 326 if (_SIOC_DIR(cmd) & _SIOC_WRITE) 327 mixer_devs[mixdev]->modify_counter++; 328 if (!mixer_devs[mixdev]->ioctl) 329 return -EINVAL; 330 return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg); 331 } 332 333 static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 334 { 335 int len = 0, dtype; 336 int dev = iminor(file_inode(file)); 337 long ret = -EINVAL; 338 void __user *p = (void __user *)arg; 339 340 if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) { 341 /* 342 * Have to validate the address given by the process. 343 */ 344 len = _SIOC_SIZE(cmd); 345 if (len < 1 || len > 65536 || !p) 346 return -EFAULT; 347 if (_SIOC_DIR(cmd) & _SIOC_WRITE) 348 if (!access_ok(VERIFY_READ, p, len)) 349 return -EFAULT; 350 if (_SIOC_DIR(cmd) & _SIOC_READ) 351 if (!access_ok(VERIFY_WRITE, p, len)) 352 return -EFAULT; 353 } 354 DEB(printk("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg)); 355 if (cmd == OSS_GETVERSION) 356 return __put_user(SOUND_VERSION, (int __user *)p); 357 358 mutex_lock(&soundcard_mutex); 359 if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ 360 (dev & 0x0f) != SND_DEV_CTL) { 361 dtype = dev & 0x0f; 362 switch (dtype) { 363 case SND_DEV_DSP: 364 case SND_DEV_DSP16: 365 case SND_DEV_AUDIO: 366 ret = sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev, 367 cmd, p); 368 break; 369 default: 370 ret = sound_mixer_ioctl(dev >> 4, cmd, p); 371 break; 372 } 373 mutex_unlock(&soundcard_mutex); 374 return ret; 375 } 376 377 switch (dev & 0x0f) { 378 case SND_DEV_CTL: 379 if (cmd == SOUND_MIXER_GETLEVELS) 380 ret = get_mixer_levels(p); 381 else if (cmd == SOUND_MIXER_SETLEVELS) 382 ret = set_mixer_levels(p); 383 else 384 ret = sound_mixer_ioctl(dev >> 4, cmd, p); 385 break; 386 387 case SND_DEV_SEQ: 388 case SND_DEV_SEQ2: 389 ret = sequencer_ioctl(dev, file, cmd, p); 390 break; 391 392 case SND_DEV_DSP: 393 case SND_DEV_DSP16: 394 case SND_DEV_AUDIO: 395 ret = audio_ioctl(dev, file, cmd, p); 396 break; 397 398 case SND_DEV_MIDIN: 399 ret = MIDIbuf_ioctl(dev, file, cmd, p); 400 break; 401 402 } 403 mutex_unlock(&soundcard_mutex); 404 return ret; 405 } 406 407 static unsigned int sound_poll(struct file *file, poll_table * wait) 408 { 409 struct inode *inode = file_inode(file); 410 int dev = iminor(inode); 411 412 DEB(printk("sound_poll(dev=%d)\n", dev)); 413 switch (dev & 0x0f) { 414 case SND_DEV_SEQ: 415 case SND_DEV_SEQ2: 416 return sequencer_poll(dev, file, wait); 417 418 case SND_DEV_MIDIN: 419 return MIDIbuf_poll(dev, file, wait); 420 421 case SND_DEV_DSP: 422 case SND_DEV_DSP16: 423 case SND_DEV_AUDIO: 424 return DMAbuf_poll(file, dev >> 4, wait); 425 } 426 return 0; 427 } 428 429 static int sound_mmap(struct file *file, struct vm_area_struct *vma) 430 { 431 int dev_class; 432 unsigned long size; 433 struct dma_buffparms *dmap = NULL; 434 int dev = iminor(file_inode(file)); 435 436 dev_class = dev & 0x0f; 437 dev >>= 4; 438 439 if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO) { 440 printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n"); 441 return -EINVAL; 442 } 443 mutex_lock(&soundcard_mutex); 444 if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ 445 dmap = audio_devs[dev]->dmap_out; 446 else if (vma->vm_flags & VM_READ) 447 dmap = audio_devs[dev]->dmap_in; 448 else { 449 printk(KERN_ERR "Sound: Undefined mmap() access\n"); 450 mutex_unlock(&soundcard_mutex); 451 return -EINVAL; 452 } 453 454 if (dmap == NULL) { 455 printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n"); 456 mutex_unlock(&soundcard_mutex); 457 return -EIO; 458 } 459 if (dmap->raw_buf == NULL) { 460 printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n"); 461 mutex_unlock(&soundcard_mutex); 462 return -EIO; 463 } 464 if (dmap->mapping_flags) { 465 printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n"); 466 mutex_unlock(&soundcard_mutex); 467 return -EIO; 468 } 469 if (vma->vm_pgoff != 0) { 470 printk(KERN_ERR "Sound: mmap() offset must be 0.\n"); 471 mutex_unlock(&soundcard_mutex); 472 return -EINVAL; 473 } 474 size = vma->vm_end - vma->vm_start; 475 476 if (size != dmap->bytes_in_use) { 477 printk(KERN_WARNING "Sound: mmap() size = %ld. Should be %d\n", size, dmap->bytes_in_use); 478 } 479 if (remap_pfn_range(vma, vma->vm_start, 480 virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT, 481 vma->vm_end - vma->vm_start, vma->vm_page_prot)) { 482 mutex_unlock(&soundcard_mutex); 483 return -EAGAIN; 484 } 485 486 dmap->mapping_flags |= DMA_MAP_MAPPED; 487 488 if( audio_devs[dev]->d->mmap) 489 audio_devs[dev]->d->mmap(dev); 490 491 memset(dmap->raw_buf, 492 dmap->neutral_byte, 493 dmap->bytes_in_use); 494 mutex_unlock(&soundcard_mutex); 495 return 0; 496 } 497 498 const struct file_operations oss_sound_fops = { 499 .owner = THIS_MODULE, 500 .llseek = no_llseek, 501 .read = sound_read, 502 .write = sound_write, 503 .poll = sound_poll, 504 .unlocked_ioctl = sound_ioctl, 505 .mmap = sound_mmap, 506 .open = sound_open, 507 .release = sound_release, 508 }; 509 510 /* 511 * Create the required special subdevices 512 */ 513 514 static int create_special_devices(void) 515 { 516 int seq1,seq2; 517 seq1=register_sound_special(&oss_sound_fops, 1); 518 if(seq1==-1) 519 goto bad; 520 seq2=register_sound_special(&oss_sound_fops, 8); 521 if(seq2!=-1) 522 return 0; 523 unregister_sound_special(1); 524 bad: 525 return -1; 526 } 527 528 529 static int dmabuf; 530 static int dmabug; 531 532 module_param(dmabuf, int, 0444); 533 module_param(dmabug, int, 0444); 534 535 /* additional minors for compatibility */ 536 struct oss_minor_dev { 537 unsigned short minor; 538 unsigned int enabled; 539 } dev_list[] = { 540 { SND_DEV_DSP16 }, 541 { SND_DEV_AUDIO }, 542 }; 543 544 static int __init oss_init(void) 545 { 546 int err; 547 int i, j; 548 549 #ifdef CONFIG_PCI 550 if(dmabug) 551 isa_dma_bridge_buggy = dmabug; 552 #endif 553 554 err = create_special_devices(); 555 if (err) { 556 printk(KERN_ERR "sound: driver already loaded/included in kernel\n"); 557 return err; 558 } 559 560 /* Protecting the innocent */ 561 sound_dmap_flag = (dmabuf > 0 ? 1 : 0); 562 563 for (i = 0; i < ARRAY_SIZE(dev_list); i++) { 564 j = 0; 565 do { 566 unsigned short minor = dev_list[i].minor + j * 0x10; 567 if (!register_sound_special(&oss_sound_fops, minor)) 568 dev_list[i].enabled = (1 << j); 569 } while (++j < num_audiodevs); 570 } 571 572 if (sound_nblocks >= MAX_MEM_BLOCKS - 1) 573 printk(KERN_ERR "Sound warning: Deallocation table was too small.\n"); 574 575 return 0; 576 } 577 578 static void __exit oss_cleanup(void) 579 { 580 int i, j; 581 582 for (i = 0; i < ARRAY_SIZE(dev_list); i++) { 583 j = 0; 584 do { 585 if (dev_list[i].enabled & (1 << j)) 586 unregister_sound_special(dev_list[i].minor); 587 } while (++j < num_audiodevs); 588 } 589 590 unregister_sound_special(1); 591 unregister_sound_special(8); 592 593 sound_stop_timer(); 594 595 sequencer_unload(); 596 597 for (i = 0; i < MAX_DMA_CHANNELS; i++) 598 if (dma_alloc_map[i] != DMA_MAP_UNAVAIL) { 599 printk(KERN_ERR "Sound: Hmm, DMA%d was left allocated - fixed\n", i); 600 sound_free_dma(i); 601 } 602 603 for (i = 0; i < sound_nblocks; i++) 604 vfree(sound_mem_blocks[i]); 605 606 } 607 608 module_init(oss_init); 609 module_exit(oss_cleanup); 610 MODULE_LICENSE("GPL"); 611 MODULE_DESCRIPTION("OSS Sound subsystem"); 612 MODULE_AUTHOR("Hannu Savolainen, et al."); 613 614 615 int sound_alloc_dma(int chn, char *deviceID) 616 { 617 int err; 618 619 if ((err = request_dma(chn, deviceID)) != 0) 620 return err; 621 622 dma_alloc_map[chn] = DMA_MAP_FREE; 623 624 return 0; 625 } 626 EXPORT_SYMBOL(sound_alloc_dma); 627 628 int sound_open_dma(int chn, char *deviceID) 629 { 630 if (!valid_dma(chn)) { 631 printk(KERN_ERR "sound_open_dma: Invalid DMA channel %d\n", chn); 632 return 1; 633 } 634 635 if (dma_alloc_map[chn] != DMA_MAP_FREE) { 636 printk("sound_open_dma: DMA channel %d busy or not allocated (%d)\n", chn, dma_alloc_map[chn]); 637 return 1; 638 } 639 dma_alloc_map[chn] = DMA_MAP_BUSY; 640 return 0; 641 } 642 EXPORT_SYMBOL(sound_open_dma); 643 644 void sound_free_dma(int chn) 645 { 646 if (dma_alloc_map[chn] == DMA_MAP_UNAVAIL) { 647 /* printk( "sound_free_dma: Bad access to DMA channel %d\n", chn); */ 648 return; 649 } 650 free_dma(chn); 651 dma_alloc_map[chn] = DMA_MAP_UNAVAIL; 652 } 653 EXPORT_SYMBOL(sound_free_dma); 654 655 void sound_close_dma(int chn) 656 { 657 if (dma_alloc_map[chn] != DMA_MAP_BUSY) { 658 printk(KERN_ERR "sound_close_dma: Bad access to DMA channel %d\n", chn); 659 return; 660 } 661 dma_alloc_map[chn] = DMA_MAP_FREE; 662 } 663 EXPORT_SYMBOL(sound_close_dma); 664 665 static void do_sequencer_timer(unsigned long dummy) 666 { 667 sequencer_timer(0); 668 } 669 670 671 static DEFINE_TIMER(seq_timer, do_sequencer_timer, 0, 0); 672 673 void request_sound_timer(int count) 674 { 675 extern unsigned long seq_time; 676 677 if (count < 0) { 678 seq_timer.expires = (-count) + jiffies; 679 add_timer(&seq_timer); 680 return; 681 } 682 count += seq_time; 683 684 count -= jiffies; 685 686 if (count < 1) 687 count = 1; 688 689 seq_timer.expires = (count) + jiffies; 690 add_timer(&seq_timer); 691 } 692 693 void sound_stop_timer(void) 694 { 695 del_timer(&seq_timer); 696 } 697 698 void conf_printf(char *name, struct address_info *hw_config) 699 { 700 #ifndef CONFIG_SOUND_TRACEINIT 701 return; 702 #else 703 printk("<%s> at 0x%03x", name, hw_config->io_base); 704 705 if (hw_config->irq) 706 printk(" irq %d", (hw_config->irq > 0) ? hw_config->irq : -hw_config->irq); 707 708 if (hw_config->dma != -1 || hw_config->dma2 != -1) 709 { 710 printk(" dma %d", hw_config->dma); 711 if (hw_config->dma2 != -1) 712 printk(",%d", hw_config->dma2); 713 } 714 printk("\n"); 715 #endif 716 } 717 EXPORT_SYMBOL(conf_printf); 718 719 void conf_printf2(char *name, int base, int irq, int dma, int dma2) 720 { 721 #ifndef CONFIG_SOUND_TRACEINIT 722 return; 723 #else 724 printk("<%s> at 0x%03x", name, base); 725 726 if (irq) 727 printk(" irq %d", (irq > 0) ? irq : -irq); 728 729 if (dma != -1 || dma2 != -1) 730 { 731 printk(" dma %d", dma); 732 if (dma2 != -1) 733 printk(",%d", dma2); 734 } 735 printk("\n"); 736 #endif 737 } 738 EXPORT_SYMBOL(conf_printf2); 739 740
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.