public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Christoph Hellwig <hch@ns.caldera.de>
To: adam@yggdrasil.com ("Adam J. Richter")
Cc: linux-kernel@vger.kernel.org
Subject: Re: sound and scsi pci MODULE_DEVICE_TABLE entries? (primary for Alan Cox)
Date: Sat, 18 Nov 2000 19:07:43 +0100	[thread overview]
Message-ID: <200011181807.TAA27511@ns.caldera.de> (raw)
In-Reply-To: <200011180601.WAA01562@adam.yggdrasil.com>

In article <200011180601.WAA01562@adam.yggdrasil.com> you wrote:


>         Jeff Garzik tells me that you, with some help from some other
> kernel developers, are hacking on the sound drivers right now.  I
> would like to add PCI MODULE_DEVICE_TABLE entries to three of
> the four PCI sound drivers: cmpci, cs46xx and nm256_audio.

I have a patch for cs46xx that does not only add MODULE_DEVICE_TABLE,
but does also adapt it to the 2.4 PCI interface and forward-ports
bug-fixes and other changes from 2.2.  If someone could _please_ test
it, I would like to send it to Linux. (there are people that have cs46xx
problems ..)

	Christoph

-- 
Always remember that you are unique.  Just like everyone else.


diff -uNr linux-2.4.0-test11-pre7/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c
--- linux-2.4.0-test11-pre7/drivers/sound/cs46xx.c	Sat Nov 18 13:10:19 2000
+++ linux/drivers/sound/cs46xx.c	Sat Nov 18 13:34:28 2000
@@ -25,9 +25,17 @@
  * Changes:
  *	20000815	Updated driver to kernel 2.4, some cleanups/fixes
  *			Nils Faerber <nils@kernelconcepts.de>
+ *
+ *	20000909	Changed cs_read, cs_write and drain_dac
+ *			Nils Faerber <nils@kernelconcepts.de>
+ *
  *	20001110	Added __initdata to BA1Struct in cs461x_image.h
  *			and three more __init here
  *			Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
+ *
+ *	20001023	Ported to Linux 2.4 PCI interface, some cleanups
+ *			Christoph Hellwig <hch@caldera.de>
+ *
  */
  
 #include <linux/module.h>
@@ -72,18 +80,11 @@
 
 #define GOF_PER_SEC	200
 
-/*
- * Define this to enable recording,
- * this is curently broken and using it will cause data corruption
- * in kernel- and user-space!
- */
-/* #define CS46XX_ENABLE_RECORD */
-
 static int external_amp = 0;
 static int thinkpad = 0;
 
 
-/* an instance of the 4610 channel */
+/* An instance of the 4610 channel */
 
 struct cs_channel 
 {
@@ -92,7 +93,7 @@
 	void *state;
 };
 
-#define DRIVER_VERSION "0.09"
+#define DRIVER_VERSION "0.14"
 
 /* magic numbers to protect our data structures */
 #define CS_CARD_MAGIC		0x46524F4D /* "FROM" */
@@ -169,7 +170,7 @@
 	unsigned int magic;
 
 	/* We keep cs461x cards in a linked list */
-	struct cs_card *next;
+	struct list_head devs;
 
 	/* The cs461x has a certain amount of cross channel interaction
 	   so we use a single per card lock */
@@ -220,7 +221,7 @@
 	void (*free_pcm_channel)(struct cs_card *, int chan);
 };
 
-static struct cs_card *devs = NULL;
+static LIST_HEAD(devs);
 
 static int cs_open_mixdev(struct inode *inode, struct file *file);
 static int cs_release_mixdev(struct inode *inode, struct file *file);
@@ -787,7 +788,7 @@
 
 		tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
 		tmo >>= sample_shift[dmabuf->fmt];
-		tmo += (4096*HZ)/dmabuf->rate;
+		tmo += (2048*HZ)/dmabuf->rate;
 
 		if (!schedule_timeout(tmo ? tmo : 1) && tmo){
 			printk(KERN_ERR "cs461x: drain_dac, dma timeout? %d\n", count);
@@ -844,8 +845,9 @@
 					memset (dmabuf->rawbuf + swptr, silence, clear_cnt);
 					dmabuf->endcleared = 1;
 				}
-			}			
-			wake_up(&dmabuf->wait);
+			}
+			if (dmabuf->count < (signed)dmabuf->dmasize/2)
+				wake_up(&dmabuf->wait);
 		}
 	}
 	/* error handling and process wake up for DAC */
@@ -864,7 +866,8 @@
 				__stop_dac(state);
 				dmabuf->error++;
 			}
-			wake_up(&dmabuf->wait);
+			if (dmabuf->count < (signed)dmabuf->dmasize/2)
+				wake_up(&dmabuf->wait);
 		}
 	}
 }
@@ -874,7 +877,7 @@
 	memcpy(state->dmabuf.rawbuf + (2048*state->dmabuf.pringbuf++),
 		state->dmabuf.pbuf+2048*state->dmabuf.ppingbuf++, 2048);
 	state->dmabuf.ppingbuf&=1;
-	if(state->dmabuf.pringbuf > (PAGE_SIZE<<state->dmabuf.buforder)/2048)
+	if(state->dmabuf.pringbuf >= (PAGE_SIZE<<state->dmabuf.buforder)/2048)
 		state->dmabuf.pringbuf=0;
 	cs_update_ptr(state);
 }
@@ -929,6 +932,7 @@
 {
 	struct cs_state *state = (struct cs_state *)file->private_data;
 	struct dmabuf *dmabuf = &state->dmabuf;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	unsigned long flags;
 	unsigned swptr;
@@ -948,6 +952,7 @@
 		return -EFAULT;
 	ret = 0;
 
+	add_wait_queue(&state->dmabuf.wait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&state->card->lock, flags);
 		if (dmabuf->count > (signed) dmabuf->dmasize) {
@@ -960,49 +965,34 @@
 		cnt = dmabuf->dmasize - swptr;
 		if (dmabuf->count < cnt)
 			cnt = dmabuf->count;
+		if (cnt <= 0)
+			__set_current_state(TASK_INTERRUPTIBLE);
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			unsigned long tmo;
 			/* buffer is empty, start the dma machine and wait for data to be
 			   recorded */
 			start_adc(state);
 			if (file->f_flags & O_NONBLOCK) {
-				if (!ret) ret = -EAGAIN;
-				return ret;
-			}
-			/* This isnt strictly right for the 810  but it'll do */
-			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
-			tmo >>= sample_shift[dmabuf->fmt];
-			/* There are two situations when sleep_on_timeout returns, one is when
-			   the interrupt is serviced correctly and the process is waked up by
-			   ISR ON TIME. Another is when timeout is expired, which means that
-			   either interrupt is NOT serviced correctly (pending interrupt) or it
-			   is TOO LATE for the process to be scheduled to run (scheduler latency)
-			   which results in a (potential) buffer overrun. And worse, there is
-			   NOTHING we can do to prevent it. */
-			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
-#ifdef DEBUG
-				printk(KERN_ERR "cs461x: recording schedule timeout, "
-				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
-				       dmabuf->hwptr, dmabuf->swptr);
-#endif
-				/* a buffer overrun, we delay the recovery untill next time the
-				   while loop begin and we REALLY have space to record */
+				if (!ret)
+					ret = -EAGAIN;
+				remove_wait_queue(&state->dmabuf.wait, &wait);
+				break;
 			}
+			schedule();
 			if (signal_pending(current)) {
 				ret = ret ? ret : -ERESTARTSYS;
-				return ret;
+				break;
 			}
 			continue;
 		}
 
 		if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
-			if (!ret) ret = -EFAULT;
-			return ret;
+			if (!ret)
+				ret = -EFAULT;
+			break;
 		}
 
 		swptr = (swptr + cnt) % dmabuf->dmasize;
@@ -1017,6 +1007,8 @@
 		ret += cnt;
 		start_adc(state);
 	}
+	remove_wait_queue(&state->dmabuf.wait, &wait);
+	set_current_state(TASK_RUNNING);
 	return ret;
 }
 
@@ -1026,7 +1018,8 @@
 {
 	struct cs_state *state = (struct cs_state *)file->private_data;
 	struct dmabuf *dmabuf = &state->dmabuf;
-	ssize_t ret;
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t ret = 0;
 	unsigned long flags;
 	unsigned swptr;
 	int cnt;
@@ -1043,8 +1036,8 @@
 		return ret;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
-	ret = 0;
 
+	add_wait_queue(&state->dmabuf.wait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&state->card->lock, flags);
 		if (dmabuf->count < 0) {
@@ -1057,48 +1050,34 @@
 		cnt = dmabuf->dmasize - swptr;
 		if (dmabuf->count + cnt > dmabuf->dmasize)
 			cnt = dmabuf->dmasize - dmabuf->count;
+		if (cnt <= 0)
+			__set_current_state(TASK_INTERRUPTIBLE);
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			unsigned long tmo;
 			/* buffer is full, start the dma machine and wait for data to be
 			   played */
 			start_dac(state);
 			if (file->f_flags & O_NONBLOCK) {
-				if (!ret) ret = -EAGAIN;
-				return ret;
-			}
-			/* Not strictly correct but works */
-			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
-			tmo >>= sample_shift[dmabuf->fmt];
-			/* There are two situations when sleep_on_timeout returns, one is when
-			   the interrupt is serviced correctly and the process is waked up by
-			   ISR ON TIME. Another is when timeout is expired, which means that
-			   either interrupt is NOT serviced correctly (pending interrupt) or it
-			   is TOO LATE for the process to be scheduled to run (scheduler latency)
-			   which results in a (potential) buffer underrun. And worse, there is
-			   NOTHING we can do to prevent it. */
-			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
-#ifdef DEBUG
-				printk(KERN_ERR "cs461x: playback schedule timeout, "
-				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
-				       dmabuf->hwptr, dmabuf->swptr);
-#endif
-				/* a buffer underrun, we delay the recovery untill next time the
-				   while loop begin and we REALLY have data to play */
+				if (!ret)
+					ret = -EAGAIN;
+				remove_wait_queue(&state->dmabuf.wait, &wait);
+				break;
 			}
+			schedule();
 			if (signal_pending(current)) {
-				if (!ret) ret = -ERESTARTSYS;
-				return ret;
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
 			}
 			continue;
 		}
 		if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
-			if (!ret) ret = -EFAULT;
-			return ret;
+			if (!ret)
+				ret = -EFAULT;
+			break;
 		}
 
 		swptr = (swptr + cnt) % dmabuf->dmasize;
@@ -1149,10 +1128,17 @@
 	return mask;
 }
 
+
+/*
+ * We let users mmap the ring buffer. Its not the real DMA buffer but
+ * that side of the code is hidden in the IRQ handling. We do a software
+ * emulation of DMA from a 64K or so buffer into a 2K FIFO.
+ * (the hardware probably deserves a moan here but Crystal send me nice
+ * toys ;)).
+ */
+
 static int cs_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	return -EINVAL;
-#if 0	
 	struct cs_state *state = (struct cs_state *)file->private_data;
 	struct dmabuf *dmabuf = &state->dmabuf;
 	int ret;
@@ -1168,7 +1154,7 @@
 	} else 
 		return -EINVAL;
 
-	if (vma->vm_offset != 0)
+	if (vma->vm_pgoff != 0)
 		return -EINVAL;
 	size = vma->vm_end - vma->vm_start;
 	if (size > (PAGE_SIZE << dmabuf->buforder))
@@ -1179,7 +1165,6 @@
 	dmabuf->mapped = 1;
 
 	return 0;
-#endif	
 }
 
 static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
@@ -1503,7 +1488,7 @@
 
 static void amp_voyetra(struct cs_card *card, int change)
 {
-	/* Manage the EAPD bit on the Crystal 4297 */
+	/* Manage the EAPD bit on the Crystal 4297 and the Analog AD1885 */
 	int old=card->amplifier;
 
 	card->amplifier+=change;
@@ -1524,7 +1509,6 @@
 }
 
 
-
 /*
  *	Untested
  */
@@ -1532,7 +1516,6 @@
 static void amp_voyetra_4294(struct cs_card *card, int change)
 {
 	struct ac97_codec *c=card->ac97_codec[0];
-	int old = card->amplifier;
 
 	card->amplifier+=change;
 
@@ -1593,17 +1576,20 @@
 static int cs_open(struct inode *inode, struct file *file)
 {
 	int i = 0;
-	struct cs_card *card = devs;
+	struct cs_card *card;
 	struct cs_state *state = NULL;
 	struct dmabuf *dmabuf = NULL;
+	struct list_head *list;
 
 #ifndef CS46XX_ENABLE_RECORD
 	if (file->f_mode & FMODE_READ)
 		return -ENODEV;
 #endif
 
-	/* find an avaiable virtual channel (instance of /dev/dsp) */
-	while (card != NULL) {
+	for (list = devs.next; ; list = list->next) {
+		if (list == &devs)
+			return -ENODEV;
+		card = list_entry(list, struct cs_card, devs);
 		for (i = 0; i < NR_HW_CH; i++) {
 			if (card->states[i] == NULL) {
 				state = card->states[i] = (struct cs_state *)
@@ -1622,7 +1608,6 @@
 				goto found_virt;
 			}
 		}
-		card = card->next;
 	}
 	/* no more virtual channel avaiable */
 	if (!state)
@@ -1841,7 +1826,11 @@
 {
 	struct cs_card *card = dev->private_data;
 	int count;
+	int val2;
 	
+	if (reg == AC97_CD_VOL)
+		val2 = cs_ac97_get(dev, AC97_CD_VOL);
+
 	/*
 	 *  1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
 	 *  2. Write ACCDA = Command Data Register = 470h    for data to write to AC97
@@ -1883,6 +1872,44 @@
 	 */
 	if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV)
 		printk(KERN_WARNING "cs461x: AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val);
+
+	/*
+	 *	Adjust power if the mixer is selected/deselected according
+	 *	to the CD.
+	 *
+	 *	IF the CD is a valid input source (mixer or direct) AND
+	 *		the CD is not muted THEN power is needed
+	 *
+	 *	We do two things. When record select changes the input to
+	 *	add/remove the CD we adjust the power count if the CD is
+	 *	unmuted.
+	 *
+	 *	When the CD mute changes we adjust the power level if the
+	 *	CD was a valid input.
+	 *
+	 *	We also check for CD volume != 0, as the CD mute isn't
+	 *	normally tweaked from userspace.
+	 */
+
+	/* CD mute change ? */
+	if (reg == AC97_CD_VOL) {
+		/* Mute bit change ? */
+		if ((val2^val) & 0x8000 || ((val2 == 0x1f1f || val == 0x1f1f) && val2 != val)) {
+			/* This is a hack but its cleaner than the alternatives.
+			   Right now card->ac97_codec[0] might be NULL as we are
+			   still doing codec setup. This does an early assignment
+			   to avoid the problem if it occurs */
+
+			if (card->ac97_codec[0] == NULL)
+				card->ac97_codec[0] = dev;
+
+			/* Mute on */
+			if(val & 0x8000 || val == 0x1f1f)
+				card->amplifier_ctrl(card, -1);
+			else /* Mute off power on */
+				card->amplifier_ctrl(card, 1);
+		}
+	}
 }
 
 
@@ -1892,13 +1919,19 @@
 {
 	int i;
 	int minor = MINOR(inode->i_rdev);
-	struct cs_card *card = devs;
+	struct cs_card *card;
+	struct list_head *list;
 
-	for (card = devs; card != NULL; card = card->next)
+	for (list = devs.next; ; list = list->next) {
+		if (list == &devs)
+			return -ENODEV;
+		card = list_entry(list, struct cs_card, devs);
 		for (i = 0; i < NR_AC97; i++)
 			if (card->ac97_codec[i] != NULL &&
 			    card->ac97_codec[i]->dev_mixer == minor)
 				goto match;
+	}
+
 
 	if (!card)
 		return -ENODEV;
@@ -1907,28 +1940,31 @@
 	file->private_data = card->ac97_codec[i];
 
 	card->active_ctrl(card,1);
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static int cs_release_mixdev(struct inode *inode, struct file *file)
 {
 	int minor = MINOR(inode->i_rdev);
-	struct cs_card *card = devs;
+	struct cs_card *card;
+	struct list_head *list;
 	int i;
-
-	for (card = devs; card != NULL; card = card->next)
+	
+	for (list = devs.next; ; list = list->next) {
+		if (list == &devs)
+			return -ENODEV;
+		card = list_entry(list, struct cs_card, devs);
 		for (i = 0; i < NR_AC97; i++)
 			if (card->ac97_codec[i] != NULL &&
 			    card->ac97_codec[i]->dev_mixer == minor)
 				goto match;
+	}
 
 	if (!card)
 		return -ENODEV;
 match:
 	card->active_ctrl(card, -1);
 
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -2269,7 +2305,7 @@
          *  for a reset.
          */
         cs461x_pokeBA0(card, BA0_ACCTL, 0);
-        udelay(500);
+        udelay(50);
         cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_RSTN);
 
 	/*
@@ -2284,7 +2320,7 @@
 	 *  generating bit clock (so we don't try to start the PLL without an
 	 *  input clock).
 	 */
-	mdelay(10);		/* 1 should be enough ?? */
+	mdelay(5);		/* 1 should be enough ?? */
 
 	/*
 	 *  Set the serial port timing configuration, so that
@@ -2309,7 +2345,7 @@
 	/*
          *  Wait until the PLL has stabilized.
 	 */
-	mdelay(100);		/* Again 1 should be enough ?? */
+	mdelay(5);		/* Again 1 should be enough ?? */
 
 	/*
 	 *  Turn on clocking of the core so that we can setup the serial ports.
@@ -2472,8 +2508,7 @@
  *	Card subid table
  */
 
-struct cs_card_type
-{
+struct cs_card_type {
 	u16 vendor;
 	u16 id;
 	char *name;
@@ -2481,7 +2516,7 @@
 	void (*active)(struct cs_card *, int);
 };
 
-static struct cs_card_type __initdata cards[]={
+static struct cs_card_type __devinitdata cards[]={
 	{0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL},
 	{0x5053, 0x3357, "Voyetra", amp_voyetra, NULL},
 	/* MI6020/21 use the same chipset as the Thinkpads, maybe needed */
@@ -2490,18 +2525,14 @@
 	{PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", amp_none, clkrun_hack},
 	{PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", amp_none, clkrun_hack},
 	{PCI_VENDOR_ID_IBM, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL},
+	{0, 0, "Card without SSID set", NULL, NULL },
 	{0, 0, NULL, NULL, NULL}
 };
 
-static int __init cs_install(struct pci_dev *pci_dev)
+static int __devinit cs_probe(struct pci_dev * pci_dev, const struct pci_device_id * id)
 {
 	struct cs_card *card;
 	struct cs_card_type *cp = &cards[0];
-	u16 ss_card, ss_vendor;
-
-
-	pci_read_config_word(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor);
-	pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &ss_card);
 
 	if ((card = kmalloc(sizeof(struct cs_card), GFP_KERNEL)) == NULL) {
 		printk(KERN_ERR "cs461x: out of memory\n");
@@ -2509,8 +2540,8 @@
 	}
 	memset(card, 0, sizeof(*card));
 
-	card->ba0_addr = pci_dev->resource[0].start&PCI_BASE_ADDRESS_MEM_MASK;
-	card->ba1_addr = pci_dev->resource[1].start&PCI_BASE_ADDRESS_MEM_MASK;
+	card->ba0_addr = pci_resource_start(pci_dev, 0);
+	card->ba1_addr = pci_resource_start(pci_dev, 1);
 	card->pci_dev = pci_dev;
 	card->irq = pci_dev->irq;
 	card->magic = CS_CARD_MAGIC;
@@ -2529,7 +2560,7 @@
 
 	while(cp->name)
 	{
-		if(cp->vendor == ss_vendor && cp->id == ss_card)
+		if(cp->vendor == id->subvendor && cp->id == id->subdevice)
 		{
 			card->amplifier_ctrl = cp->amp;
 			if(cp->active)
@@ -2541,7 +2572,7 @@
 	if(cp->name==NULL)
 	{
 	printk(KERN_INFO "cs461x: Unknown card (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n",
-		ss_vendor, ss_card, card->ba0_addr, card->ba1_addr,  card->irq);
+		id->subvendor, id->subdevice, card->ba0_addr, card->ba1_addr,  card->irq);
 	}
 	else
 	{
@@ -2598,9 +2629,11 @@
 		unregister_sound_dsp(card->dev_audio);
 		goto fail;
 	}
-	card->next = devs;
-	devs = card;
-	
+
+	pci_set_drvdata (pci_dev, card);
+
+	list_add_tail(&card->devs, &devs);
+
 	card->active_ctrl(card, -1);
 	return 0;
 	
@@ -2622,11 +2655,13 @@
 
 }
 
-static void cs_remove(struct cs_card *card)
+static void __devexit cs_remove(struct pci_dev * pci_dev)
 {
+	struct cs_card * card = pci_get_drvdata (pci_dev);
 	int i;
 	unsigned int tmp;
-	
+
+	list_del(&card->devs);
 	card->active_ctrl(card,1);
 
 	tmp = cs461x_peek(card, BA1_PFIE);
@@ -2698,57 +2733,38 @@
 
 MODULE_AUTHOR("Alan Cox <alan@redhat.com>, Jaroslav Kysela");
 MODULE_DESCRIPTION("Crystal SoundFusion Audio Support");
+MODULE_PARM(external_amp, "i");
+MODULE_PARM(thinkpad, "i");
+
+static struct pci_device_id cs_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_CIRRUS, 0x6004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE (pci, cs_pci_tbl);
 
-int __init cs_probe(void)
+static struct pci_driver cs_pci_driver = {
+	name:		"cs46xx",
+	id_table:	cs_pci_tbl,
+	probe:		cs_probe,
+	remove:		cs_remove,
+};
+
+static int __init cs_init(void)
 {
-	struct pci_dev *pcidev = NULL;
 	int foundone=0;
 	
-	if (!pci_present())   /* No PCI bus in this machine! */
-		return -ENODEV;
-		
 	printk(KERN_INFO "Crystal 4280/461x + AC97 Audio, version "
 	       DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
 
-	while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6001 , pcidev))!=NULL ) {
-		if (cs_install(pcidev)==0)
-			foundone++;
-	}
-	while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6003 , pcidev))!=NULL ) {
-		if (cs_install(pcidev)==0)
-			foundone++;
-	}
-	while( (pcidev = pci_find_device(PCI_VENDOR_ID_CIRRUS, 0x6004 , pcidev))!=NULL ) {
-		if (cs_install(pcidev)==0)
-			foundone++;
-	}
-
-	printk(KERN_INFO "cs461x: Found %d audio device(s).\n",
-		foundone);
-	return foundone;
+	return pci_module_init(&cs_pci_driver);
 }
 
-#ifdef MODULE
-
-int init_module(void)
+static void __exit cs_exit(void)
 {
-	if(cs_probe()==0)
-		printk(KERN_ERR "cs461x: No devices found.\n");
-	return 0;
+	pci_unregister_driver(&cs_pci_driver);
 }
 
-void cleanup_module (void)
-{
-	struct cs_card *next;
-	while(devs)
-	{
-		next=devs->next;
-		cs_remove(devs);
-		devs=next;
-	}
-}
-
-MODULE_PARM(external_amp, "i");
-MODULE_PARM(thinkpad, "i");
-
-#endif
+module_init(cs_init);
+module_exit(cs_exit);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/

      parent reply	other threads:[~2000-11-18 18:38 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2000-11-18  6:01 sound and scsi pci MODULE_DEVICE_TABLE entries? (primary for Alan Cox) Adam J. Richter
2000-11-18  6:17 ` Jeff Garzik
2000-11-18 18:07 ` Christoph Hellwig [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200011181807.TAA27511@ns.caldera.de \
    --to=hch@ns.caldera.de \
    --cc=adam@yggdrasil.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox