blob: f56f870b48400e844a52d3547566fbefbb59ccf9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright 2001-2004 Randolph Chung <tausq@debian.org>
3 *
4 * Analog Devices 1889 PCI audio driver (AD1819 AC97-compatible codec)
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * Notes:
21 * 1. Only flat DMA is supported; s-g is not supported right now
22 *
23 *
24<jsm> tausq: Anyway, to set up sample rates for D to A, you just use the sample rate on the codec. For A to D, you need to set the codec always to 48K (using the split sample rate feature on the codec) and then set the resampler on the AD1889 to the sample rate you want.
25<jsm> Also, when changing the sample rate on the codec you need to power it down and re power it up for the change to take effect!
26 *
27 * $Id: ad1889.c,v 1.3 2002/10/19 21:31:44 grundler Exp $
28 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/module.h>
30#include <linux/init.h>
31#include <linux/ioport.h>
32#include <linux/pci.h>
33#include <linux/poll.h>
34#include <linux/proc_fs.h>
35#include <linux/slab.h>
36#include <linux/soundcard.h>
37#include <linux/ac97_codec.h>
38#include <linux/sound.h>
39#include <linux/interrupt.h>
Ingo Molnar910f5d22006-03-23 03:00:39 -080040#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#include <asm/delay.h>
43#include <asm/io.h>
44#include <asm/dma.h>
45#include <asm/uaccess.h>
46
47#include "ad1889.h"
48
49#define DBG(fmt, arg...) printk(fmt, ##arg)
50#define DEVNAME "ad1889"
51
52#define NR_HW_CH 4
53#define DAC_RUNNING 1
54#define ADC_RUNNING 2
55
56#define UNDERRUN(dev) (0)
57
58#define AD1889_READW(dev,reg) readw(dev->regbase + reg)
59#define AD1889_WRITEW(dev,reg,val) writew((val), dev->regbase + reg)
60#define AD1889_READL(dev,reg) readl(dev->regbase + reg)
61#define AD1889_WRITEL(dev,reg,val) writel((val), dev->regbase + reg)
62
63//now 100ms
64/* #define WAIT_10MS() schedule_timeout(HZ/10) */
65#define WAIT_10MS() do { int __i; for (__i = 0; __i < 100; __i++) udelay(1000); } while(0)
66
67/* currently only support a single device */
68static ad1889_dev_t *ad1889_dev = NULL;
69
70/************************* helper routines ***************************** */
71static inline void ad1889_set_wav_rate(ad1889_dev_t *dev, int rate)
72{
73 struct ac97_codec *ac97_codec = dev->ac97_codec;
74
75 DBG("Setting WAV rate to %d\n", rate);
76 dev->state[AD_WAV_STATE].dmabuf.rate = rate;
Stuart Bradye74eb802005-03-01 23:00:56 +000077 AD1889_WRITEW(dev, AD_DS_WAS, rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79 /* Cycle the DAC to enable the new rate */
80 ac97_codec->codec_write(dev->ac97_codec, AC97_POWER_CONTROL, 0x0200);
81 WAIT_10MS();
82 ac97_codec->codec_write(dev->ac97_codec, AC97_POWER_CONTROL, 0);
83}
84
85static inline void ad1889_set_wav_fmt(ad1889_dev_t *dev, int fmt)
86{
87 u16 tmp;
88
89 DBG("Setting WAV format to 0x%x\n", fmt);
90
Stuart Bradye74eb802005-03-01 23:00:56 +000091 tmp = AD1889_READW(ad1889_dev, AD_DS_WSMC);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 if (fmt & AFMT_S16_LE) {
93 //tmp |= 0x0100; /* set WA16 */
94 tmp |= 0x0300; /* set WA16 stereo */
95 } else if (fmt & AFMT_U8) {
96 tmp &= ~0x0100; /* clear WA16 */
97 }
Stuart Bradye74eb802005-03-01 23:00:56 +000098 AD1889_WRITEW(ad1889_dev, AD_DS_WSMC, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099}
100
101static inline void ad1889_set_adc_fmt(ad1889_dev_t *dev, int fmt)
102{
103 u16 tmp;
104
105 DBG("Setting ADC format to 0x%x\n", fmt);
106
Stuart Bradye74eb802005-03-01 23:00:56 +0000107 tmp = AD1889_READW(ad1889_dev, AD_DS_RAMC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 if (fmt & AFMT_S16_LE) {
109 tmp |= 0x0100; /* set WA16 */
110 } else if (fmt & AFMT_U8) {
111 tmp &= ~0x0100; /* clear WA16 */
112 }
Stuart Bradye74eb802005-03-01 23:00:56 +0000113 AD1889_WRITEW(ad1889_dev, AD_DS_RAMC, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114}
115
116static void ad1889_start_wav(ad1889_state_t *state)
117{
118 unsigned long flags;
119 struct dmabuf *dmabuf = &state->dmabuf;
120 int cnt;
121 u16 tmp;
122
123 spin_lock_irqsave(&state->card->lock, flags);
124
125 if (dmabuf->dma_len) /* DMA already in flight */
126 goto skip_dma;
127
128 /* setup dma */
129 cnt = dmabuf->wr_ptr - dmabuf->rd_ptr;
130 if (cnt == 0) /* done - don't need to do anything */
131 goto skip_dma;
132
133 /* If the wr_ptr has wrapped, only map to the end */
134 if (cnt < 0)
135 cnt = DMA_SIZE - dmabuf->rd_ptr;
136
137 dmabuf->dma_handle = pci_map_single(ad1889_dev->pci,
138 dmabuf->rawbuf + dmabuf->rd_ptr,
139 cnt, PCI_DMA_TODEVICE);
140 dmabuf->dma_len = cnt;
141 dmabuf->ready = 1;
142
143 DBG("Starting playback at 0x%p for %ld bytes\n", dmabuf->rawbuf +
144 dmabuf->rd_ptr, dmabuf->dma_len);
145
146 /* load up the current register set */
Stuart Bradye74eb802005-03-01 23:00:56 +0000147 AD1889_WRITEL(ad1889_dev, AD_DMA_WAVCC, cnt);
148 AD1889_WRITEL(ad1889_dev, AD_DMA_WAVICC, cnt);
149 AD1889_WRITEL(ad1889_dev, AD_DMA_WAVCA, dmabuf->dma_handle);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151 /* TODO: for now we load the base registers with the same thing */
Stuart Bradye74eb802005-03-01 23:00:56 +0000152 AD1889_WRITEL(ad1889_dev, AD_DMA_WAVBC, cnt);
153 AD1889_WRITEL(ad1889_dev, AD_DMA_WAVIBC, cnt);
154 AD1889_WRITEL(ad1889_dev, AD_DMA_WAVBA, dmabuf->dma_handle);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156 /* and we're off to the races... */
Stuart Bradye74eb802005-03-01 23:00:56 +0000157 AD1889_WRITEL(ad1889_dev, AD_DMA_CHSS, 0x8);
158 tmp = AD1889_READW(ad1889_dev, AD_DS_WSMC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 tmp |= 0x0400; /* set WAEN */
Stuart Bradye74eb802005-03-01 23:00:56 +0000160 AD1889_WRITEW(ad1889_dev, AD_DS_WSMC, tmp);
161 (void) AD1889_READW(ad1889_dev, AD_DS_WSMC); /* flush posted PCI write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
163 dmabuf->enable |= DAC_RUNNING;
164
165skip_dma:
166 spin_unlock_irqrestore(&state->card->lock, flags);
167}
168
169
170static void ad1889_stop_wav(ad1889_state_t *state)
171{
172 unsigned long flags;
173 struct dmabuf *dmabuf = &state->dmabuf;
174
175 spin_lock_irqsave(&state->card->lock, flags);
176
177 if (dmabuf->enable & DAC_RUNNING) {
178 u16 tmp;
179 unsigned long cnt = dmabuf->dma_len;
180
Stuart Bradye74eb802005-03-01 23:00:56 +0000181 tmp = AD1889_READW(ad1889_dev, AD_DS_WSMC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 tmp &= ~0x0400; /* clear WAEN */
Stuart Bradye74eb802005-03-01 23:00:56 +0000183 AD1889_WRITEW(ad1889_dev, AD_DS_WSMC, tmp);
184 (void) AD1889_READW(ad1889_dev, AD_DS_WSMC); /* flush posted PCI write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 pci_unmap_single(ad1889_dev->pci, dmabuf->dma_handle,
186 cnt, PCI_DMA_TODEVICE);
187
188 dmabuf->enable &= ~DAC_RUNNING;
189
190 /* update dma pointers */
191 dmabuf->rd_ptr += cnt;
192 dmabuf->rd_ptr &= (DMA_SIZE - 1);
193
194 dmabuf->dma_handle = 0;
195 dmabuf->dma_len = 0;
196 dmabuf->ready = 0;
197
198 wake_up(&dmabuf->wait);
199 }
200
201 spin_unlock_irqrestore(&state->card->lock, flags);
202}
203
204
205#if 0
206static void ad1889_startstop_adc(ad1889_state_t *state, int start)
207{
208 u16 tmp;
209 unsigned long flags;
210
211 spin_lock_irqsave(&state->card->lock, flags);
212
Stuart Bradye74eb802005-03-01 23:00:56 +0000213 tmp = AD1889_READW(ad1889_dev, AD_DS_RAMC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 if (start) {
215 state->dmabuf.enable |= ADC_RUNNING;
216 tmp |= 0x0004; /* set ADEN */
217 } else {
218 state->dmabuf.enable &= ~ADC_RUNNING;
219 tmp &= ~0x0004; /* clear ADEN */
220 }
Stuart Bradye74eb802005-03-01 23:00:56 +0000221 AD1889_WRITEW(ad1889_dev, AD_DS_RAMC, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
223 spin_unlock_irqrestore(&state->card->lock, flags);
224}
225#endif
226
227static ad1889_dev_t *ad1889_alloc_dev(struct pci_dev *pci)
228{
229 ad1889_dev_t *dev;
230 struct dmabuf *dmabuf;
231 int i;
232
233 if ((dev = kmalloc(sizeof(ad1889_dev_t), GFP_KERNEL)) == NULL)
234 return NULL;
235 memset(dev, 0, sizeof(ad1889_dev_t));
236 spin_lock_init(&dev->lock);
237 dev->pci = pci;
238
239 for (i = 0; i < AD_MAX_STATES; i++) {
240 dev->state[i].card = dev;
Ingo Molnar910f5d22006-03-23 03:00:39 -0800241 mutex_init(&dev->state[i].mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 init_waitqueue_head(&dev->state[i].dmabuf.wait);
243 }
244
245 /* allocate dma buffer */
246
247 for (i = 0; i < AD_MAX_STATES; i++) {
248 dmabuf = &dev->state[i].dmabuf;
249 dmabuf->rawbuf = kmalloc(DMA_SIZE, GFP_KERNEL|GFP_DMA);
250 if (!dmabuf->rawbuf)
251 goto err_free_dmabuf;
252 dmabuf->rawbuf_size = DMA_SIZE;
253 dmabuf->dma_handle = 0;
254 dmabuf->rd_ptr = dmabuf->wr_ptr = dmabuf->dma_len = 0UL;
255 dmabuf->ready = 0;
256 dmabuf->rate = 48000;
257 }
258 return dev;
259
260err_free_dmabuf:
261 while (--i >= 0)
262 kfree(dev->state[i].dmabuf.rawbuf);
263 kfree(dev);
264 return NULL;
265}
266
267static void ad1889_free_dev(ad1889_dev_t *dev)
268{
269 int j;
270 struct dmabuf *dmabuf;
271
272 if (dev == NULL)
273 return;
274
275 if (dev->ac97_codec)
276 ac97_release_codec(dev->ac97_codec);
277
278 for (j = 0; j < AD_MAX_STATES; j++) {
279 dmabuf = &dev->state[j].dmabuf;
Jesper Juhl09417372005-06-25 14:58:49 -0700280 kfree(dmabuf->rawbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 }
282
283 kfree(dev);
284}
285
286static inline void ad1889_trigger_playback(ad1889_dev_t *dev)
287{
288#if 0
289 u32 val;
290 struct dmabuf *dmabuf = &dev->state[AD_WAV_STATE].dmabuf;
291#endif
292
293 ad1889_start_wav(&dev->state[AD_WAV_STATE]);
294}
295
296static int ad1889_read_proc (char *page, char **start, off_t off,
297 int count, int *eof, void *data)
298{
299 char *out = page;
300 int len, i;
301 ad1889_dev_t *dev = data;
302 ad1889_reg_t regs[] = {
Stuart Bradye74eb802005-03-01 23:00:56 +0000303 { "WSMC", AD_DS_WSMC, 16 },
304 { "RAMC", AD_DS_RAMC, 16 },
305 { "WADA", AD_DS_WADA, 16 },
306 { "SYDA", AD_DS_SYDA, 16 },
307 { "WAS", AD_DS_WAS, 16 },
308 { "RES", AD_DS_RES, 16 },
309 { "CCS", AD_DS_CCS, 16 },
310 { "ADCBA", AD_DMA_ADCBA, 32 },
311 { "ADCCA", AD_DMA_ADCCA, 32 },
312 { "ADCBC", AD_DMA_ADCBC, 32 },
313 { "ADCCC", AD_DMA_ADCCC, 32 },
314 { "ADCIBC", AD_DMA_ADCIBC, 32 },
315 { "ADCICC", AD_DMA_ADCICC, 32 },
316 { "ADCCTRL", AD_DMA_ADCCTRL, 16 },
317 { "WAVBA", AD_DMA_WAVBA, 32 },
318 { "WAVCA", AD_DMA_WAVCA, 32 },
319 { "WAVBC", AD_DMA_WAVBC, 32 },
320 { "WAVCC", AD_DMA_WAVCC, 32 },
321 { "WAVIBC", AD_DMA_WAVIBC, 32 },
322 { "WAVICC", AD_DMA_WAVICC, 32 },
323 { "WAVCTRL", AD_DMA_WAVCTRL, 16 },
324 { "DISR", AD_DMA_DISR, 32 },
325 { "CHSS", AD_DMA_CHSS, 32 },
326 { "IPC", AD_GPIO_IPC, 16 },
327 { "OP", AD_GPIO_OP, 16 },
328 { "IP", AD_GPIO_IP, 16 },
329 { "ACIC", AD_AC97_ACIC, 16 },
330 { "AC97_RESET", AD_AC97_BASE + AC97_RESET, 16 },
331 { "AC97_MASTER_VOL_STEREO", AD_AC97_BASE + AC97_MASTER_VOL_STEREO, 16 },
332 { "AC97_HEADPHONE_VOL", AD_AC97_BASE + AC97_HEADPHONE_VOL, 16 },
333 { "AC97_MASTER_VOL_MONO", AD_AC97_BASE + AC97_MASTER_VOL_MONO, 16 },
334 { "AC97_MASTER_TONE", AD_AC97_BASE + AC97_MASTER_TONE, 16 },
335 { "AC97_PCBEEP_VOL", AD_AC97_BASE + AC97_PCBEEP_VOL, 16 },
336 { "AC97_PHONE_VOL", AD_AC97_BASE + AC97_PHONE_VOL, 16 },
337 { "AC97_MIC_VOL", AD_AC97_BASE + AC97_MIC_VOL, 16 },
338 { "AC97_LINEIN_VOL", AD_AC97_BASE + AC97_LINEIN_VOL, 16 },
339 { "AC97_CD_VOL", AD_AC97_BASE + AC97_CD_VOL, 16 },
340 { "AC97_VIDEO_VOL", AD_AC97_BASE + AC97_VIDEO_VOL, 16 },
341 { "AC97_AUX_VOL", AD_AC97_BASE + AC97_AUX_VOL, 16 },
342 { "AC97_PCMOUT_VOL", AD_AC97_BASE + AC97_PCMOUT_VOL, 16 },
343 { "AC97_RECORD_SELECT", AD_AC97_BASE + AC97_RECORD_SELECT, 16 },
344 { "AC97_RECORD_GAIN", AD_AC97_BASE + AC97_RECORD_GAIN, 16 },
345 { "AC97_RECORD_GAIN_MIC", AD_AC97_BASE + AC97_RECORD_GAIN_MIC, 16 },
346 { "AC97_GENERAL_PURPOSE", AD_AC97_BASE + AC97_GENERAL_PURPOSE, 16 },
347 { "AC97_3D_CONTROL", AD_AC97_BASE + AC97_3D_CONTROL, 16 },
348 { "AC97_MODEM_RATE", AD_AC97_BASE + AC97_MODEM_RATE, 16 },
349 { "AC97_POWER_CONTROL", AD_AC97_BASE + AC97_POWER_CONTROL, 16 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 { NULL }
351 };
352
353 if (dev == NULL)
354 return -ENODEV;
355
356 for (i = 0; regs[i].name != 0; i++)
357 out += sprintf(out, "%s: 0x%0*x\n", regs[i].name,
358 regs[i].width >> 2,
359 (regs[i].width == 16
360 ? AD1889_READW(dev, regs[i].offset)
361 : AD1889_READL(dev, regs[i].offset)));
362
363 for (i = 0; i < AD_MAX_STATES; i++) {
364 out += sprintf(out, "DMA status for %s:\n",
365 (i == AD_WAV_STATE ? "WAV" : "ADC"));
366 out += sprintf(out, "\t\t0x%p (IOVA: 0x%llu)\n",
367 dev->state[i].dmabuf.rawbuf,
368 (unsigned long long)dev->state[i].dmabuf.dma_handle);
369
370 out += sprintf(out, "\tread ptr: offset %u\n",
371 (unsigned int)dev->state[i].dmabuf.rd_ptr);
372 out += sprintf(out, "\twrite ptr: offset %u\n",
373 (unsigned int)dev->state[i].dmabuf.wr_ptr);
374 out += sprintf(out, "\tdma len: offset %u\n",
375 (unsigned int)dev->state[i].dmabuf.dma_len);
376 }
377
378 len = out - page - off;
379 if (len < count) {
380 *eof = 1;
381 if (len <= 0) return 0;
382 } else {
383 len = count;
384 }
385 *start = page + off;
386 return len;
387}
388
389/***************************** DMA interfaces ************************** */
390#if 0
391static inline unsigned long ad1889_get_dma_addr(ad1889_state_t *state)
392{
393 struct dmabuf *dmabuf = &state->dmabuf;
394 u32 offset;
395
396 if (!(dmabuf->enable & (DAC_RUNNING | ADC_RUNNING))) {
397 printk(KERN_ERR DEVNAME ": get_dma_addr called without dma enabled\n");
398 return 0;
399 }
400
401 if (dmabuf->enable & DAC_RUNNING)
Stuart Bradye74eb802005-03-01 23:00:56 +0000402 offset = le32_to_cpu(AD1889_READL(state->card, AD_DMA_WAVBA));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 else
Stuart Bradye74eb802005-03-01 23:00:56 +0000404 offset = le32_to_cpu(AD1889_READL(state->card, AD_DMA_ADCBA));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
406 return (unsigned long)bus_to_virt((unsigned long)offset) - (unsigned long)dmabuf->rawbuf;
407}
408
409static void ad1889_update_ptr(ad1889_dev_t *dev, int wake)
410{
411 ad1889_state_t *state;
412 struct dmabuf *dmabuf;
413 unsigned long hwptr;
414 int diff;
415
416 /* check ADC first */
417 state = &dev->adc_state;
418 dmabuf = &state->dmabuf;
419 if (dmabuf->enable & ADC_RUNNING) {
420 hwptr = ad1889_get_dma_addr(state);
421 diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
422
423 dmabuf->hwptr = hwptr;
424 dmabuf->total_bytes += diff;
425 dmabuf->count += diff;
426 if (dmabuf->count > dmabuf->dmasize)
427 dmabuf->count = dmabuf->dmasize;
428
429 if (dmabuf->mapped) {
430 if (wake & dmabuf->count >= dmabuf->fragsize)
431 wake_up(&dmabuf->wait);
432 } else {
433 if (wake & dmabuf->count > 0)
434 wake_up(&dmabuf->wait);
435 }
436 }
437
438 /* check DAC */
439 state = &dev->wav_state;
440 dmabuf = &state->dmabuf;
441 if (dmabuf->enable & DAC_RUNNING) {
442XXX
443
444}
445#endif
446
447/************************* /dev/dsp interfaces ************************* */
448
449static ssize_t ad1889_read(struct file *file, char __user *buffer, size_t count,
450 loff_t *ppos)
451{
452 return 0;
453}
454
455static ssize_t ad1889_write(struct file *file, const char __user *buffer, size_t count,
456 loff_t *ppos)
457{
458 ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
459 ad1889_state_t *state = &dev->state[AD_WAV_STATE];
460 volatile struct dmabuf *dmabuf = &state->dmabuf;
461 ssize_t ret = 0;
462 DECLARE_WAITQUEUE(wait, current);
463
Ingo Molnar910f5d22006-03-23 03:00:39 -0800464 mutex_lock(&state->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465#if 0
466 if (dmabuf->mapped) {
467 ret = -ENXIO;
468 goto err1;
469 }
470#endif
471 if (!access_ok(VERIFY_READ, buffer, count)) {
472 ret = -EFAULT;
473 goto err1;
474 }
475
476 add_wait_queue(&state->dmabuf.wait, &wait);
477
478 /* start filling dma buffer.... */
479 while (count > 0) {
480 long rem;
481 long cnt = count;
482 unsigned long flags;
483
484 for (;;) {
485 long used_bytes;
486 long timeout; /* max time for DMA in jiffies */
487
488 /* buffer is full if wr catches up to rd */
489 spin_lock_irqsave(&state->card->lock, flags);
490 used_bytes = dmabuf->wr_ptr - dmabuf->rd_ptr;
491 timeout = (dmabuf->dma_len * HZ) / dmabuf->rate;
492 spin_unlock_irqrestore(&state->card->lock, flags);
493
494 /* adjust for buffer wrap around */
495 used_bytes = (used_bytes + DMA_SIZE) & (DMA_SIZE - 1);
496
497 /* If at least one page unused */
498 if (used_bytes < (DMA_SIZE - 0x1000))
499 break;
500
501 /* dma buffer full */
502
503 if (file->f_flags & O_NONBLOCK) {
504 ret = -EAGAIN;
505 goto err2;
506 }
507
508 set_current_state(TASK_INTERRUPTIBLE);
509 schedule_timeout(timeout + 1);
510 if (signal_pending(current)) {
511 ret = -ERESTARTSYS;
512 goto err2;
513 }
514 }
515
516 /* watch out for wrapping around static buffer */
517 spin_lock_irqsave(&state->card->lock, flags);
518 rem = DMA_SIZE - dmabuf->wr_ptr;
519 if (cnt > rem)
520 cnt = rem;
521
522 rem = dmabuf->wr_ptr;
523
524 /* update dma pointers */
525 dmabuf->wr_ptr += cnt;
526 dmabuf->wr_ptr &= DMA_SIZE - 1; /* wrap ptr if necessary */
527 spin_unlock_irqrestore(&state->card->lock, flags);
528
529 /* transfer unwrapped chunk */
530 if (copy_from_user(dmabuf->rawbuf + rem, buffer, cnt)) {
531 ret = -EFAULT;
532 goto err2;
533 }
534
535 DBG("Writing 0x%lx bytes to +0x%lx\n", cnt, rem);
536
537 /* update counters */
538 count -= cnt;
539 buffer += cnt;
540 ret += cnt;
541
542 /* we have something to play - go play it! */
543 ad1889_trigger_playback(dev);
544 }
545
546err2:
547 remove_wait_queue(&state->dmabuf.wait, &wait);
548err1:
Ingo Molnar910f5d22006-03-23 03:00:39 -0800549 mutex_unlock(&state->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 return ret;
551}
552
553static unsigned int ad1889_poll(struct file *file, struct poll_table_struct *wait)
554{
555 unsigned int mask = 0;
556#if 0
557 ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
558 ad1889_state_t *state = NULL;
559 struct dmabuf *dmabuf;
560 unsigned long flags;
561
562 if (!(file->f_mode & (FMODE_READ | FMODE_WRITE)))
563 return -EINVAL;
564
565 if (file->f_mode & FMODE_WRITE) {
566 state = &dev->state[AD_WAV_STATE];
567 if (!state) return 0;
568 dmabuf = &state->dmabuf;
569 poll_wait(file, &dmabuf->wait, wait);
570 }
571
572 if (file->f_mode & FMODE_READ) {
573 state = &dev->state[AD_ADC_STATE];
574 if (!state) return 0;
575 dmabuf = &state->dmabuf;
576 poll_wait(file, &dmabuf->wait, wait);
577 }
578
579 spin_lock_irqsave(&dev->lock, flags);
580 ad1889_update_ptr(dev, 0);
581
582 if (file->f_mode & FMODE_WRITE) {
583 state = &dev->state[WAV_STATE];
584 dmabuf = &state->dmabuf;
585 if (dmabuf->mapped) {
586 if (dmabuf->count >= (int)dmabuf->fragsize)
587 mask |= POLLOUT | POLLWRNORM;
588 } else {
589 if ((int)dmabuf->dmasize >= dmabuf->count +
590 (int)dmabuf->fragsize)
591 mask |= POLLOUT | POLLWRNORM;
592 }
593 }
594
595 if (file ->f_mode & FMODE_READ) {
596 state = &dev->state[AD_ADC_STATE];
597 dmabuf = &state->dmabuf;
598 if (dmabuf->count >= (int)dmabuf->fragsize)
599 mask |= POLLIN | POLLRDNORM;
600 }
601 spin_unlock_irqrestore(&dev->lock, flags);
602
603#endif
604 return mask;
605}
606
607static int ad1889_mmap(struct file *file, struct vm_area_struct *vma)
608{
609 return 0;
610}
611
612static int ad1889_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
613 unsigned long arg)
614{
615 int val = 0;
616 ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
617 struct dmabuf *dmabuf;
618 audio_buf_info abinfo;
619 int __user *p = (int __user *)arg;
620
621 DBG("ad1889_ioctl cmd 0x%x arg %lu\n", cmd, arg);
622
623 switch (cmd)
624 {
625 case OSS_GETVERSION:
626 return put_user(SOUND_VERSION, p);
627
628 case SNDCTL_DSP_RESET:
629 break;
630
631 case SNDCTL_DSP_SYNC:
632 break;
633
634 case SNDCTL_DSP_SPEED:
635 /* set sampling rate */
636 if (get_user(val, p))
637 return -EFAULT;
638 if (val > 5400 && val < 48000)
639 {
640 if (file->f_mode & FMODE_WRITE)
Stuart Bradye74eb802005-03-01 23:00:56 +0000641 AD1889_WRITEW(ad1889_dev, AD_DS_WAS, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 if (file->f_mode & FMODE_READ)
Stuart Bradye74eb802005-03-01 23:00:56 +0000643 AD1889_WRITEW(ad1889_dev, AD_DS_RES, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 }
645 return 0;
646
647 case SNDCTL_DSP_STEREO: /* undocumented? */
648 if (get_user(val, p))
649 return -EFAULT;
650 if (file->f_mode & FMODE_READ) {
Stuart Bradye74eb802005-03-01 23:00:56 +0000651 val = AD1889_READW(ad1889_dev, AD_DS_WSMC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 if (val) {
653 val |= 0x0200; /* set WAST */
654 } else {
655 val &= ~0x0200; /* clear WAST */
656 }
Stuart Bradye74eb802005-03-01 23:00:56 +0000657 AD1889_WRITEW(ad1889_dev, AD_DS_WSMC, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 }
659 if (file->f_mode & FMODE_WRITE) {
Stuart Bradye74eb802005-03-01 23:00:56 +0000660 val = AD1889_READW(ad1889_dev, AD_DS_RAMC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 if (val) {
662 val |= 0x0002; /* set ADST */
663 } else {
664 val &= ~0x0002; /* clear ADST */
665 }
Stuart Bradye74eb802005-03-01 23:00:56 +0000666 AD1889_WRITEW(ad1889_dev, AD_DS_RAMC, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 }
668
669 return 0;
670
671 case SNDCTL_DSP_GETBLKSIZE:
672 return put_user(DMA_SIZE, p);
673
674 case SNDCTL_DSP_GETFMTS:
675 return put_user(AFMT_S16_LE|AFMT_U8, p);
676
677 case SNDCTL_DSP_SETFMT:
678 if (get_user(val, p))
679 return -EFAULT;
680
681 if (val == 0) {
682 if (file->f_mode & FMODE_READ)
683 ad1889_set_adc_fmt(dev, val);
684
685 if (file->f_mode & FMODE_WRITE)
686 ad1889_set_wav_fmt(dev, val);
687 } else {
688 val = AFMT_S16_LE | AFMT_U8;
689 }
690
691 return put_user(val, p);
692
693 case SNDCTL_DSP_CHANNELS:
694 break;
695
696 case SNDCTL_DSP_POST:
697 /* send all data to device */
698 break;
699
700 case SNDCTL_DSP_SUBDIVIDE:
701 break;
702
703 case SNDCTL_DSP_SETFRAGMENT:
704 /* not supported; uses fixed fragment sizes */
705 return put_user(DMA_SIZE, p);
706
707 case SNDCTL_DSP_GETOSPACE:
708 case SNDCTL_DSP_GETISPACE:
709 /* space left in dma buffers */
710 if (cmd == SNDCTL_DSP_GETOSPACE)
711 dmabuf = &dev->state[AD_WAV_STATE].dmabuf;
712 else
713 dmabuf = &dev->state[AD_ADC_STATE].dmabuf;
714 abinfo.fragments = 1;
715 abinfo.fragstotal = 1;
716 abinfo.fragsize = DMA_SIZE;
717 abinfo.bytes = DMA_SIZE;
718 return copy_to_user(p, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
719 case SNDCTL_DSP_NONBLOCK:
720 file->f_flags |= O_NONBLOCK;
721 return 0;
722
723 case SNDCTL_DSP_GETCAPS:
724 return put_user(0, p);
725
726 case SNDCTL_DSP_GETTRIGGER:
727 case SNDCTL_DSP_SETTRIGGER:
728 break;
729
730 case SNDCTL_DSP_GETIPTR:
731 case SNDCTL_DSP_GETOPTR:
732 break;
733
734 case SNDCTL_DSP_SETDUPLEX:
735 break;
736
737 case SNDCTL_DSP_GETODELAY:
738 break;
739
740 case SOUND_PCM_READ_RATE:
Stuart Bradye74eb802005-03-01 23:00:56 +0000741 return put_user(AD1889_READW(ad1889_dev, AD_DS_WAS), p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
743 case SOUND_PCM_READ_CHANNELS:
744 case SOUND_PCM_READ_BITS:
745 break;
746
747 case SNDCTL_DSP_MAPINBUF:
748 case SNDCTL_DSP_MAPOUTBUF:
749 case SNDCTL_DSP_SETSYNCRO:
750 case SOUND_PCM_WRITE_FILTER:
751 case SOUND_PCM_READ_FILTER:
752 break;
753
754 default:
755 break;
756 }
757
758 return -ENOTTY;
759}
760
761static int ad1889_open(struct inode *inode, struct file *file)
762{
763 /* check minor; only support /dev/dsp atm */
764 if (iminor(inode) != 3)
765 return -ENXIO;
766
767 file->private_data = ad1889_dev;
768
769 ad1889_set_wav_rate(ad1889_dev, 48000);
770 ad1889_set_wav_fmt(ad1889_dev, AFMT_S16_LE);
Stuart Bradye74eb802005-03-01 23:00:56 +0000771 AD1889_WRITEW(ad1889_dev, AD_DS_WADA, 0x0404); /* attenuation */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 return nonseekable_open(inode, file);
773}
774
775static int ad1889_release(struct inode *inode, struct file *file)
776{
777 /* if we have state free it here */
778 return 0;
779}
780
781static struct file_operations ad1889_fops = {
782 .owner = THIS_MODULE,
783 .llseek = no_llseek,
784 .read = ad1889_read,
785 .write = ad1889_write,
786 .poll = ad1889_poll,
787 .ioctl = ad1889_ioctl,
788 .mmap = ad1889_mmap,
789 .open = ad1889_open,
790 .release = ad1889_release,
791};
792
793/************************* /dev/mixer interfaces ************************ */
794static int ad1889_mixer_open(struct inode *inode, struct file *file)
795{
796 if (ad1889_dev->ac97_codec->dev_mixer != iminor(inode))
797 return -ENODEV;
798
799 file->private_data = ad1889_dev->ac97_codec;
800 return 0;
801}
802
803static int ad1889_mixer_release(struct inode *inode, struct file *file)
804{
805 return 0;
806}
807
808static int ad1889_mixer_ioctl(struct inode *inode, struct file *file,
809 unsigned int cmd, unsigned long arg)
810{
811 struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
812 return codec->mixer_ioctl(codec, cmd, arg);
813}
814
815static struct file_operations ad1889_mixer_fops = {
816 .owner = THIS_MODULE,
817 .llseek = no_llseek,
818 .ioctl = ad1889_mixer_ioctl,
819 .open = ad1889_mixer_open,
820 .release = ad1889_mixer_release,
821};
822
823/************************* AC97 interfaces ****************************** */
824static void ad1889_codec_write(struct ac97_codec *ac97, u8 reg, u16 val)
825{
826 ad1889_dev_t *dev = ac97->private_data;
827
Stuart Bradye74eb802005-03-01 23:00:56 +0000828 //DBG("Writing 0x%x to 0x%lx\n", val, dev->regbase + AD_AC97_BASE + reg);
829 AD1889_WRITEW(dev, AD_AC97_BASE + reg, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830}
831
832static u16 ad1889_codec_read(struct ac97_codec *ac97, u8 reg)
833{
834 ad1889_dev_t *dev = ac97->private_data;
Stuart Bradye74eb802005-03-01 23:00:56 +0000835 //DBG("Reading from 0x%lx\n", dev->regbase + AD_AC97_BASE + reg);
836 return AD1889_READW(dev, AD_AC97_BASE + reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837}
838
839static int ad1889_ac97_init(ad1889_dev_t *dev, int id)
840{
841 struct ac97_codec *ac97;
842 u16 eid;
843
844 if ((ac97 = ac97_alloc_codec()) == NULL)
845 return -ENOMEM;
846
847 ac97->private_data = dev;
848 ac97->id = id;
849
850 ac97->codec_read = ad1889_codec_read;
851 ac97->codec_write = ad1889_codec_write;
852
853 if (ac97_probe_codec(ac97) == 0) {
854 printk(DEVNAME ": ac97_probe_codec failed\n");
855 goto out_free;
856 }
857
858 eid = ad1889_codec_read(ac97, AC97_EXTENDED_ID);
859 if (eid == 0xffff) {
860 printk(KERN_WARNING DEVNAME ": no codec attached?\n");
861 goto out_free;
862 }
863
864 dev->ac97_features = eid;
865
866 if ((ac97->dev_mixer = register_sound_mixer(&ad1889_mixer_fops, -1)) < 0) {
867 printk(KERN_ERR DEVNAME ": cannot register mixer\n");
868 goto out_free;
869 }
870
871 dev->ac97_codec = ac97;
872 return 0;
873
874out_free:
875 ac97_release_codec(ac97);
876 return -ENODEV;
877}
878
879static int ad1889_aclink_reset(struct pci_dev * pcidev)
880{
881 u16 stat;
882 int retry = 200;
883 ad1889_dev_t *dev = pci_get_drvdata(pcidev);
884
Stuart Bradye74eb802005-03-01 23:00:56 +0000885 AD1889_WRITEW(dev, AD_DS_CCS, 0x8000); /* turn on clock */
886 AD1889_READW(dev, AD_DS_CCS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887
888 WAIT_10MS();
889
Stuart Bradye74eb802005-03-01 23:00:56 +0000890 stat = AD1889_READW(dev, AD_AC97_ACIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 stat |= 0x0002; /* Reset Disable */
Stuart Bradye74eb802005-03-01 23:00:56 +0000892 AD1889_WRITEW(dev, AD_AC97_ACIC, stat);
893 (void) AD1889_READW(dev, AD_AC97_ACIC); /* flush posted write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
895 udelay(10);
896
Stuart Bradye74eb802005-03-01 23:00:56 +0000897 stat = AD1889_READW(dev, AD_AC97_ACIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 stat |= 0x0001; /* Interface Enable */
Stuart Bradye74eb802005-03-01 23:00:56 +0000899 AD1889_WRITEW(dev, AD_AC97_ACIC, stat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
901 do {
Stuart Bradye74eb802005-03-01 23:00:56 +0000902 if (AD1889_READW(dev, AD_AC97_ACIC) & 0x8000) /* Ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 break;
904 WAIT_10MS();
905 retry--;
906 } while (retry > 0);
907
908 if (!retry) {
909 printk(KERN_ERR "ad1889_aclink_reset: codec is not ready [0x%x]\n",
Stuart Bradye74eb802005-03-01 23:00:56 +0000910 AD1889_READW(dev, AD_AC97_ACIC));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 return -EBUSY;
912 }
913
914 /* TODO reset AC97 codec */
915 /* TODO set wave/adc pci ctrl status */
916
Stuart Bradye74eb802005-03-01 23:00:56 +0000917 stat = AD1889_READW(dev, AD_AC97_ACIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 stat |= 0x0004; /* Audio Stream Output Enable */
Stuart Bradye74eb802005-03-01 23:00:56 +0000919 AD1889_WRITEW(dev, AD_AC97_ACIC, stat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 return 0;
921}
922
923/************************* PCI interfaces ****************************** */
924/* PCI device table */
925static struct pci_device_id ad1889_id_tbl[] = {
926 { PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS, PCI_ANY_ID,
927 PCI_ANY_ID, 0, 0, (unsigned long)DEVNAME },
928 { },
929};
930MODULE_DEVICE_TABLE(pci, ad1889_id_tbl);
931
932static irqreturn_t ad1889_interrupt(int irq, void *dev_id, struct pt_regs *regs)
933{
934 u32 stat;
935 ad1889_dev_t *dev = (ad1889_dev_t *)dev_id;
936
Stuart Bradye74eb802005-03-01 23:00:56 +0000937 stat = AD1889_READL(dev, AD_DMA_DISR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
939 /* clear ISR */
Stuart Bradye74eb802005-03-01 23:00:56 +0000940 AD1889_WRITEL(dev, AD_DMA_DISR, stat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
942 if (stat & 0x8) { /* WAVI */
943 DBG("WAV interrupt\n");
944 dev->stats.wav_intrs++;
945 if (dev->state[AD_WAV_STATE].dmabuf.ready) {
946 ad1889_stop_wav(&dev->state[AD_WAV_STATE]); /* clean up */
947 ad1889_start_wav(&dev->state[AD_WAV_STATE]); /* start new */
948 }
949 }
950
951 if ((stat & 0x2) && dev->state[AD_ADC_STATE].dmabuf.ready) { /* ADCI */
952 DBG("ADC interrupt\n");
953 dev->stats.adc_intrs++;
954 }
955 if(stat)
956 return IRQ_HANDLED;
957 return IRQ_NONE;
958}
959
960static void ad1889_initcfg(ad1889_dev_t *dev)
961{
962 u16 tmp16;
963 u32 tmp32;
964
965 /* make sure the interrupt bits are setup the way we want */
Stuart Bradye74eb802005-03-01 23:00:56 +0000966 tmp32 = AD1889_READL(dev, AD_DMA_WAVCTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 tmp32 &= ~0xff; /* flat dma, no sg, mask out the intr bits */
968 tmp32 |= 0x6; /* intr on count, loop */
Stuart Bradye74eb802005-03-01 23:00:56 +0000969 AD1889_WRITEL(dev, AD_DMA_WAVCTRL, tmp32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
971 /* unmute... */
Stuart Bradye74eb802005-03-01 23:00:56 +0000972 tmp16 = AD1889_READW(dev, AD_DS_WADA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 tmp16 &= ~0x8080;
Stuart Bradye74eb802005-03-01 23:00:56 +0000974 AD1889_WRITEW(dev, AD_DS_WADA, tmp16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975}
976
977static int __devinit ad1889_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
978{
979 int err;
980 ad1889_dev_t *dev;
981 unsigned long bar;
982 struct proc_dir_entry *proc_root = NULL;
983
984 if ((err = pci_enable_device(pcidev)) != 0) {
985 printk(KERN_ERR DEVNAME ": pci_enable_device failed\n");
986 return err;
987 }
988
989 pci_set_master(pcidev);
990 if ((dev = ad1889_alloc_dev(pcidev)) == NULL) {
991 printk(KERN_ERR DEVNAME ": cannot allocate memory for device\n");
992 return -ENOMEM;
993 }
994 pci_set_drvdata(pcidev, dev);
995 bar = pci_resource_start(pcidev, 0);
996
997 if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM)) {
998 printk(KERN_ERR DEVNAME ": memory region not assigned\n");
999 goto out1;
1000 }
1001
1002 if (pci_request_region(pcidev, 0, DEVNAME)) {
1003 printk(KERN_ERR DEVNAME ": unable to request memory region\n");
1004 goto out1;
1005 }
1006
Stuart Bradye74eb802005-03-01 23:00:56 +00001007 dev->regbase = ioremap_nocache(bar, AD_DS_IOMEMSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 if (!dev->regbase) {
1009 printk(KERN_ERR DEVNAME ": unable to remap iomem\n");
1010 goto out2;
1011 }
1012
Thomas Gleixner65ca68b2006-07-01 19:29:46 -07001013 if (request_irq(pcidev->irq, ad1889_interrupt, IRQF_SHARED, DEVNAME, dev) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 printk(KERN_ERR DEVNAME ": unable to request interrupt\n");
1015 goto out3;
1016 }
1017
1018 printk(KERN_INFO DEVNAME ": %s at %p IRQ %d\n",
1019 (char *)ent->driver_data, dev->regbase, pcidev->irq);
1020
1021 if (ad1889_aclink_reset(pcidev) != 0)
1022 goto out4;
1023
1024 /* register /dev/dsp */
1025 if ((dev->dev_audio = register_sound_dsp(&ad1889_fops, -1)) < 0) {
1026 printk(KERN_ERR DEVNAME ": cannot register /dev/dsp\n");
1027 goto out4;
1028 }
1029
1030 if ((err = ad1889_ac97_init(dev, 0)) != 0)
1031 goto out5;
1032
1033 /* XXX: cleanups */
1034 if (((proc_root = proc_mkdir("driver/ad1889", NULL)) == NULL) ||
1035 create_proc_read_entry("ac97", S_IFREG|S_IRUGO, proc_root, ac97_read_proc, dev->ac97_codec) == NULL ||
1036 create_proc_read_entry("info", S_IFREG|S_IRUGO, proc_root, ad1889_read_proc, dev) == NULL)
1037 goto out5;
1038
1039 ad1889_initcfg(dev);
1040
1041 //DBG(DEVNAME ": Driver initialization done!\n");
1042
1043 ad1889_dev = dev;
1044
1045 return 0;
1046
1047out5:
1048 unregister_sound_dsp(dev->dev_audio);
1049out4:
1050 free_irq(pcidev->irq, dev);
1051out3:
1052 iounmap(dev->regbase);
1053out2:
1054 pci_release_region(pcidev, 0);
1055out1:
1056 ad1889_free_dev(dev);
1057 pci_set_drvdata(pcidev, NULL);
1058
1059 return -ENODEV;
1060}
1061
1062static void __devexit ad1889_remove(struct pci_dev *pcidev)
1063{
1064 ad1889_dev_t *dev = pci_get_drvdata(pcidev);
1065
1066 if (dev == NULL) return;
1067
1068 unregister_sound_mixer(dev->ac97_codec->dev_mixer);
1069 unregister_sound_dsp(dev->dev_audio);
1070 free_irq(pcidev->irq, dev);
1071 iounmap(dev->regbase);
1072 pci_release_region(pcidev, 0);
1073
1074 /* any hw programming needed? */
1075 ad1889_free_dev(dev);
1076 pci_set_drvdata(pcidev, NULL);
1077}
1078
1079MODULE_AUTHOR("Randolph Chung");
1080MODULE_DESCRIPTION("Analog Devices AD1889 PCI Audio");
1081MODULE_LICENSE("GPL");
1082
1083static struct pci_driver ad1889_driver = {
1084 .name = DEVNAME,
1085 .id_table = ad1889_id_tbl,
1086 .probe = ad1889_probe,
1087 .remove = __devexit_p(ad1889_remove),
1088};
1089
1090static int __init ad1889_init_module(void)
1091{
Greg Kroah-Hartman46654722005-12-06 15:33:15 -08001092 return pci_register_driver(&ad1889_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093}
1094
1095static void ad1889_exit_module(void)
1096{
1097 pci_unregister_driver(&ad1889_driver);
1098 return;
1099}
1100
1101module_init(ad1889_init_module);
1102module_exit(ad1889_exit_module);