📄 ad1816.c
字号:
return -(EINVAL);}/* ------------------------------------------------------------------- *//* Mixer structure */static struct mixer_operations ad1816_mixer_operations = { owner: THIS_MODULE, id: "AD1816", name: "AD1816 Mixer", ioctl: ad1816_mixer_ioctl};/* ------------------------------------------------------------------- *//* stuff for card recognition, init and unloading *//* replace with probe routine */static int __init probe_ad1816 ( struct address_info *hw_config ){ ad1816_info *devc = &dev_info[nr_ad1816_devs]; int io_base=hw_config->io_base; int *osp=hw_config->osp; int tmp; printk("ad1816: AD1816 sounddriver Copyright (C) 1998 by Thorsten Knabe\n"); printk("ad1816: io=0x%x, irq=%d, dma=%d, dma2=%d, clockfreq=%d, options=%d isadmabug=%d\n", hw_config->io_base, hw_config->irq, hw_config->dma, hw_config->dma2, ad1816_clockfreq, options, isa_dma_bridge_buggy); if (check_region (io_base, 16)) { printk ("ad1816: I/O port 0x%03x not free\n", io_base); return 0; } DEBUGLOG(printk ("ad1816: detect(%x)\n", io_base)); if (nr_ad1816_devs >= MAX_AUDIO_DEV) { printk ("ad1816: detect error - step 0\n"); return 0; } devc->base = io_base; devc->irq_ok = 0; devc->irq = 0; devc->opened = 0; devc->osp = osp; /* base+0: bit 1 must be set but not 255 */ tmp=inb(devc->base); if ( (tmp&0x80)==0 || tmp==255 ) { DEBUGLOG (printk ("ad1816: Chip is not an AD1816 or chip is not active (Test 0)\n")); return(0); } /* writes to ireg 8 are copied to ireg 9 */ ad_write(devc,8,12345); if (ad_read(devc,9)!=12345) { DEBUGLOG (printk ("ad1816: Chip is not an AD1816 (Test 1)\n")); return(0); } /* writes to ireg 8 are copied to ireg 9 */ ad_write(devc,8,54321); if (ad_read(devc,9)!=54321) { DEBUGLOG (printk ("ad1816: Chip is not an AD1816 (Test 2)\n")); return(0); } /* writes to ireg 10 are copied to ireg 11 */ ad_write(devc,10,54321); if (ad_read(devc,11)!=54321) { DEBUGLOG (printk ("ad1816: Chip is not an AD1816 (Test 3)\n")); return(0); } /* writes to ireg 10 are copied to ireg 11 */ ad_write(devc,10,12345); if (ad_read(devc,11)!=12345) { DEBUGLOG (printk ("ad1816: Chip is not an AD1816 (Test 4)\n")); return(0); } /* bit in base +1 cannot be set to 1 */ tmp=inb(devc->base+1); outb(0xff,devc->base+1); if (inb(devc->base+1)!=tmp) { DEBUGLOG (printk ("ad1816: Chip is not an AD1816 (Test 5)\n")); return(0); } DEBUGLOG (printk ("ad1816: detect() - Detected OK\n")); DEBUGLOG (printk ("ad1816: AD1816 Version: %d\n",ad_read(devc,45))); /* detection was successful */ return 1; }/* allocate resources from the kernel. If any allocation fails, free all allocated resources and exit attach. */static void __init attach_ad1816 (struct address_info *hw_config){ int my_dev; char dev_name[100]; ad1816_info *devc = &dev_info[nr_ad1816_devs]; /* allocate i/o ports */ request_region (hw_config->io_base, 16, "AD1816 Sound"); devc->base = hw_config->io_base; /* disable all interrupts */ ad_write(devc,1,0); /* Clear pending interrupts */ outb (0, devc->base+1); /* allocate irq */ if (hw_config->irq < 0 || hw_config->irq > 15) { release_region(hw_config->io_base, 16); return; } if (request_irq(hw_config->irq, ad1816_interrupt,0, "SoundPort", hw_config->osp) < 0) { printk ("ad1816: IRQ in use\n"); release_region(hw_config->io_base, 16); return; } devc->irq=hw_config->irq; /* DMA stuff */ if (sound_alloc_dma (hw_config->dma, "Sound System")) { printk ("ad1816: Can't allocate DMA%d\n", hw_config->dma); free_irq(hw_config->irq,hw_config->osp); release_region(hw_config->io_base, 16); return; } devc->dma_playback=hw_config->dma; if ( hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) { if (sound_alloc_dma (hw_config->dma2, "Sound System (capture)")) { printk ("ad1816: Can't allocate DMA%d\n", hw_config->dma2); sound_free_dma(hw_config->dma); free_irq(hw_config->irq,hw_config->osp); release_region(hw_config->io_base, 16); return; } devc->dma_capture=hw_config->dma2; devc->audio_mode=DMA_AUTOMODE|DMA_DUPLEX; } else { devc->dma_capture=-1; devc->audio_mode=DMA_AUTOMODE; } sprintf (dev_name,"AD1816 audio driver"); conf_printf2 (dev_name, devc->base, devc->irq, hw_config->dma, hw_config->dma2); /* register device */ if ((my_dev = sound_install_audiodrv (AUDIO_DRIVER_VERSION, dev_name, &ad1816_audio_driver, sizeof (struct audio_driver), devc->audio_mode, ad_format_mask, devc, hw_config->dma, hw_config->dma2)) < 0) { printk ("ad1816: Can't install sound driver\n"); if (devc->dma_capture>=0) { sound_free_dma(hw_config->dma2); } sound_free_dma(hw_config->dma); free_irq(hw_config->irq,hw_config->osp); release_region(hw_config->io_base, 16); return; } /* fill rest of structure with reasonable default values */ irq2dev[hw_config->irq] = devc->dev_no = my_dev; devc->opened = 0; devc->irq_ok = 0; devc->osp = hw_config->osp; nr_ad1816_devs++; ad_write(devc,32,0x80f0); /* sound system mode */ if (options&1) { ad_write(devc,33,0); /* disable all audiosources for dsp */ } else { ad_write(devc,33,0x03f8); /* enable all audiosources for dsp */ } ad_write(devc,4,0x8080); /* default values for volumes (muted)*/ ad_write(devc,5,0x8080); ad_write(devc,6,0x8080); ad_write(devc,7,0x8080); ad_write(devc,15,0x8888); ad_write(devc,16,0x8888); ad_write(devc,17,0x8888); ad_write(devc,18,0x8888); ad_write(devc,19,0xc888); /* +20db mic active */ ad_write(devc,14,0x0000); /* Master volume unmuted */ ad_write(devc,39,0x009f); /* 3D effect on 0% phone out muted */ ad_write(devc,44,0x0080); /* everything on power, 3d enabled for d/a */ outb(0x10,devc->base+8); /* set dma mode */ outb(0x10,devc->base+9); /* enable capture + playback interrupt */ ad_write(devc,1,0xc000); /* set mixer defaults */ ad1816_mixer_reset (devc); /* register mixer */ if ((audio_devs[my_dev]->mixer_dev=sound_install_mixer( MIXER_DRIVER_VERSION, dev_name, &ad1816_mixer_operations, sizeof (struct mixer_operations), devc)) >= 0) { audio_devs[my_dev]->min_fragment = 0; }}static void __exit unload_card(ad1816_info *devc){ int mixer, dev = 0; if (devc != NULL) { DEBUGLOG (printk("ad1816: Unloading card at base=%x\n",devc->base)); dev = devc->dev_no; mixer = audio_devs[dev]->mixer_dev; /* unreg mixer*/ if(mixer>=0) { sound_unload_mixerdev(mixer); } sound_unload_audiodev(dev); /* free dma channels */ if (devc->dma_capture>=0) { sound_free_dma(devc->dma_capture); } /* card wont get added if resources could not be allocated thus we need not ckeck if allocation was successful */ sound_free_dma (devc->dma_playback); free_irq(devc->irq, devc->osp); release_region (devc->base, 16); DEBUGLOG (printk("ad1816: Unloading card at base=%x was successful\n",devc->base)); } else { printk ("ad1816: no device/card specified\n"); }}static struct address_info cfg;static int __initdata io = -1;static int __initdata irq = -1;static int __initdata dma = -1;static int __initdata dma2 = -1;#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULEstruct pci_dev *ad1816_dev = NULL;static int activated = 1;static int isapnp = 1;static int isapnpjump = 0;MODULE_PARM(isapnp, "i");MODULE_PARM(isapnpjump, "i");#elsestatic int isapnp = 0;#endifMODULE_PARM(io,"i");MODULE_PARM(irq,"i");MODULE_PARM(dma,"i");MODULE_PARM(dma2,"i");MODULE_PARM(ad1816_clockfreq,"i");MODULE_PARM(options,"i");#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULEstatic struct pci_dev *activate_dev(char *devname, char *resname, struct pci_dev *dev){ int err; if(dev->active) { activated = 0; return(dev); } if((err = dev->activate(dev)) < 0) { printk(KERN_ERR "ad1816: %s %s config failed (out of resources?)[%d]\n", devname, resname, err); dev->deactivate(dev); return(NULL); } return(dev);}static struct pci_dev *ad1816_init_generic(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config){ if((ad1816_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL))) { ad1816_dev->prepare(ad1816_dev); if((ad1816_dev = activate_dev("Analog Devices 1816(A)", "ad1816", ad1816_dev))) { hw_config->io_base = ad1816_dev->resource[2].start; hw_config->irq = ad1816_dev->irq_resource[0].start; hw_config->dma = ad1816_dev->dma_resource[0].start; hw_config->dma2 = ad1816_dev->dma_resource[1].start; } } return(ad1816_dev);}static struct { unsigned short vendor; unsigned short function; struct pci_dev * (*initfunc)(struct pci_bus*, struct pci_dev *, struct address_info *); char *name;} isapnp_ad1816_list[] __initdata = { {ISAPNP_VENDOR('A','D','S'), ISAPNP_FUNCTION(0x7150), &ad1816_init_generic, "Analog Devices 1815" }, {ISAPNP_VENDOR('A','D','S'), ISAPNP_FUNCTION(0x7180), &ad1816_init_generic, "Analog Devices 1816A" }, {0}};static int __init ad1816_init_isapnp(struct address_info *hw_config, struct pci_bus *bus, struct pci_dev *card, int slot){ struct pci_dev *idev = NULL; /* You missed the init func? That's bad. */ if(isapnp_ad1816_list[slot].initfunc) { char *busname = bus->name[0] ? bus->name : isapnp_ad1816_list[slot].name; printk(KERN_INFO "ad1816: %s detected\n", busname); /* Initialize this baby. */ if((idev = isapnp_ad1816_list[slot].initfunc(bus, card, hw_config))) { /* We got it. */ printk(KERN_NOTICE "ad1816: ISAPnP reports '%s' at i/o %#x, irq %d, dma %d, %d\n", busname, hw_config->io_base, hw_config->irq, hw_config->dma, hw_config->dma2); return 1; } else printk(KERN_INFO "ad1816: Failed to initialize %s\n", busname); } else printk(KERN_ERR "ad1816: Bad entry in ad1816.c PnP table\n"); return 0;}/* * Actually this routine will detect and configure only the first card with successful * initialization. isapnpjump could be used to jump to a specific entry. * Please always add entries at the end of the array. * Should this be fixed? - azummo */int __init ad1816_probe_isapnp(struct address_info *hw_config){ int i; /* Count entries in isapnp_ad1816_list */ for (i = 0; isapnp_ad1816_list[i].vendor != 0; i++) ; /* Check and adjust isapnpjump */ if( isapnpjump < 0 || isapnpjump > ( i - 1 ) ) { printk(KERN_ERR "ad1816: Valid range for isapnpjump is 0-%d. Adjusted to 0.\n", i-1); isapnpjump = 0; } for (i = isapnpjump; isapnp_ad1816_list[i].vendor != 0; i++) { struct pci_dev *card = NULL; while ((card = isapnp_find_dev(NULL, isapnp_ad1816_list[i].vendor, isapnp_ad1816_list[i].function, card))) if(ad1816_init_isapnp(hw_config, card->bus, card, i)) return 0; } return -ENODEV;}#endifstatic int __init init_ad1816(void){#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE if(isapnp && (ad1816_probe_isapnp(&cfg) < 0) ) { printk(KERN_NOTICE "ad1816: No ISAPnP cards found, trying standard ones...\n"); isapnp = 0; }#endif if( isapnp == 0) { cfg.io_base = io; cfg.irq = irq; cfg.dma = dma; cfg.dma2 = dma2; } if (cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.dma2 == -1) { printk(KERN_INFO "ad1816: dma, dma2, irq and io must be set.\n"); return -EINVAL; } if (probe_ad1816(&cfg) == 0) { return -ENODEV; } attach_ad1816(&cfg); return 0;}static void __exit cleanup_ad1816 (void){ int i; ad1816_info *devc = NULL; /* remove any soundcard */ for (i = 0; i < nr_ad1816_devs; i++) { devc = &dev_info[i]; unload_card(devc); } nr_ad1816_devs=0;#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE if(activated) if(ad1816_dev) ad1816_dev->deactivate(ad1816_dev);#endif}module_init(init_ad1816);module_exit(cleanup_ad1816);#ifndef MODULEstatic int __init setup_ad1816(char *str){ /* io, irq, dma, dma2 */ int ints[5]; str = get_options(str, ARRAY_SIZE(ints), ints); io = ints[1]; irq = ints[2]; dma = ints[3]; dma2 = ints[4]; return 1;}__setup("ad1816=", setup_ad1816);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -