patch-2.3.43 linux/drivers/sound/sonicvibes.c
Next file: linux/drivers/sound/soundcard.c
Previous file: linux/drivers/sound/sb_card.c
Back to the patch index
Back to the overall index
- Lines: 730
- Date:
Wed Feb 9 11:42:35 2000
- Orig file:
v2.3.42/linux/drivers/sound/sonicvibes.c
- Orig date:
Fri Jan 21 18:19:17 2000
diff -u --recursive --new-file v2.3.42/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
@@ -87,6 +87,7 @@
* 08.01.2000 0.25 Prevent some ioctl's from returning bad count values on underrun/overrun;
* Tim Janik's BSE (Bedevilled Sound Engine) found this
* use Martin Mares' pci_assign_resource
+ * 07.02.2000 0.26 Use pci_alloc_consistent and pci_register_driver
*
*/
@@ -287,8 +288,11 @@
/* magic */
unsigned int magic;
- /* we keep sv cards in a linked list */
- struct sv_state *next;
+ /* list of sonicvibes devices */
+ struct list_head devs;
+
+ /* the corresponding pci_dev structure */
+ struct pci_dev *dev;
/* soundcore stuff */
int dev_audio;
@@ -319,6 +323,7 @@
struct dmabuf {
void *rawbuf;
+ dma_addr_t dmaaddr;
unsigned buforder;
unsigned numfrag;
unsigned fragshift;
@@ -354,7 +359,7 @@
/* --------------------------------------------------------------------- */
-static struct sv_state *devs = NULL;
+static LIST_HEAD(devs);
static unsigned long wavetable_mem = 0;
/* --------------------------------------------------------------------- */
@@ -684,7 +689,7 @@
#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
#define DMABUF_MINORDER 1
-static void dealloc_dmabuf(struct dmabuf *db)
+static void dealloc_dmabuf(struct sv_state *s, struct dmabuf *db)
{
unsigned long map, mapend;
@@ -693,7 +698,7 @@
mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
clear_bit(PG_reserved, &mem_map[map].flags);
- free_pages((unsigned long)db->rawbuf, db->buforder);
+ pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
}
db->rawbuf = NULL;
db->mapped = db->ready = 0;
@@ -729,7 +734,7 @@
if (!db->rawbuf) {
db->ready = db->mapped = 0;
for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
- if ((db->rawbuf = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, order)))
+ if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
break;
if (!db->rawbuf)
return -ENOMEM;
@@ -770,12 +775,12 @@
memset(db->rawbuf, (fmt & SV_CFMT_16BIT) ? 0 : 0x80, db->dmasize);
spin_lock_irqsave(&s->lock, flags);
if (rec) {
- set_dmac(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift);
+ set_dmac(s, db->dmaaddr, db->numfrag << db->fragshift);
/* program enhanced mode registers */
wrindir(s, SV_CIDMACBASECOUNT1, (db->fragsamples-1) >> 8);
wrindir(s, SV_CIDMACBASECOUNT0, db->fragsamples-1);
} else {
- set_dmaa(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift);
+ set_dmaa(s, db->dmaaddr, db->numfrag << db->fragshift);
/* program enhanced mode registers */
wrindir(s, SV_CIDMAABASECOUNT1, (db->fragsamples-1) >> 8);
wrindir(s, SV_CIDMAABASECOUNT0, db->fragsamples-1);
@@ -1223,12 +1228,16 @@
static int sv_open_mixdev(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
- struct sv_state *s = devs;
+ struct list_head *list;
+ struct sv_state *s;
- while (s && s->dev_mixer != minor)
- s = s->next;
- if (!s)
- return -ENODEV;
+ for (list = devs.next; ; list = list->next) {
+ if (list == &devs)
+ return -ENODEV;
+ s = list_entry(list, struct sv_state, devs);
+ if (s->dev_mixer == minor)
+ break;
+ }
VALIDATE_STATE(s);
file->private_data = s;
MOD_INC_USE_COUNT;
@@ -1250,19 +1259,10 @@
}
static /*const*/ struct file_operations sv_mixer_fops = {
- &sv_llseek,
- NULL, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- &sv_ioctl_mixdev,
- NULL, /* mmap */
- &sv_open_mixdev,
- NULL, /* flush */
- &sv_release_mixdev,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
+ llseek: sv_llseek,
+ ioctl: sv_ioctl_mixdev,
+ open: sv_open_mixdev,
+ release: sv_release_mixdev,
};
/* --------------------------------------------------------------------- */
@@ -1852,13 +1852,17 @@
{
int minor = MINOR(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
- struct sv_state *s = devs;
unsigned char fmtm = ~0, fmts = 0;
+ struct list_head *list;
+ struct sv_state *s;
- while (s && ((s->dev_audio ^ minor) & ~0xf))
- s = s->next;
- if (!s)
- return -ENODEV;
+ for (list = devs.next; ; list = list->next) {
+ if (list == &devs)
+ return -ENODEV;
+ s = list_entry(list, struct sv_state, devs);
+ if (!((s->dev_audio ^ minor) & ~0xf))
+ break;
+ }
VALIDATE_STATE(s);
file->private_data = s;
/* wait for device to become free */
@@ -1909,11 +1913,11 @@
down(&s->open_sem);
if (file->f_mode & FMODE_WRITE) {
stop_dac(s);
- dealloc_dmabuf(&s->dma_dac);
+ dealloc_dmabuf(s, &s->dma_dac);
}
if (file->f_mode & FMODE_READ) {
stop_adc(s);
- dealloc_dmabuf(&s->dma_adc);
+ dealloc_dmabuf(s, &s->dma_adc);
}
s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
wake_up(&s->open_wait);
@@ -1923,19 +1927,14 @@
}
static /*const*/ struct file_operations sv_audio_fops = {
- &sv_llseek,
- &sv_read,
- &sv_write,
- NULL, /* readdir */
- &sv_poll,
- &sv_ioctl,
- &sv_mmap,
- &sv_open,
- NULL, /* flush */
- &sv_release,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
+ llseek: sv_llseek,
+ read: sv_read,
+ write: sv_write,
+ poll: sv_poll,
+ ioctl: sv_ioctl,
+ mmap: sv_mmap,
+ open: sv_open,
+ release: sv_release,
};
/* --------------------------------------------------------------------- */
@@ -2098,13 +2097,17 @@
{
int minor = MINOR(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
- struct sv_state *s = devs;
unsigned long flags;
+ struct list_head *list;
+ struct sv_state *s;
- while (s && s->dev_midi != minor)
- s = s->next;
- if (!s)
- return -ENODEV;
+ for (list = devs.next; ; list = list->next) {
+ if (list == &devs)
+ return -ENODEV;
+ s = list_entry(list, struct sv_state, devs);
+ if (s->dev_midi == minor)
+ break;
+ }
VALIDATE_STATE(s);
file->private_data = s;
/* wait for device to become free */
@@ -2203,19 +2206,12 @@
}
static /*const*/ struct file_operations sv_midi_fops = {
- &sv_llseek,
- &sv_midi_read,
- &sv_midi_write,
- NULL, /* readdir */
- &sv_midi_poll,
- NULL, /* ioctl */
- NULL, /* mmap */
- &sv_midi_open,
- NULL, /* flush */
- &sv_midi_release,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
+ llseek: sv_llseek,
+ read: sv_midi_read,
+ write: sv_midi_write,
+ poll: sv_midi_poll,
+ open: sv_midi_open,
+ release: sv_midi_release,
};
/* --------------------------------------------------------------------- */
@@ -2321,12 +2317,16 @@
{
int minor = MINOR(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
- struct sv_state *s = devs;
+ struct list_head *list;
+ struct sv_state *s;
- while (s && s->dev_dmfm != minor)
- s = s->next;
- if (!s)
- return -ENODEV;
+ for (list = devs.next; ; list = list->next) {
+ if (list == &devs)
+ return -ENODEV;
+ s = list_entry(list, struct sv_state, devs);
+ if (s->dev_dmfm == minor)
+ break;
+ }
VALIDATE_STATE(s);
file->private_data = s;
/* wait for device to become free */
@@ -2380,24 +2380,15 @@
}
static /*const*/ struct file_operations sv_dmfm_fops = {
- &sv_llseek,
- NULL, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- &sv_dmfm_ioctl,
- NULL, /* mmap */
- &sv_dmfm_open,
- NULL, /* flush */
- &sv_dmfm_release,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
+ llseek: sv_llseek,
+ ioctl: sv_dmfm_ioctl,
+ open: sv_dmfm_open,
+ release: sv_dmfm_release,
};
/* --------------------------------------------------------------------- */
-/* maximum number of devices */
+/* maximum number of devices; only used for command line params */
#define NR_DEVICE 5
static int reverb[NR_DEVICE] = { 0, };
@@ -2406,6 +2397,8 @@
static int wavetable[NR_DEVICE] = { 0, };
#endif
+static unsigned int devindex = 0;
+
MODULE_PARM(reverb, "1-" __MODULE_STRING(NR_DEVICE) "i");
MODULE_PARM_DESC(reverb, "if 1 enables the reverb circuitry. NOTE: your card must have the reverb RAM");
#if 0
@@ -2437,216 +2430,235 @@
((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
-static int __init init_sonicvibes(void)
+static int sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{
static const char __initlocaldata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller";
struct sv_state *s;
- struct pci_dev *pcidev = NULL;
mm_segment_t fs;
- int i, val, index = 0;
+ int i, val;
char *ddmaname;
unsigned ddmanamelen;
+ if (!RSRCISIOREGION(pcidev, RESOURCE_SB) ||
+ !RSRCISIOREGION(pcidev, RESOURCE_ENH) ||
+ !RSRCISIOREGION(pcidev, RESOURCE_SYNTH) ||
+ !RSRCISIOREGION(pcidev, RESOURCE_MIDI) ||
+ !RSRCISIOREGION(pcidev, RESOURCE_GAME))
+ return -1;
+ if (pcidev->irq == 0)
+ return -1;
+ /* try to allocate a DDMA resource if not already available */
+ if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) {
+ pcidev->resource[RESOURCE_DDMA].start = 0;
+ pcidev->resource[RESOURCE_DDMA].end = 2*SV_EXTENT_DMA-1;
+ pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO;
+ ddmanamelen = strlen(sv_ddma_name)+1;
+ if (!(ddmaname = kmalloc(ddmanamelen, GFP_KERNEL)))
+ return -1;
+ memcpy(ddmaname, sv_ddma_name, ddmanamelen);
+ pcidev->resource[RESOURCE_DDMA].name = ddmaname;
+ if (pci_assign_resource(pcidev, RESOURCE_DDMA)) {
+ pcidev->resource[RESOURCE_DDMA].name = NULL;
+ kfree(ddmaname);
+ printk(KERN_ERR "sv: cannot allocate DDMA controller io ports\n");
+ return -1;
+ }
+ }
+ if (!(s = kmalloc(sizeof(struct sv_state), GFP_KERNEL))) {
+ printk(KERN_WARNING "sv: out of memory\n");
+ return -1;
+ }
+ memset(s, 0, sizeof(struct sv_state));
+ init_waitqueue_head(&s->dma_adc.wait);
+ init_waitqueue_head(&s->dma_dac.wait);
+ init_waitqueue_head(&s->open_wait);
+ init_waitqueue_head(&s->midi.iwait);
+ init_waitqueue_head(&s->midi.owait);
+ init_MUTEX(&s->open_sem);
+ spin_lock_init(&s->lock);
+ s->magic = SV_MAGIC;
+ s->dev = pcidev;
+ s->iosb = RSRCADDRESS(pcidev, RESOURCE_SB);
+ s->ioenh = RSRCADDRESS(pcidev, RESOURCE_ENH);
+ s->iosynth = RSRCADDRESS(pcidev, RESOURCE_SYNTH);
+ s->iomidi = RSRCADDRESS(pcidev, RESOURCE_MIDI);
+ s->iogame = RSRCADDRESS(pcidev, RESOURCE_GAME);
+ s->iodmaa = RSRCADDRESS(pcidev, RESOURCE_DDMA);
+ s->iodmac = RSRCADDRESS(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA;
+ pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */
+ pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */
+ printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#lx %#x %#x\n",
+ s->iosb, s->ioenh, s->iosynth, s->iomidi, s->iogame, s->iodmaa, s->iodmac);
+ s->irq = pcidev->irq;
+
+ /* hack */
+ pci_write_config_dword(pcidev, 0x60, wavetable_mem >> 12); /* wavetable base address */
+
+ if (!request_region(s->ioenh, SV_EXTENT_ENH, "S3 SonicVibes PCM")) {
+ printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1);
+ goto err_region5;
+ }
+ if (!request_region(s->iodmaa, SV_EXTENT_DMA, "S3 SonicVibes DMAA")) {
+ printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmaa, s->iodmaa+SV_EXTENT_DMA-1);
+ goto err_region4;
+ }
+ if (!request_region(s->iodmac, SV_EXTENT_DMA, "S3 SonicVibes DMAC")) {
+ printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmac, s->iodmac+SV_EXTENT_DMA-1);
+ goto err_region3;
+ }
+ if (!request_region(s->iomidi, SV_EXTENT_MIDI, "S3 SonicVibes Midi")) {
+ printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iomidi, s->iomidi+SV_EXTENT_MIDI-1);
+ goto err_region2;
+ }
+ if (!request_region(s->iosynth, SV_EXTENT_SYNTH, "S3 SonicVibes Synth")) {
+ printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1);
+ goto err_region1;
+ }
+ pci_enable_device(pcidev);
+ /* initialize codec registers */
+ outb(0x80, s->ioenh + SV_CODEC_CONTROL); /* assert reset */
+ udelay(50);
+ outb(0x00, s->ioenh + SV_CODEC_CONTROL); /* deassert reset */
+ udelay(50);
+ outb(SV_CCTRL_INTADRIVE | SV_CCTRL_ENHANCED /*| SV_CCTRL_WAVETABLE */
+ | (reverb[devindex] ? SV_CCTRL_REVERB : 0), s->ioenh + SV_CODEC_CONTROL);
+ inb(s->ioenh + SV_CODEC_STATUS); /* clear ints */
+ wrindir(s, SV_CIDRIVECONTROL, 0); /* drive current 16mA */
+ wrindir(s, SV_CIENABLE, s->enable = 0); /* disable DMAA and DMAC */
+ outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK);
+ /* outb(0xff, s->iodmaa + SV_DMA_RESET); */
+ /* outb(0xff, s->iodmac + SV_DMA_RESET); */
+ inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
+ wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */
+ wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */
+ wrindir(s, SV_CIDIGITALPWRDOWN, 0); /* power up the digital parts of the device */
+ setpll(s, SV_CIADCPLLM, 8000);
+ wrindir(s, SV_CISRSSPACE, 0x80); /* SRS off */
+ wrindir(s, SV_CIPCMSR0, (8000 * 65536 / FULLRATE) & 0xff);
+ wrindir(s, SV_CIPCMSR1, ((8000 * 65536 / FULLRATE) >> 8) & 0xff);
+ wrindir(s, SV_CIADCOUTPUT, 0);
+ /* request irq */
+ if (request_irq(s->irq, sv_interrupt, SA_SHIRQ, "S3 SonicVibes", s)) {
+ printk(KERN_ERR "sv: irq %u in use\n", s->irq);
+ goto err_irq;
+ }
+ printk(KERN_INFO "sv: found adapter at io %#lx irq %u dmaa %#06x dmac %#06x revision %u\n",
+ s->ioenh, s->irq, s->iodmaa, s->iodmac, rdindir(s, SV_CIREVISION));
+ /* register devices */
+ if ((s->dev_audio = register_sound_dsp(&sv_audio_fops, -1)) < 0)
+ goto err_dev1;
+ if ((s->dev_mixer = register_sound_mixer(&sv_mixer_fops, -1)) < 0)
+ goto err_dev2;
+ if ((s->dev_midi = register_sound_midi(&sv_midi_fops, -1)) < 0)
+ goto err_dev3;
+ if ((s->dev_dmfm = register_sound_special(&sv_dmfm_fops, 15 /* ?? */)) < 0)
+ goto err_dev4;
+ pci_set_master(pcidev); /* enable bus mastering */
+ /* initialize the chips */
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ val = SOUND_MASK_LINE|SOUND_MASK_SYNTH;
+ mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
+ for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
+ val = initvol[i].vol;
+ mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
+ }
+ set_fs(fs);
+ /* store it in the driver field */
+ pcidev->driver_data = s;
+ pcidev->dma_mask = 0x00ffffff;
+ /* put it into driver list */
+ list_add_tail(&s->devs, &devs);
+ /* increment devindex */
+ if (devindex < NR_DEVICE-1)
+ devindex++;
+ return 0;
+
+ err_dev4:
+ unregister_sound_midi(s->dev_midi);
+ err_dev3:
+ unregister_sound_mixer(s->dev_mixer);
+ err_dev2:
+ unregister_sound_dsp(s->dev_audio);
+ err_dev1:
+ printk(KERN_ERR "sv: cannot register misc device\n");
+ free_irq(s->irq, s);
+ err_irq:
+ release_region(s->iosynth, SV_EXTENT_SYNTH);
+ err_region1:
+ release_region(s->iomidi, SV_EXTENT_MIDI);
+ err_region2:
+ release_region(s->iodmac, SV_EXTENT_DMA);
+ err_region3:
+ release_region(s->iodmaa, SV_EXTENT_DMA);
+ err_region4:
+ release_region(s->ioenh, SV_EXTENT_ENH);
+ err_region5:
+ kfree_s(s, sizeof(struct sv_state));
+ return -1;
+}
+
+static void sv_remove(struct pci_dev *dev)
+{
+ struct sv_state *s = (struct sv_state *)dev->driver_data;
+
+ if (!s)
+ return;
+ list_del(&s->devs);
+ outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */
+ synchronize_irq();
+ inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
+ wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */
+ /*outb(0, s->iodmaa + SV_DMA_RESET);*/
+ /*outb(0, s->iodmac + SV_DMA_RESET);*/
+ free_irq(s->irq, s);
+ release_region(s->iodmac, SV_EXTENT_DMA);
+ release_region(s->iodmaa, SV_EXTENT_DMA);
+ release_region(s->ioenh, SV_EXTENT_ENH);
+ release_region(s->iomidi, SV_EXTENT_MIDI);
+ release_region(s->iosynth, SV_EXTENT_SYNTH);
+ unregister_sound_dsp(s->dev_audio);
+ unregister_sound_mixer(s->dev_mixer);
+ unregister_sound_midi(s->dev_midi);
+ unregister_sound_special(s->dev_dmfm);
+ kfree_s(s, sizeof(struct sv_state));
+ dev->driver_data = NULL;
+}
+
+static const struct pci_device_id id_table[] = {
+ { PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+ { 0, 0, 0, 0, 0, 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, id_table);
+
+static struct pci_driver sv_driver = {
+ name: "sonicvibes",
+ id_table: id_table,
+ probe: sv_probe,
+ remove: sv_remove
+};
+
+static int __init init_sonicvibes(void)
+{
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "sv: version v0.25 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "sv: version v0.26 time " __TIME__ " " __DATE__ "\n");
#if 0
if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
#endif
- while (index < NR_DEVICE &&
- (pcidev = pci_find_device(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, pcidev))) {
- if (!RSRCISIOREGION(pcidev, RESOURCE_SB) ||
- !RSRCISIOREGION(pcidev, RESOURCE_ENH) ||
- !RSRCISIOREGION(pcidev, RESOURCE_SYNTH) ||
- !RSRCISIOREGION(pcidev, RESOURCE_MIDI) ||
- !RSRCISIOREGION(pcidev, RESOURCE_GAME))
- continue;
- if (pcidev->irq == 0)
- continue;
- /* try to allocate a DDMA resource if not already available */
- if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) {
- pcidev->resource[RESOURCE_DDMA].start = 0;
- pcidev->resource[RESOURCE_DDMA].end = 2*SV_EXTENT_DMA-1;
- pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO;
- ddmanamelen = strlen(sv_ddma_name)+1;
- if (!(ddmaname = kmalloc(ddmanamelen, GFP_KERNEL)))
- continue;
- memcpy(ddmaname, sv_ddma_name, ddmanamelen);
- pcidev->resource[RESOURCE_DDMA].name = ddmaname;
- if (pci_assign_resource(pcidev, RESOURCE_DDMA)) {
- pcidev->resource[RESOURCE_DDMA].name = NULL;
- kfree(ddmaname);
- printk(KERN_ERR "sv: cannot allocate DDMA controller io ports\n");
- continue;
- }
- }
- if (!(s = kmalloc(sizeof(struct sv_state), GFP_KERNEL))) {
- printk(KERN_WARNING "sv: out of memory\n");
- continue;
- }
- memset(s, 0, sizeof(struct sv_state));
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac.wait);
- init_waitqueue_head(&s->open_wait);
- init_waitqueue_head(&s->midi.iwait);
- init_waitqueue_head(&s->midi.owait);
- init_MUTEX(&s->open_sem);
- spin_lock_init(&s->lock);
- s->magic = SV_MAGIC;
- s->iosb = RSRCADDRESS(pcidev, RESOURCE_SB);
- s->ioenh = RSRCADDRESS(pcidev, RESOURCE_ENH);
- s->iosynth = RSRCADDRESS(pcidev, RESOURCE_SYNTH);
- s->iomidi = RSRCADDRESS(pcidev, RESOURCE_MIDI);
- s->iogame = RSRCADDRESS(pcidev, RESOURCE_GAME);
- s->iodmaa = RSRCADDRESS(pcidev, RESOURCE_DDMA);
- s->iodmac = RSRCADDRESS(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA;
- pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */
- pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */
- printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#lx %#x %#x\n",
- s->iosb, s->ioenh, s->iosynth, s->iomidi, s->iogame, s->iodmaa, s->iodmac);
- s->irq = pcidev->irq;
-
- /* hack */
- pci_write_config_dword(pcidev, 0x60, wavetable_mem >> 12); /* wavetable base address */
-
- if (check_region(s->ioenh, SV_EXTENT_ENH)) {
- printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1);
- goto err_region5;
- }
- request_region(s->ioenh, SV_EXTENT_ENH, "S3 SonicVibes PCM");
- if (check_region(s->iodmaa, SV_EXTENT_DMA)) {
- printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmaa, s->iodmaa+SV_EXTENT_DMA-1);
- goto err_region4;
- }
- request_region(s->iodmaa, SV_EXTENT_DMA, "S3 SonicVibes DMAA");
- if (check_region(s->iodmac, SV_EXTENT_DMA)) {
- printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmac, s->iodmac+SV_EXTENT_DMA-1);
- goto err_region3;
- }
- request_region(s->iodmac, SV_EXTENT_DMA, "S3 SonicVibes DMAC");
- if (check_region(s->iomidi, SV_EXTENT_MIDI)) {
- printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iomidi, s->iomidi+SV_EXTENT_MIDI-1);
- goto err_region2;
- }
- request_region(s->iomidi, SV_EXTENT_MIDI, "S3 SonicVibes Midi");
- if (check_region(s->iosynth, SV_EXTENT_SYNTH)) {
- printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1);
- goto err_region1;
- }
- request_region(s->iosynth, SV_EXTENT_SYNTH, "S3 SonicVibes Synth");
- /* initialize codec registers */
- outb(0x80, s->ioenh + SV_CODEC_CONTROL); /* assert reset */
- udelay(50);
- outb(0x00, s->ioenh + SV_CODEC_CONTROL); /* deassert reset */
- udelay(50);
- outb(SV_CCTRL_INTADRIVE | SV_CCTRL_ENHANCED /*| SV_CCTRL_WAVETABLE */
- | (reverb[index] ? SV_CCTRL_REVERB : 0), s->ioenh + SV_CODEC_CONTROL);
- inb(s->ioenh + SV_CODEC_STATUS); /* clear ints */
- wrindir(s, SV_CIDRIVECONTROL, 0); /* drive current 16mA */
- wrindir(s, SV_CIENABLE, s->enable = 0); /* disable DMAA and DMAC */
- outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK);
- /* outb(0xff, s->iodmaa + SV_DMA_RESET); */
- /* outb(0xff, s->iodmac + SV_DMA_RESET); */
- inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
- wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */
- wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */
- wrindir(s, SV_CIDIGITALPWRDOWN, 0); /* power up the digital parts of the device */
- setpll(s, SV_CIADCPLLM, 8000);
- wrindir(s, SV_CISRSSPACE, 0x80); /* SRS off */
- wrindir(s, SV_CIPCMSR0, (8000 * 65536 / FULLRATE) & 0xff);
- wrindir(s, SV_CIPCMSR1, ((8000 * 65536 / FULLRATE) >> 8) & 0xff);
- wrindir(s, SV_CIADCOUTPUT, 0);
- /* request irq */
- if (request_irq(s->irq, sv_interrupt, SA_SHIRQ, "S3 SonicVibes", s)) {
- printk(KERN_ERR "sv: irq %u in use\n", s->irq);
- goto err_irq;
- }
- printk(KERN_INFO "sv: found adapter at io %#lx irq %u dmaa %#06x dmac %#06x revision %u\n",
- s->ioenh, s->irq, s->iodmaa, s->iodmac, rdindir(s, SV_CIREVISION));
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&sv_audio_fops, -1)) < 0)
- goto err_dev1;
- if ((s->dev_mixer = register_sound_mixer(&sv_mixer_fops, -1)) < 0)
- goto err_dev2;
- if ((s->dev_midi = register_sound_midi(&sv_midi_fops, -1)) < 0)
- goto err_dev3;
- if ((s->dev_dmfm = register_sound_special(&sv_dmfm_fops, 15 /* ?? */)) < 0)
- goto err_dev4;
- pci_set_master(pcidev); /* enable bus mastering */
- /* initialize the chips */
- fs = get_fs();
- set_fs(KERNEL_DS);
- val = SOUND_MASK_LINE|SOUND_MASK_SYNTH;
- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
- val = initvol[i].vol;
- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
- }
- set_fs(fs);
- /* queue it for later freeing */
- s->next = devs;
- devs = s;
- index++;
- continue;
-
- err_dev4:
- unregister_sound_midi(s->dev_midi);
- err_dev3:
- unregister_sound_mixer(s->dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- printk(KERN_ERR "sv: cannot register misc device\n");
- free_irq(s->irq, s);
- err_irq:
- release_region(s->iosynth, SV_EXTENT_SYNTH);
- err_region1:
- release_region(s->iomidi, SV_EXTENT_MIDI);
- err_region2:
- release_region(s->iodmac, SV_EXTENT_DMA);
- err_region3:
- release_region(s->iodmaa, SV_EXTENT_DMA);
- err_region4:
- release_region(s->ioenh, SV_EXTENT_ENH);
- err_region5:
- kfree_s(s, sizeof(struct sv_state));
- }
- if (!devs) {
- if (wavetable_mem)
- free_pages(wavetable_mem, 20-PAGE_SHIFT);
- return -ENODEV;
- }
- return 0;
+ if (!pci_register_driver(&sv_driver))
+ return -ENODEV;
+ return 0;
}
static void __exit cleanup_sonicvibes(void)
{
- struct sv_state *s;
-
- while ((s = devs)) {
- devs = devs->next;
- outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */
- synchronize_irq();
- inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
- wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */
- /*outb(0, s->iodmaa + SV_DMA_RESET);*/
- /*outb(0, s->iodmac + SV_DMA_RESET);*/
- free_irq(s->irq, s);
- release_region(s->iodmac, SV_EXTENT_DMA);
- release_region(s->iodmaa, SV_EXTENT_DMA);
- release_region(s->ioenh, SV_EXTENT_ENH);
- release_region(s->iomidi, SV_EXTENT_MIDI);
- release_region(s->iosynth, SV_EXTENT_SYNTH);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->dev_mixer);
- unregister_sound_midi(s->dev_midi);
- unregister_sound_special(s->dev_dmfm);
- kfree_s(s, sizeof(struct sv_state));
- }
- if (wavetable_mem)
- free_pages(wavetable_mem, 20-PAGE_SHIFT);
printk(KERN_INFO "sv: unloading\n");
+ pci_unregister_driver(&sv_driver);
+ if (wavetable_mem)
+ free_pages(wavetable_mem, 20-PAGE_SHIFT);
}
module_init(init_sonicvibes);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)