📄 forte.c
字号:
} spin_lock_irqsave (&chip->lock, flags); /* Advance software pointer */ buffer += sz; if (channel->filled_frags > 0) channel->filled_frags--; channel->swptr += channel->frag_sz; channel->swptr %= channel->buf_sz; i -= sz; } spin_unlock_irqrestore (&chip->lock, flags); return bytes - i;}static struct file_operations forte_dsp_fops = { .owner = THIS_MODULE, .llseek = &no_llseek, .read = &forte_dsp_read, .write = &forte_dsp_write, .poll = &forte_dsp_poll, .ioctl = &forte_dsp_ioctl, .open = &forte_dsp_open, .release = &forte_dsp_release, .mmap = &forte_dsp_mmap,};/* Common ------------------------------------------------------------------ *//** * forte_interrupt: */static irqreturn_tforte_interrupt (int irq, void *dev_id, struct pt_regs *regs){ struct forte_chip *chip = dev_id; struct forte_channel *channel = NULL; u16 status, count; status = inw (chip->iobase + FORTE_IRQ_STATUS); /* If this is not for us, get outta here ASAP */ if ((status & (FORTE_IRQ_PLAYBACK | FORTE_IRQ_CAPTURE)) == 0) return IRQ_NONE; if (status & FORTE_IRQ_PLAYBACK) { channel = &chip->play; spin_lock (&chip->lock); if (channel->frag_sz == 0) goto pack; /* Declare a fragment done */ if (channel->filled_frags > 0) channel->filled_frags--; channel->bytes += channel->frag_sz; channel->nr_irqs++; /* Flip-flop between buffer I and II */ channel->next_buf ^= 1; /* Advance hardware pointer by fragment size and wrap around */ channel->hwptr += channel->frag_sz; channel->hwptr %= channel->buf_sz; /* Buffer I or buffer II BAR */ outl (channel->buf_handle + channel->hwptr, channel->next_buf == 0 ? channel->iobase + FORTE_PLY_BUF1 : channel->iobase + FORTE_PLY_BUF2); /* If the currently playing fragment is last, schedule pause */ if (channel->filled_frags == 1) forte_channel_pause (channel); pack: /* Acknowledge interrupt */ outw (FORTE_IRQ_PLAYBACK, chip->iobase + FORTE_IRQ_STATUS); if (waitqueue_active (&channel->wait)) wake_up_all (&channel->wait); spin_unlock (&chip->lock); } if (status & FORTE_IRQ_CAPTURE) { channel = &chip->rec; spin_lock (&chip->lock); /* One fragment filled */ channel->filled_frags++; /* Get # of completed bytes */ count = inw (channel->iobase + FORTE_PLY_COUNT) + 1; if (count == 0) { DPRINTK ("%s: last, filled_frags = %d\n", __FUNCTION__, channel->filled_frags); channel->filled_frags = 0; goto rack; } /* Buffer I or buffer II BAR */ outl (channel->buf_handle + channel->hwptr, channel->next_buf == 0 ? channel->iobase + FORTE_PLY_BUF1 : channel->iobase + FORTE_PLY_BUF2); /* Flip-flop between buffer I and II */ channel->next_buf ^= 1; /* Advance hardware pointer by fragment size and wrap around */ channel->hwptr += channel->frag_sz; channel->hwptr %= channel->buf_sz; /* Out of buffers */ if (channel->filled_frags == channel->frag_num - 1) forte_channel_stop (channel); rack: /* Acknowledge interrupt */ outw (FORTE_IRQ_CAPTURE, chip->iobase + FORTE_IRQ_STATUS); spin_unlock (&chip->lock); if (waitqueue_active (&channel->wait)) wake_up_all (&channel->wait); } return IRQ_HANDLED;}/** * forte_proc_read: */static intforte_proc_read (char *page, char **start, off_t off, int count, int *eof, void *data){ int i = 0, p_rate, p_chan, r_rate; unsigned short p_reg, r_reg; i += sprintf (page, "ForteMedia FM801 OSS Lite driver\n%s\n \n", DRIVER_VERSION); if (!forte->iobase) return i; p_rate = p_chan = -1; p_reg = inw (forte->iobase + FORTE_PLY_CTRL); p_rate = (p_reg >> 8) & 15; p_chan = (p_reg >> 12) & 3; if (p_rate >= 0 || p_rate <= 10) p_rate = rates[p_rate]; if (p_chan >= 0 || p_chan <= 2) p_chan = channels[p_chan]; r_rate = -1; r_reg = inw (forte->iobase + FORTE_CAP_CTRL); r_rate = (r_reg >> 8) & 15; if (r_rate >= 0 || r_rate <= 10) r_rate = rates[r_rate]; i += sprintf (page + i, " Playback Capture\n" "FIFO empty : %-3s %-3s\n" "Buf1 Last : %-3s %-3s\n" "Buf2 Last : %-3s %-3s\n" "Started : %-3s %-3s\n" "Paused : %-3s %-3s\n" "Immed Stop : %-3s %-3s\n" "Rate : %-5d %-5d\n" "Channels : %-5d -\n" "16-bit : %-3s %-3s\n" "Stereo : %-3s %-3s\n" " \n" "Buffer Sz : %-6d %-6d\n" "Frag Sz : %-6d %-6d\n" "Frag Num : %-6d %-6d\n" "Frag msecs : %-6d %-6d\n" "Used Frags : %-6d %-6d\n" "Mapped : %-3s %-3s\n", p_reg & 1<<0 ? "yes" : "no", r_reg & 1<<0 ? "yes" : "no", p_reg & 1<<1 ? "yes" : "no", r_reg & 1<<1 ? "yes" : "no", p_reg & 1<<2 ? "yes" : "no", r_reg & 1<<2 ? "yes" : "no", p_reg & 1<<5 ? "yes" : "no", r_reg & 1<<5 ? "yes" : "no", p_reg & 1<<6 ? "yes" : "no", r_reg & 1<<6 ? "yes" : "no", p_reg & 1<<7 ? "yes" : "no", r_reg & 1<<7 ? "yes" : "no", p_rate, r_rate, p_chan, p_reg & 1<<14 ? "yes" : "no", r_reg & 1<<14 ? "yes" : "no", p_reg & 1<<15 ? "yes" : "no", r_reg & 1<<15 ? "yes" : "no", forte->play.buf_sz, forte->rec.buf_sz, forte->play.frag_sz, forte->rec.frag_sz, forte->play.frag_num, forte->rec.frag_num, forte->play.frag_msecs, forte->rec.frag_msecs, forte->play.filled_frags, forte->rec.filled_frags, forte->play.mapped ? "yes" : "no", forte->rec.mapped ? "yes" : "no" ); return i;}/** * forte_proc_init: * * Creates driver info entries in /proc */static int __init forte_proc_init (void){ if (!proc_mkdir ("driver/forte", NULL)) return -EIO; if (!create_proc_read_entry ("driver/forte/chip", 0, NULL, forte_proc_read, forte)) { remove_proc_entry ("driver/forte", NULL); return -EIO; } if (!create_proc_read_entry("driver/forte/ac97", 0, NULL, ac97_read_proc, forte->ac97)) { remove_proc_entry ("driver/forte/chip", NULL); remove_proc_entry ("driver/forte", NULL); return -EIO; } return 0;}/** * forte_proc_remove: * * Removes driver info entries in /proc */static voidforte_proc_remove (void){ remove_proc_entry ("driver/forte/ac97", NULL); remove_proc_entry ("driver/forte/chip", NULL); remove_proc_entry ("driver/forte", NULL); }/** * forte_chip_init: * @chip: Chip instance to initialize * * Description: * Resets chip, configures codec and registers the driver with * the sound subsystem. * * Press and hold Start for 8 secs, then switch on Run * and hold for 4 seconds. Let go of Start. Numbers * assume a properly oiled TWG. */static int __devinitforte_chip_init (struct forte_chip *chip){ u8 revision; u16 cmdw; struct ac97_codec *codec; pci_read_config_byte (chip->pci_dev, PCI_REVISION_ID, &revision); if (revision >= 0xB1) { chip->multichannel = 1; printk (KERN_INFO PFX "Multi-channel device detected.\n"); } /* Reset chip */ outw (FORTE_CC_CODEC_RESET | FORTE_CC_AC97_RESET, chip->iobase + FORTE_CODEC_CTRL); udelay(100); outw (0, chip->iobase + FORTE_CODEC_CTRL); /* Request read from AC97 */ outw (FORTE_AC97_READ | (0 << FORTE_AC97_ADDR_SHIFT), chip->iobase + FORTE_AC97_CMD); mdelay(750); if ((inw (chip->iobase + FORTE_AC97_CMD) & (3<<8)) != (1<<8)) { printk (KERN_INFO PFX "AC97 codec not responding"); return -EIO; } /* Init volume */ outw (0x0808, chip->iobase + FORTE_PCM_VOL); outw (0x9f1f, chip->iobase + FORTE_FM_VOL); outw (0x8808, chip->iobase + FORTE_I2S_VOL); /* I2S control - I2S mode */ outw (0x0003, chip->iobase + FORTE_I2S_MODE); /* Interrupt setup - unmask PLAYBACK & CAPTURE */ cmdw = inw (chip->iobase + FORTE_IRQ_MASK); cmdw &= ~0x0003; outw (cmdw, chip->iobase + FORTE_IRQ_MASK); /* Interrupt clear */ outw (FORTE_IRQ_PLAYBACK|FORTE_IRQ_CAPTURE, chip->iobase + FORTE_IRQ_STATUS); /* Set up the AC97 codec */ if ((codec = ac97_alloc_codec()) == NULL) return -ENOMEM; codec->private_data = chip; codec->codec_read = forte_ac97_read; codec->codec_write = forte_ac97_write; codec->id = 0; if (ac97_probe_codec (codec) == 0) { printk (KERN_ERR PFX "codec probe failed\n"); ac97_release_codec(codec); return -1; } /* Register mixer */ if ((codec->dev_mixer = register_sound_mixer (&forte_mixer_fops, -1)) < 0) { printk (KERN_ERR PFX "couldn't register mixer!\n"); ac97_release_codec(codec); return -1; } chip->ac97 = codec; /* Register DSP */ if ((chip->dsp = register_sound_dsp (&forte_dsp_fops, -1) ) < 0) { printk (KERN_ERR PFX "couldn't register dsp!\n"); return -1; } /* Register with /proc */ if (forte_proc_init()) { printk (KERN_ERR PFX "couldn't add entries to /proc!\n"); return -1; } return 0;}/** * forte_probe: * @pci_dev: PCI struct for probed device * @pci_id: * * Description: * Allocates chip instance, I/O region, and IRQ */static int __init forte_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id){ struct forte_chip *chip; int ret = 0; /* FIXME: Support more than one chip */ if (found++) return -EIO; /* Ignition */ if (pci_enable_device (pci_dev)) return -EIO; pci_set_master (pci_dev); /* Allocate chip instance and configure */ forte = (struct forte_chip *) kmalloc (sizeof (struct forte_chip), GFP_KERNEL); chip = forte; if (chip == NULL) { printk (KERN_WARNING PFX "Out of memory"); return -ENOMEM; } memset (chip, 0, sizeof (struct forte_chip)); chip->pci_dev = pci_dev; init_MUTEX(&chip->open_sem); spin_lock_init (&chip->lock); spin_lock_init (&chip->ac97_lock); if (! request_region (pci_resource_start (pci_dev, 0), pci_resource_len (pci_dev, 0), DRIVER_NAME)) { printk (KERN_WARNING PFX "Unable to reserve I/O space"); ret = -ENOMEM; goto error; } chip->iobase = pci_resource_start (pci_dev, 0); chip->irq = pci_dev->irq; if (request_irq (chip->irq, forte_interrupt, SA_SHIRQ, DRIVER_NAME, chip)) { printk (KERN_WARNING PFX "Unable to reserve IRQ"); ret = -EIO; goto error; } pci_set_drvdata (pci_dev, chip); printk (KERN_INFO PFX "FM801 chip found at 0x%04lX-0x%04lX IRQ %u\n", chip->iobase, pci_resource_end (pci_dev, 0), chip->irq); /* Power it up */ if ((ret = forte_chip_init (chip)) == 0) return 0; error: if (chip->irq) free_irq (chip->irq, chip); if (chip->iobase) release_region (pci_resource_start (pci_dev, 0), pci_resource_len (pci_dev, 0)); kfree (chip); return ret;}/** * forte_remove: * @pci_dev: PCI device to unclaim * */static void forte_remove (struct pci_dev *pci_dev){ struct forte_chip *chip = pci_get_drvdata (pci_dev); if (chip == NULL) return; /* Turn volume down to avoid popping */ outw (0x1f1f, chip->iobase + FORTE_PCM_VOL); outw (0x1f1f, chip->iobase + FORTE_FM_VOL); outw (0x1f1f, chip->iobase + FORTE_I2S_VOL); forte_proc_remove(); free_irq (chip->irq, chip); release_region (chip->iobase, pci_resource_len (pci_dev, 0)); unregister_sound_dsp (chip->dsp); unregister_sound_mixer (chip->ac97->dev_mixer); ac97_release_codec(chip->ac97); kfree (chip); printk (KERN_INFO PFX "driver released\n");}static struct pci_device_id forte_pci_ids[] = { { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, { 0, }};static struct pci_driver forte_pci_driver = { .name = DRIVER_NAME, .id_table = forte_pci_ids, .probe = forte_probe, .remove = forte_remove,};/** * forte_init_module: * */static int __initforte_init_module (void){ printk (KERN_INFO PFX DRIVER_VERSION "\n"); if (!pci_register_driver (&forte_pci_driver)) { pci_unregister_driver (&forte_pci_driver); return -ENODEV; } return 0;}/** * forte_cleanup_module: * */static void __exit forte_cleanup_module (void){ pci_unregister_driver (&forte_pci_driver);}module_init(forte_init_module);module_exit(forte_cleanup_module);MODULE_AUTHOR("Martin K. Petersen <mkp@mkp.net>");MODULE_DESCRIPTION("ForteMedia FM801 OSS Driver");MODULE_LICENSE("GPL");MODULE_DEVICE_TABLE (pci, forte_pci_ids);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -