patch-2.3.43 linux/drivers/sound/esssolo1.c
Next file: linux/drivers/sound/maestro.c
Previous file: linux/drivers/sound/es1371.c
Back to the patch index
Back to the overall index
- Lines: 701
- Date:
Wed Feb 9 11:42:35 2000
- Orig file:
v2.3.42/linux/drivers/sound/esssolo1.c
- Orig date:
Fri Jan 28 15:09:08 2000
diff -u --recursive --new-file v2.3.42/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
@@ -66,12 +66,12 @@
* 12.01.2000 0.12 Prevent some ioctl's from returning bad count values on underrun/overrun;
* Tim Janik's BSE (Bedevilled Sound Engine) found this
* Integrated (aka redid 8-)) APM support patch by Zach Brown
+ * 07.02.2000 0.13 Use pci_alloc_consistent and pci_register_driver
*
*/
/*****************************************************************************/
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/string.h>
@@ -83,7 +83,7 @@
#include <linux/soundcard.h>
#include <linux/pci.h>
#include <linux/bitops.h>
-#include <linux/apm_bios.h>
+#include <linux/pm.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/init.h>
@@ -137,11 +137,11 @@
/* magic */
unsigned int magic;
- /* we keep the cards in a linked list */
- struct solo1_state *next;
+ /* list of esssolo1 devices */
+ struct list_head devs;
- /* pcidev is needed to turn off the DDMA controller at driver shutdown */
- struct pci_dev *pcidev;
+ /* the corresponding pci_dev structure */
+ struct pci_dev *dev;
/* soundcore stuff */
int dev_audio;
@@ -175,6 +175,7 @@
struct dmabuf {
void *rawbuf;
+ dma_addr_t dmaaddr;
unsigned buforder;
unsigned numfrag;
unsigned fragshift;
@@ -210,7 +211,7 @@
/* --------------------------------------------------------------------- */
-struct solo1_state *devs = NULL;
+static LIST_HEAD(devs);
/* --------------------------------------------------------------------- */
@@ -396,7 +397,7 @@
#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
#define DMABUF_MINORDER 1
-extern inline void dealloc_dmabuf(struct dmabuf *db)
+extern inline void dealloc_dmabuf(struct solo1_state *s, struct dmabuf *db)
{
unsigned long map, mapend;
@@ -405,13 +406,13 @@
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;
}
-static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db, int gfp_mask)
+static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db, unsigned long dmamask)
{
int order;
unsigned bytespersec;
@@ -421,19 +422,12 @@
db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
if (!db->rawbuf) {
db->ready = db->mapped = 0;
+ s->dev->dma_mask = dmamask;
for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
- if ((db->rawbuf = (void *)__get_free_pages(gfp_mask, order)))
+ if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
break;
if (!db->rawbuf)
return -ENOMEM;
- /* work around a problem of the alpha port */
- if ((gfp_mask & GFP_DMA) && (virt_to_bus(db->rawbuf) & (~0xffffffUL))) {
- printk(KERN_ERR "solo1: requested DMA buffer below 16M but got 0x%lx, Alpha bug?\n",
- (unsigned long)virt_to_bus(db->rawbuf));
- kfree(db->rawbuf);
- db->rawbuf = NULL;
- return -ENOMEM;
- }
db->buforder = order;
/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
@@ -475,9 +469,9 @@
int c;
stop_adc(s);
- if ((c = prog_dmabuf(s, &s->dma_adc, GFP_KERNEL | GFP_DMA)))
+ if ((c = prog_dmabuf(s, &s->dma_adc, 0xffffff)))
return c;
- va = virt_to_bus(s->dma_adc.rawbuf);
+ va = s->dma_adc.dmaaddr;
if ((va & ~((1<<24)-1)))
panic("solo1: buffer above 16M boundary");
outb(0, s->ddmabase+0xd); /* clear */
@@ -500,10 +494,10 @@
int c;
stop_dac(s);
- if ((c = prog_dmabuf(s, &s->dma_dac, GFP_KERNEL)))
+ if ((c = prog_dmabuf(s, &s->dma_dac, 0xffffffff)))
return c;
memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80, s->dma_dac.dmasize); /* almost correct for U16 */
- va = virt_to_bus(s->dma_dac.rawbuf);
+ va = s->dma_dac.dmaaddr;
if ((va ^ (va + s->dma_dac.dmasize - 1)) & ~((1<<20)-1))
panic("solo1: buffer crosses 1M boundary");
outl(va, s->iobase);
@@ -900,12 +894,16 @@
static int solo1_open_mixdev(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
- struct solo1_state *s = devs;
+ struct list_head *list;
+ struct solo1_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 solo1_state, devs);
+ if (s->dev_mixer == minor)
+ break;
+ }
VALIDATE_STATE(s);
file->private_data = s;
MOD_INC_USE_COUNT;
@@ -915,7 +913,7 @@
static int solo1_release_mixdev(struct inode *inode, struct file *file)
{
struct solo1_state *s = (struct solo1_state *)file->private_data;
-
+
VALIDATE_STATE(s);
MOD_DEC_USE_COUNT;
return 0;
@@ -927,19 +925,10 @@
}
static /*const*/ struct file_operations solo1_mixer_fops = {
- &solo1_llseek,
- NULL, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- &solo1_ioctl_mixdev,
- NULL, /* mmap */
- &solo1_open_mixdev,
- NULL, /* flush */
- &solo1_release_mixdev,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
+ llseek: solo1_llseek,
+ ioctl: solo1_ioctl_mixdev,
+ open: solo1_open_mixdev,
+ release: solo1_release_mixdev,
};
/* --------------------------------------------------------------------- */
@@ -1522,13 +1511,13 @@
if (file->f_mode & FMODE_WRITE) {
stop_dac(s);
outb(0, s->iobase+6); /* disable DMA */
- dealloc_dmabuf(&s->dma_dac);
+ dealloc_dmabuf(s, &s->dma_dac);
}
if (file->f_mode & FMODE_READ) {
stop_adc(s);
outb(1, s->ddmabase+0xf); /* mask DMA channel */
outb(0, s->ddmabase+0xd); /* DMA master clear */
- dealloc_dmabuf(&s->dma_adc);
+ dealloc_dmabuf(s, &s->dma_adc);
}
s->open_mode &= ~(FMODE_READ | FMODE_WRITE);
wake_up(&s->open_wait);
@@ -1541,12 +1530,16 @@
{
int minor = MINOR(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
- struct solo1_state *s = devs;
-
- while (s && ((s->dev_audio ^ minor) & ~0xf))
- s = s->next;
- if (!s)
- return -ENODEV;
+ struct list_head *list;
+ struct solo1_state *s;
+
+ for (list = devs.next; ; list = list->next) {
+ if (list == &devs)
+ return -ENODEV;
+ s = list_entry(list, struct solo1_state, devs);
+ if (!((s->dev_audio ^ minor) & ~0xf))
+ break;
+ }
VALIDATE_STATE(s);
file->private_data = s;
/* wait for device to become free */
@@ -1581,19 +1574,14 @@
}
static /*const*/ struct file_operations solo1_audio_fops = {
- &solo1_llseek,
- &solo1_read,
- &solo1_write,
- NULL, /* readdir */
- &solo1_poll,
- &solo1_ioctl,
- &solo1_mmap,
- &solo1_open,
- NULL, /* flush */
- &solo1_release,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
+ llseek: solo1_llseek,
+ read: solo1_read,
+ write: solo1_write,
+ poll: solo1_poll,
+ ioctl: solo1_ioctl,
+ mmap: solo1_mmap,
+ open: solo1_open,
+ release: solo1_release,
};
/* --------------------------------------------------------------------- */
@@ -1821,13 +1809,17 @@
{
int minor = MINOR(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
- struct solo1_state *s = devs;
unsigned long flags;
+ struct list_head *list;
+ struct solo1_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 solo1_state, devs);
+ if (s->dev_midi == minor)
+ break;
+ }
VALIDATE_STATE(s);
file->private_data = s;
/* wait for device to become free */
@@ -1923,19 +1915,12 @@
}
static /*const*/ struct file_operations solo1_midi_fops = {
- &solo1_llseek,
- &solo1_midi_read,
- &solo1_midi_write,
- NULL, /* readdir */
- &solo1_midi_poll,
- NULL, /* ioctl */
- NULL, /* mmap */
- &solo1_midi_open,
- NULL, /* flush */
- &solo1_midi_release,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
+ llseek: solo1_llseek,
+ read: solo1_midi_read,
+ write: solo1_midi_write,
+ poll: solo1_midi_poll,
+ open: solo1_midi_open,
+ release: solo1_midi_release,
};
/* --------------------------------------------------------------------- */
@@ -2041,12 +2026,16 @@
{
int minor = MINOR(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
- struct solo1_state *s = devs;
+ struct list_head *list;
+ struct solo1_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 solo1_state, devs);
+ if (s->dev_dmfm == minor)
+ break;
+ }
VALIDATE_STATE(s);
file->private_data = s;
/* wait for device to become free */
@@ -2107,28 +2096,14 @@
}
static /*const*/ struct file_operations solo1_dmfm_fops = {
- &solo1_llseek,
- NULL, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- &solo1_dmfm_ioctl,
- NULL, /* mmap */
- &solo1_dmfm_open,
- NULL, /* flush */
- &solo1_dmfm_release,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
+ llseek: solo1_llseek,
+ ioctl: solo1_dmfm_ioctl,
+ open: solo1_dmfm_open,
+ release: solo1_dmfm_release,
};
/* --------------------------------------------------------------------- */
-/* maximum number of devices */
-#define NR_DEVICE 5
-
-/* --------------------------------------------------------------------- */
-
static struct initvol {
int mixch;
int vol;
@@ -2147,7 +2122,7 @@
static int setup_solo1(struct solo1_state *s)
{
- struct pci_dev *pcidev = s->pcidev;
+ struct pci_dev *pcidev = s->dev;
mm_segment_t fs;
int i, val;
@@ -2187,141 +2162,185 @@
return 0;
}
-#ifdef CONFIG_APM
-
-static int solo1_apm_callback(apm_event_t event)
+static int solo1_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
{
- struct solo1_state *s;
-
- switch(event) {
- case APM_NORMAL_RESUME:
- case APM_CRITICAL_RESUME:
- case APM_STANDBY_RESUME:
- for(s = devs ; s ; s = s->next)
+ struct solo1_state *s = (struct solo1_state*) dev->data;
+ if (s) {
+ switch(rqst) {
+ case PM_RESUME:
setup_solo1(s);
- break;
+ break;
- default:
- for(s = devs ; s ; s = s->next) {
- outb(0, s->iobase+6);
- /* DMA master clear */
- outb(0, s->ddmabase+0xd);
- /* reset sequencer and FIFO */
- outb(3, s->sbbase+6);
- /* turn off DDMA controller address space */
- pci_write_config_word(s->pcidev, 0x60, 0);
- }
+ case PM_SUSPEND:
+ outb(0, s->iobase+6);
+ /* DMA master clear */
+ outb(0, s->ddmabase+0xd);
+ /* reset sequencer and FIFO */
+ outb(3, s->sbbase+6);
+ /* turn off DDMA controller address space */
+ pci_write_config_word(s->dev, 0x60, 0);
+ break;
+ }
}
return 0;
}
-#endif
-
#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
((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_solo1(void)
+static int solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{
struct solo1_state *s;
- struct pci_dev *pcidev = NULL;
- int index = 0;
+ struct pm_dev *pmdev;
- if (!pci_present()) /* No PCI bus in this machine! */
- return -ENODEV;
- printk(KERN_INFO "solo1: version v0.12 time " __TIME__ " " __DATE__ "\n");
- while (index < NR_DEVICE &&
- (pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
- if (!RSRCISIOREGION(pcidev, 0) ||
- !RSRCISIOREGION(pcidev, 1) ||
- !RSRCISIOREGION(pcidev, 2) ||
- !RSRCISIOREGION(pcidev, 3))
- continue;
- if (pcidev->irq == 0)
- continue;
- if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) {
- printk(KERN_WARNING "solo1: out of memory\n");
- continue;
- }
- memset(s, 0, sizeof(struct solo1_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 = SOLO1_MAGIC;
- s->pcidev = pcidev;
- s->iobase = RSRCADDRESS(pcidev, 0);
- s->sbbase = RSRCADDRESS(pcidev, 1);
- s->vcbase = RSRCADDRESS(pcidev, 2);
- s->ddmabase = s->vcbase + DDMABASE_OFFSET;
- s->mpubase = RSRCADDRESS(pcidev, 3);
- s->gpbase = RSRCADDRESS(pcidev, 4);
- s->irq = pcidev->irq;
- if (check_region(s->iobase, IOBASE_EXTENT) ||
- check_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT) ||
- check_region(s->ddmabase, DDMABASE_EXTENT) ||
- check_region(s->mpubase, MPUBASE_EXTENT)) {
- printk(KERN_ERR "solo1: io ports in use\n");
- goto err_region;
- }
- request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1");
- request_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT, "ESS Solo1");
- request_region(s->ddmabase, DDMABASE_EXTENT, "ESS Solo1");
- request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1");
- if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) {
- printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
- goto err_irq;
- }
- printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase);
-
- printk(KERN_INFO "solo1: joystick port at %#lx\n", s->gpbase+1);
-
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0)
- goto err_dev1;
- if ((s->dev_mixer = register_sound_mixer(&solo1_mixer_fops, -1)) < 0)
- goto err_dev2;
- if ((s->dev_midi = register_sound_midi(&solo1_midi_fops, -1)) < 0)
- goto err_dev3;
- if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0)
- goto err_dev4;
- if (setup_solo1(s))
- goto err;
- /* queue it for later freeing */
- s->next = devs;
- devs = s;
- index++;
- continue;
-
- err:
- unregister_sound_dsp(s->dev_dmfm);
- err_dev4:
- unregister_sound_dsp(s->dev_midi);
- err_dev3:
- unregister_sound_mixer(s->dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- printk(KERN_ERR "solo1: initialisation error\n");
- free_irq(s->irq, s);
- err_irq:
- release_region(s->iobase, IOBASE_EXTENT);
- release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
- release_region(s->ddmabase, DDMABASE_EXTENT);
- release_region(s->mpubase, MPUBASE_EXTENT);
- err_region:
- kfree_s(s, sizeof(struct solo1_state));
+ if (!RSRCISIOREGION(pcidev, 0) ||
+ !RSRCISIOREGION(pcidev, 1) ||
+ !RSRCISIOREGION(pcidev, 2) ||
+ !RSRCISIOREGION(pcidev, 3))
+ return -1;
+ if (pcidev->irq == 0)
+ return -1;
+ if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) {
+ printk(KERN_WARNING "solo1: out of memory\n");
+ return -1;
}
- if (!devs)
+ memset(s, 0, sizeof(struct solo1_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 = SOLO1_MAGIC;
+ s->dev = pcidev;
+ s->iobase = RSRCADDRESS(pcidev, 0);
+ s->sbbase = RSRCADDRESS(pcidev, 1);
+ s->vcbase = RSRCADDRESS(pcidev, 2);
+ s->ddmabase = s->vcbase + DDMABASE_OFFSET;
+ s->mpubase = RSRCADDRESS(pcidev, 3);
+ s->gpbase = RSRCADDRESS(pcidev, 4);
+ s->irq = pcidev->irq;
+ if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) {
+ printk(KERN_ERR "solo1: io ports in use\n");
+ goto err_region1;
+ }
+ if (!request_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT, "ESS Solo1")) {
+ printk(KERN_ERR "solo1: io ports in use\n");
+ goto err_region2;
+ }
+ if (!request_region(s->ddmabase, DDMABASE_EXTENT, "ESS Solo1")) {
+ printk(KERN_ERR "solo1: io ports in use\n");
+ goto err_region3;
+ }
+ if (!request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1")) {
+ printk(KERN_ERR "solo1: io ports in use\n");
+ goto err_region4;
+ }
+ if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) {
+ printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
+ goto err_irq;
+ }
+ pci_enable_device(pcidev);
+ printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase);
+ printk(KERN_INFO "solo1: joystick port at %#lx\n", s->gpbase+1);
+ /* register devices */
+ if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0)
+ goto err_dev1;
+ if ((s->dev_mixer = register_sound_mixer(&solo1_mixer_fops, -1)) < 0)
+ goto err_dev2;
+ if ((s->dev_midi = register_sound_midi(&solo1_midi_fops, -1)) < 0)
+ goto err_dev3;
+ if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0)
+ goto err_dev4;
+ if (setup_solo1(s))
+ goto err;
+ /* store it in the driver field */
+ pcidev->driver_data = s;
+ pcidev->dma_mask = 0xffffff; /* pessimistic; play can handle 32bit addrs */
+ /* put it into driver list */
+ list_add_tail(&s->devs, &devs);
+
+ pmdev = pm_register(PM_PCI_DEV, PM_PCI_ID(pcidev), solo1_pm_callback);
+ if (pmdev)
+ pmdev->data = s;
+
+ return 0;
+
+ err:
+ unregister_sound_dsp(s->dev_dmfm);
+ err_dev4:
+ unregister_sound_dsp(s->dev_midi);
+ err_dev3:
+ unregister_sound_mixer(s->dev_mixer);
+ err_dev2:
+ unregister_sound_dsp(s->dev_audio);
+ err_dev1:
+ printk(KERN_ERR "solo1: initialisation error\n");
+ free_irq(s->irq, s);
+ err_irq:
+ release_region(s->iobase, IOBASE_EXTENT);
+ err_region4:
+ release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
+ err_region3:
+ release_region(s->ddmabase, DDMABASE_EXTENT);
+ err_region2:
+ release_region(s->mpubase, MPUBASE_EXTENT);
+ err_region1:
+ kfree_s(s, sizeof(struct solo1_state));
+ return -1;
+}
+
+static void solo1_remove(struct pci_dev *dev)
+{
+ struct solo1_state *s = (struct solo1_state *)dev->driver_data;
+
+ if (!s)
+ return;
+ list_del(&s->devs);
+ /* stop DMA controller */
+ outb(0, s->iobase+6);
+ outb(0, s->ddmabase+0xd); /* DMA master clear */
+ outb(3, s->sbbase+6); /* reset sequencer and FIFO */
+ synchronize_irq();
+ pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */
+ free_irq(s->irq, s);
+ release_region(s->iobase, IOBASE_EXTENT);
+ release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
+ release_region(s->ddmabase, DDMABASE_EXTENT);
+ release_region(s->mpubase, MPUBASE_EXTENT);
+ 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 solo1_state));
+ dev->driver_data = NULL;
+}
+
+static const struct pci_device_id id_table[] = {
+ { PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+ { 0, 0, 0, 0, 0, 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, id_table);
+
+static struct pci_driver solo1_driver = {
+ name: "ESS Solo1",
+ id_table: id_table,
+ probe: solo1_probe,
+ remove: solo1_remove
+};
+
+
+static int __init init_solo1(void)
+{
+ if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
-#ifdef CONFIG_APM
- apm_register_callback(solo1_apm_callback);
-#endif
+ printk(KERN_INFO "solo1: version v0.13 time " __TIME__ " " __DATE__ "\n");
+ if (!pci_register_driver(&solo1_driver))
+ return -ENODEV;
return 0;
}
@@ -2332,31 +2351,9 @@
static void __exit cleanup_solo1(void)
{
- struct solo1_state *s;
-
- while ((s = devs)) {
- devs = devs->next;
- /* stop DMA controller */
- outb(0, s->iobase+6);
- outb(0, s->ddmabase+0xd); /* DMA master clear */
- outb(3, s->sbbase+6); /* reset sequencer and FIFO */
- synchronize_irq();
- pci_write_config_word(s->pcidev, 0x60, 0); /* turn off DDMA controller address space */
- free_irq(s->irq, s);
- release_region(s->iobase, IOBASE_EXTENT);
- release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
- release_region(s->ddmabase, DDMABASE_EXTENT);
- release_region(s->mpubase, MPUBASE_EXTENT);
- 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 solo1_state));
- }
-#ifdef CONFIG_APM
- apm_unregister_callback(solo1_apm_callback);
-#endif
printk(KERN_INFO "solo1: unloading\n");
+ pci_unregister_driver(&solo1_driver);
+ pm_unregister_all(solo1_pm_callback);
}
/* --------------------------------------------------------------------- */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)