📄 ite8172.c
字号:
s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; if (s->dma_adc.ossfragshift < 4) s->dma_adc.ossfragshift = 4; if (s->dma_adc.ossfragshift > 15) s->dma_adc.ossfragshift = 15; if (s->dma_adc.ossmaxfrags < 4) s->dma_adc.ossmaxfrags = 4; if ((ret = prog_dmabuf_adc(s))) return ret; } if (file->f_mode & FMODE_WRITE) { stop_dac(s); s->dma_dac.ossfragshift = val & 0xffff; s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff; if (s->dma_dac.ossfragshift < 4) s->dma_dac.ossfragshift = 4; if (s->dma_dac.ossfragshift > 15) s->dma_dac.ossfragshift = 15; if (s->dma_dac.ossmaxfrags < 4) s->dma_dac.ossmaxfrags = 4; if ((ret = prog_dmabuf_dac(s))) return ret; } return 0; case SNDCTL_DSP_SUBDIVIDE: if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) return -EINVAL; if (get_user(val, (int *)arg)) return -EFAULT; if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) { stop_adc(s); s->dma_adc.subdivision = val; if ((ret = prog_dmabuf_adc(s))) return ret; } if (file->f_mode & FMODE_WRITE) { stop_dac(s); s->dma_dac.subdivision = val; if ((ret = prog_dmabuf_dac(s))) return ret; } return 0; case SOUND_PCM_READ_RATE: return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dacrate, (int *)arg); case SOUND_PCM_READ_CHANNELS: if (file->f_mode & FMODE_READ) return put_user((s->capcc & CC_SM) ? 2 : 1, (int *)arg); else return put_user((s->pcc & CC_SM) ? 2 : 1, (int *)arg); case SOUND_PCM_READ_BITS: if (file->f_mode & FMODE_READ) return put_user((s->capcc & CC_DF) ? 16 : 8, (int *)arg); else return put_user((s->pcc & CC_DF) ? 16 : 8, (int *)arg); case SOUND_PCM_WRITE_FILTER: case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL; } return mixdev_ioctl(&s->codec, cmd, arg);}static int it8172_open(struct inode *inode, struct file *file){ int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); unsigned long flags; struct list_head *list; struct it8172_state *s; int ret; for (list = devs.next; ; list = list->next) { if (list == &devs) return -ENODEV; s = list_entry(list, struct it8172_state, devs); if (!((s->dev_audio ^ minor) & ~0xf)) break; } file->private_data = s; /* wait for device to become free */ down(&s->open_sem); while (s->open_mode & file->f_mode) { if (file->f_flags & O_NONBLOCK) { up(&s->open_sem); return -EBUSY; } add_wait_queue(&s->open_wait, &wait); __set_current_state(TASK_INTERRUPTIBLE); up(&s->open_sem); schedule(); remove_wait_queue(&s->open_wait, &wait); set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); } spin_lock_irqsave(&s->lock, flags); if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = s->dma_adc.total_bytes = 0; s->capcc &= ~(CC_SM | CC_DF); set_adc_rate(s, 8000); if ((minor & 0xf) == SND_DEV_DSP16) s->capcc |= CC_DF; outw(s->capcc, s->io+IT_AC_CAPCC); if ((ret = prog_dmabuf_adc(s))) return ret; } if (file->f_mode & FMODE_WRITE) { s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = s->dma_dac.total_bytes = 0; s->pcc &= ~(CC_SM | CC_DF); set_dac_rate(s, 8000); if ((minor & 0xf) == SND_DEV_DSP16) s->pcc |= CC_DF; outw(s->pcc, s->io+IT_AC_PCC); if ((ret = prog_dmabuf_dac(s))) return ret; } spin_unlock_irqrestore(&s->lock, flags); s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&s->open_sem); return 0;}static int it8172_release(struct inode *inode, struct file *file){ struct it8172_state *s = (struct it8172_state *)file->private_data; lock_kernel(); if (file->f_mode & FMODE_WRITE) drain_dac(s, file->f_flags & O_NONBLOCK); down(&s->open_sem); if (file->f_mode & FMODE_WRITE) { stop_dac(s); dealloc_dmabuf(s, &s->dma_dac); } if (file->f_mode & FMODE_READ) { stop_adc(s); dealloc_dmabuf(s, &s->dma_adc); } s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); up(&s->open_sem); wake_up(&s->open_wait); unlock_kernel(); return 0;}static /*const*/ struct file_operations it8172_audio_fops = { owner: THIS_MODULE, llseek: it8172_llseek, read: it8172_read, write: it8172_write, poll: it8172_poll, ioctl: it8172_ioctl, mmap: it8172_mmap, open: it8172_open, release: it8172_release,};/* --------------------------------------------------------------------- *//* --------------------------------------------------------------------- *//* * for debugging purposes, we'll create a proc device that dumps the * CODEC chipstate */#ifdef IT8172_DEBUGstatic int proc_it8172_dump (char *buf, char **start, off_t fpos, int length, int *eof, void *data){ struct it8172_state *s; int cnt, len = 0; if (list_empty(&devs)) return 0; s = list_entry(devs.next, struct it8172_state, devs); /* print out header */ len += sprintf(buf + len, "\n\t\tIT8172 Audio Debug\n\n"); // print out digital controller state len += sprintf (buf + len, "IT8172 Audio Controller registers\n"); len += sprintf (buf + len, "---------------------------------\n"); cnt=0; while (cnt < 0x72) { if (cnt == IT_AC_PCB1STA || cnt == IT_AC_PCB2STA || cnt == IT_AC_CAPB1STA || cnt == IT_AC_CAPB2STA || cnt == IT_AC_PFDP) { len+= sprintf (buf + len, "reg %02x = %08x\n", cnt, inl(s->io+cnt)); cnt += 4; } else { len+= sprintf (buf + len, "reg %02x = %04x\n", cnt, inw(s->io+cnt)); cnt += 2; } } /* print out CODEC state */ len += sprintf (buf + len, "\nAC97 CODEC registers\n"); len += sprintf (buf + len, "----------------------\n"); for (cnt=0; cnt <= 0x7e; cnt = cnt +2) len+= sprintf (buf + len, "reg %02x = %04x\n", cnt, rdcodec(&s->codec, cnt)); if (fpos >=len){ *start = buf; *eof =1; return 0; } *start = buf + fpos; if ((len -= fpos) > length) return length; *eof =1; return len;}#endif /* IT8172_DEBUG *//* --------------------------------------------------------------------- *//* maximum number of devices; only used for command line params */#define NR_DEVICE 5static int spdif[NR_DEVICE] = { 0, };static unsigned int devindex = 0;MODULE_PARM(spdif, "1-" __MODULE_STRING(NR_DEVICE) "i");MODULE_PARM_DESC(spdif, "if 1 the S/PDIF digital output is enabled");MODULE_AUTHOR("Monta Vista Software, stevel@mvista.com");MODULE_DESCRIPTION("IT8172 AudioPCI97 Driver");MODULE_LICENSE("GPL");/* --------------------------------------------------------------------- */static int __devinit it8172_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid){ struct it8172_state *s; int i, val; unsigned short pcisr, vol; unsigned char legacy, imc; char proc_str[80]; if (pcidev->irq == 0) return -1; if (!(s = kmalloc(sizeof(struct it8172_state), GFP_KERNEL))) { printk(KERN_ERR PFX "alloc of device struct failed\n"); return -1; } memset(s, 0, sizeof(struct it8172_state)); init_waitqueue_head(&s->dma_adc.wait); init_waitqueue_head(&s->dma_dac.wait); init_waitqueue_head(&s->open_wait); init_MUTEX(&s->open_sem); spin_lock_init(&s->lock); s->dev = pcidev; s->io = pci_resource_start(pcidev, 0); s->irq = pcidev->irq; s->vendor = pcidev->vendor; s->device = pcidev->device; pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev); s->codec.private_data = s; s->codec.id = 0; s->codec.codec_read = rdcodec; s->codec.codec_write = wrcodec; s->codec.codec_wait = waitcodec; if (!request_region(s->io, pci_resource_len(pcidev,0), IT8172_MODULE_NAME)) { printk(KERN_ERR PFX "io ports %#lx->%#lx in use\n", s->io, s->io + pci_resource_len(pcidev,0)-1); goto err_region; } if (request_irq(s->irq, it8172_interrupt, SA_INTERRUPT, IT8172_MODULE_NAME, s)) { printk(KERN_ERR PFX "irq %u in use\n", s->irq); goto err_irq; } printk(KERN_INFO PFX "IO at %#lx, IRQ %d\n", s->io, s->irq); /* register devices */ if ((s->dev_audio = register_sound_dsp(&it8172_audio_fops, -1)) < 0) goto err_dev1; if ((s->codec.dev_mixer = register_sound_mixer(&it8172_mixer_fops, -1)) < 0) goto err_dev2;#ifdef IT8172_DEBUG /* intialize the debug proc device */ s->ps = create_proc_read_entry(IT8172_MODULE_NAME, 0, NULL, proc_it8172_dump, NULL);#endif /* IT8172_DEBUG */ /* * Reset the Audio device using the IT8172 PCI Reset register. This * creates an audible double click on a speaker connected to Line-out. */ IT_IO_READ16(IT_PM_PCISR, pcisr); pcisr |= IT_PM_PCISR_ACSR; IT_IO_WRITE16(IT_PM_PCISR, pcisr); /* wait up to 100msec for reset to complete */ for (i=0; pcisr & IT_PM_PCISR_ACSR; i++) { it8172_delay(10); if (i == 10) break; IT_IO_READ16(IT_PM_PCISR, pcisr); } if (i == 10) { printk(KERN_ERR PFX "chip reset timeout!\n"); goto err_dev3; } /* enable pci io and bus mastering */ if (pci_enable_device(pcidev)) goto err_dev3; pci_set_master(pcidev); /* get out of legacy mode */ pci_read_config_byte (pcidev, 0x40, &legacy); pci_write_config_byte (pcidev, 0x40, legacy & ~1); s->spdif_volume = -1; /* check to see if s/pdif mode is being requested */ if (spdif[devindex]) { printk(KERN_INFO PFX "enabling S/PDIF output\n"); s->spdif_volume = 0; outb(GC_SOE, s->io+IT_AC_GC); } else { printk(KERN_INFO PFX "disabling S/PDIF output\n"); outb(0, s->io+IT_AC_GC); } /* cold reset the AC97 */ outw(CODECC_CR, s->io+IT_AC_CODECC); udelay(1000); outw(0, s->io+IT_AC_CODECC); /* need to delay around 500msec(bleech) to give some CODECs enough time to wakeup */ it8172_delay(500); /* AC97 warm reset to start the bitclk */ outw(CODECC_WR, s->io+IT_AC_CODECC); udelay(1000); outw(0, s->io+IT_AC_CODECC); /* codec init */ if (!ac97_probe_codec(&s->codec)) goto err_dev3; /* Enable Volume button interrupts */ imc = inb(s->io+IT_AC_IMC); outb(imc & ~IMC_VCIM, s->io+IT_AC_IMC); /* Un-mute PCM and FM out on the controller */ vol = inw(s->io+IT_AC_PCMOV); outw(vol & ~PCMOV_PCMOM, s->io+IT_AC_PCMOV); vol = inw(s->io+IT_AC_FMOV); outw(vol & ~FMOV_FMOM, s->io+IT_AC_FMOV); /* set channel defaults to 8-bit, mono, 8 Khz */ s->pcc = 0; s->capcc = 0; set_dac_rate(s, 8000); set_adc_rate(s, 8000); /* set mic to be the recording source */ val = SOUND_MASK_MIC; mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); /* mute master and PCM when in S/PDIF mode */ if (s->spdif_volume != -1) { val = 0x0000; mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_VOLUME, (unsigned long)&val); mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_PCM, (unsigned long)&val); } #ifdef IT8172_DEBUG sprintf(proc_str, "driver/%s/%d/ac97", IT8172_MODULE_NAME, s->codec.id); s->ac97_ps = create_proc_read_entry (proc_str, 0, NULL, ac97_read_proc, &s->codec);#endif /* store it in the driver field */ pci_set_drvdata(pcidev, s); pcidev->dma_mask = 0xffffffff; /* put it into driver list */ list_add_tail(&s->devs, &devs); /* increment devindex */ if (devindex < NR_DEVICE-1) devindex++; return 0; err_dev3: unregister_sound_mixer(s->codec.dev_mixer); err_dev2: unregister_sound_dsp(s->dev_audio); err_dev1: printk(KERN_ERR PFX "cannot register misc device\n"); free_irq(s->irq, s); err_irq: release_region(s->io, pci_resource_len(pcidev,0)); err_region: kfree(s); return -1;}static void __devinit it8172_remove(struct pci_dev *dev){ struct it8172_state *s = pci_get_drvdata(dev); if (!s) return; list_del(&s->devs);#ifdef IT8172_DEBUG if (s->ps) remove_proc_entry(IT8172_MODULE_NAME, NULL);#endif /* IT8172_DEBUG */ synchronize_irq(); free_irq(s->irq, s); release_region(s->io, pci_resource_len(dev,0)); unregister_sound_dsp(s->dev_audio); unregister_sound_mixer(s->codec.dev_mixer); kfree(s); pci_set_drvdata(dev, NULL);}static struct pci_device_id id_table[] __devinitdata = { { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { 0, }};MODULE_DEVICE_TABLE(pci, id_table);static struct pci_driver it8172_driver = { name: IT8172_MODULE_NAME, id_table: id_table, probe: it8172_probe, remove: it8172_remove};static int __init init_it8172(void){ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; printk("version v0.26 time " __TIME__ " " __DATE__ "\n"); return pci_module_init(&it8172_driver);}static void __exit cleanup_it8172(void){ printk(KERN_INFO PFX "unloading\n"); pci_unregister_driver(&it8172_driver);}module_init(init_it8172);module_exit(cleanup_it8172);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -