blob: c0730a3563a2962ab86a4c24ec39c063c4df0de4 [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
Robert P. J. Day3159f062007-02-14 00:33:16 -0800233 if ((dev = kzalloc(sizeof(ad1889_dev_t), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 spin_lock_init(&dev->lock);
236 dev->pci = pci;
237
238 for (i = 0; i < AD_MAX_STATES; i++) {
239 dev->state[i].card = dev;
Ingo Molnar910f5d22006-03-23 03:00:39 -0800240 mutex_init(&dev->state[i].mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 init_waitqueue_head(&dev->state[i].dmabuf.wait);
242 }
243
244 /* allocate dma buffer */
245
246 for (i = 0; i < AD_MAX_STATES; i++) {
247 dmabuf = &dev->state[i].dmabuf;
248 dmabuf->rawbuf = kmalloc(DMA_SIZE, GFP_KERNEL|GFP_DMA);
249 if (!dmabuf->rawbuf)
250 goto err_free_dmabuf;
251 dmabuf->rawbuf_size = DMA_SIZE;
252 dmabuf->dma_handle = 0;
253 dmabuf->rd_ptr = dmabuf->wr_ptr = dmabuf->dma_len = 0UL;
254 dmabuf->ready = 0;
255 dmabuf->rate = 48000;
256 }
257 return dev;
258
259err_free_dmabuf:
260 while (--i >= 0)
261 kfree(dev->state[i].dmabuf.rawbuf);
262 kfree(dev);
263 return NULL;
264}
265
266static void ad1889_free_dev(ad1889_dev_t *dev)
267{
268 int j;
269 struct dmabuf *dmabuf;
270
271 if (dev == NULL)
272 return;
273
274 if (dev->ac97_codec)
275 ac97_release_codec(dev->ac97_codec);
276
277 for (j = 0; j < AD_MAX_STATES; j++) {
278 dmabuf = &dev->state[j].dmabuf;
Jesper Juhl09417372005-06-25 14:58:49 -0700279 kfree(dmabuf->rawbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 }
281
282 kfree(dev);
283}
284
285static inline void ad1889_trigger_playback(ad1889_dev_t *dev)
286{
287#if 0
288 u32 val;
289 struct dmabuf *dmabuf = &dev->state[AD_WAV_STATE].dmabuf;
290#endif
291
292 ad1889_start_wav(&dev->state[AD_WAV_STATE]);
293}
294
295static int ad1889_read_proc (char *page, char **start, off_t off,
296 int count, int *eof, void *data)
297{
298 char *out = page;
299 int len, i;
300 ad1889_dev_t *dev = data;
301 ad1889_reg_t regs[] = {
Stuart Bradye74eb802005-03-01 23:00:56 +0000302 { "WSMC", AD_DS_WSMC, 16 },
303 { "RAMC", AD_DS_RAMC, 16 },
304 { "WADA", AD_DS_WADA, 16 },
305 { "SYDA", AD_DS_SYDA, 16 },
306 { "WAS", AD_DS_WAS, 16 },
307 { "RES", AD_DS_RES, 16 },
308 { "CCS", AD_DS_CCS, 16 },
309 { "ADCBA", AD_DMA_ADCBA, 32 },
310 { "ADCCA", AD_DMA_ADCCA, 32 },
311 { "ADCBC", AD_DMA_ADCBC, 32 },
312 { "ADCCC", AD_DMA_ADCCC, 32 },
313 { "ADCIBC", AD_DMA_ADCIBC, 32 },
314 { "ADCICC", AD_DMA_ADCICC, 32 },
315 { "ADCCTRL", AD_DMA_ADCCTRL, 16 },
316 { "WAVBA", AD_DMA_WAVBA, 32 },
317 { "WAVCA", AD_DMA_WAVCA, 32 },
318 { "WAVBC", AD_DMA_WAVBC, 32 },
319 { "WAVCC", AD_DMA_WAVCC, 32 },
320 { "WAVIBC", AD_DMA_WAVIBC, 32 },
321 { "WAVICC", AD_DMA_WAVICC, 32 },
322 { "WAVCTRL", AD_DMA_WAVCTRL, 16 },
323 { "DISR", AD_DMA_DISR, 32 },
324 { "CHSS", AD_DMA_CHSS, 32 },
325 { "IPC", AD_GPIO_IPC, 16 },
326 { "OP", AD_GPIO_OP, 16 },
327 { "IP", AD_GPIO_IP, 16 },
328 { "ACIC", AD_AC97_ACIC, 16 },
329 { "AC97_RESET", AD_AC97_BASE + AC97_RESET, 16 },
330 { "AC97_MASTER_VOL_STEREO", AD_AC97_BASE + AC97_MASTER_VOL_STEREO, 16 },
331 { "AC97_HEADPHONE_VOL", AD_AC97_BASE + AC97_HEADPHONE_VOL, 16 },
332 { "AC97_MASTER_VOL_MONO", AD_AC97_BASE + AC97_MASTER_VOL_MONO, 16 },
333 { "AC97_MASTER_TONE", AD_AC97_BASE + AC97_MASTER_TONE, 16 },
334 { "AC97_PCBEEP_VOL", AD_AC97_BASE + AC97_PCBEEP_VOL, 16 },
335 { "AC97_PHONE_VOL", AD_AC97_BASE + AC97_PHONE_VOL, 16 },
336 { "AC97_MIC_VOL", AD_AC97_BASE + AC97_MIC_VOL, 16 },
337 { "AC97_LINEIN_VOL", AD_AC97_BASE + AC97_LINEIN_VOL, 16 },
338 { "AC97_CD_VOL", AD_AC97_BASE + AC97_CD_VOL, 16 },
339 { "AC97_VIDEO_VOL", AD_AC97_BASE + AC97_VIDEO_VOL, 16 },
340 { "AC97_AUX_VOL", AD_AC97_BASE + AC97_AUX_VOL, 16 },
341 { "AC97_PCMOUT_VOL", AD_AC97_BASE + AC97_PCMOUT_VOL, 16 },
342 { "AC97_RECORD_SELECT", AD_AC97_BASE + AC97_RECORD_SELECT, 16 },
343 { "AC97_RECORD_GAIN", AD_AC97_BASE + AC97_RECORD_GAIN, 16 },
344 { "AC97_RECORD_GAIN_MIC", AD_AC97_BASE + AC97_RECORD_GAIN_MIC, 16 },
345 { "AC97_GENERAL_PURPOSE", AD_AC97_BASE + AC97_GENERAL_PURPOSE, 16 },
346 { "AC97_3D_CONTROL", AD_AC97_BASE + AC97_3D_CONTROL, 16 },
347 { "AC97_MODEM_RATE", AD_AC97_BASE + AC97_MODEM_RATE, 16 },
348 { "AC97_POWER_CONTROL", AD_AC97_BASE + AC97_POWER_CONTROL, 16 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 { NULL }
350 };
351
352 if (dev == NULL)
353 return -ENODEV;
354
355 for (i = 0; regs[i].name != 0; i++)
356 out += sprintf(out, "%s: 0x%0*x\n", regs[i].name,
357 regs[i].width >> 2,
358 (regs[i].width == 16
359 ? AD1889_READW(dev, regs[i].offset)
360 : AD1889_READL(dev, regs[i].offset)));
361
362 for (i = 0; i < AD_MAX_STATES; i++) {
363 out += sprintf(out, "DMA status for %s:\n",
364 (i == AD_WAV_STATE ? "WAV" : "ADC"));
365 out += sprintf(out, "\t\t0x%p (IOVA: 0x%llu)\n",
366 dev->state[i].dmabuf.rawbuf,
367 (unsigned long long)dev->state[i].dmabuf.dma_handle);
368
369 out += sprintf(out, "\tread ptr: offset %u\n",
370 (unsigned int)dev->state[i].dmabuf.rd_ptr);
371 out += sprintf(out, "\twrite ptr: offset %u\n",
372 (unsigned int)dev->state[i].dmabuf.wr_ptr);
373 out += sprintf(out, "\tdma len: offset %u\n",
374 (unsigned int)dev->state[i].dmabuf.dma_len);
375 }
376
377 len = out - page - off;
378 if (len < count) {
379 *eof = 1;
380 if (len <= 0) return 0;
381 } else {
382 len = count;
383 }
384 *start = page + off;
385 return len;
386}
387
388/***************************** DMA interfaces ************************** */
389#if 0
390static inline unsigned long ad1889_get_dma_addr(ad1889_state_t *state)
391{
392 struct dmabuf *dmabuf = &state->dmabuf;
393 u32 offset;
394
395 if (!(dmabuf->enable & (DAC_RUNNING | ADC_RUNNING))) {
396 printk(KERN_ERR DEVNAME ": get_dma_addr called without dma enabled\n");
397 return 0;
398 }
399
400 if (dmabuf->enable & DAC_RUNNING)
Stuart Bradye74eb802005-03-01 23:00:56 +0000401 offset = le32_to_cpu(AD1889_READL(state->card, AD_DMA_WAVBA));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 else
Stuart Bradye74eb802005-03-01 23:00:56 +0000403 offset = le32_to_cpu(AD1889_READL(state->card, AD_DMA_ADCBA));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
405 return (unsigned long)bus_to_virt((unsigned long)offset) - (unsigned long)dmabuf->rawbuf;
406}
407
408static void ad1889_update_ptr(ad1889_dev_t *dev, int wake)
409{
410 ad1889_state_t *state;
411 struct dmabuf *dmabuf;
412 unsigned long hwptr;
413 int diff;
414
415 /* check ADC first */
416 state = &dev->adc_state;
417 dmabuf = &state->dmabuf;
418 if (dmabuf->enable & ADC_RUNNING) {
419 hwptr = ad1889_get_dma_addr(state);
420 diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
421
422 dmabuf->hwptr = hwptr;
423 dmabuf->total_bytes += diff;
424 dmabuf->count += diff;
425 if (dmabuf->count > dmabuf->dmasize)
426 dmabuf->count = dmabuf->dmasize;
427
428 if (dmabuf->mapped) {
429 if (wake & dmabuf->count >= dmabuf->fragsize)
430 wake_up(&dmabuf->wait);
431 } else {
432 if (wake & dmabuf->count > 0)
433 wake_up(&dmabuf->wait);
434 }
435 }
436
437 /* check DAC */
438 state = &dev->wav_state;
439 dmabuf = &state->dmabuf;
440 if (dmabuf->enable & DAC_RUNNING) {
441XXX
442
443}
444#endif
445
446/************************* /dev/dsp interfaces ************************* */
447
448static ssize_t ad1889_read(struct file *file, char __user *buffer, size_t count,
449 loff_t *ppos)
450{
451 return 0;
452}
453
454static ssize_t ad1889_write(struct file *file, const char __user *buffer, size_t count,
455 loff_t *ppos)
456{
457 ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
458 ad1889_state_t *state = &dev->state[AD_WAV_STATE];
459 volatile struct dmabuf *dmabuf = &state->dmabuf;
460 ssize_t ret = 0;
461 DECLARE_WAITQUEUE(wait, current);
462
Ingo Molnar910f5d22006-03-23 03:00:39 -0800463 mutex_lock(&state->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464#if 0
465 if (dmabuf->mapped) {
466 ret = -ENXIO;
467 goto err1;
468 }
469#endif
470 if (!access_ok(VERIFY_READ, buffer, count)) {
471 ret = -EFAULT;
472 goto err1;
473 }
474
475 add_wait_queue(&state->dmabuf.wait, &wait);
476
477 /* start filling dma buffer.... */
478 while (count > 0) {
479 long rem;
480 long cnt = count;
481 unsigned long flags;
482
483 for (;;) {
484 long used_bytes;
485 long timeout; /* max time for DMA in jiffies */
486
487 /* buffer is full if wr catches up to rd */
488 spin_lock_irqsave(&state->card->lock, flags);
489 used_bytes = dmabuf->wr_ptr - dmabuf->rd_ptr;
490 timeout = (dmabuf->dma_len * HZ) / dmabuf->rate;
491 spin_unlock_irqrestore(&state->card->lock, flags);
492
493 /* adjust for buffer wrap around */
494 used_bytes = (used_bytes + DMA_SIZE) & (DMA_SIZE - 1);
495
496 /* If at least one page unused */
497 if (used_bytes < (DMA_SIZE - 0x1000))
498 break;
499
500 /* dma buffer full */
501
502 if (file->f_flags & O_NONBLOCK) {
503 ret = -EAGAIN;
504 goto err2;
505 }
506
507 set_current_state(TASK_INTERRUPTIBLE);
508 schedule_timeout(timeout + 1);
509 if (signal_pending(current)) {
510 ret = -ERESTARTSYS;
511 goto err2;
512 }
513 }
514
515 /* watch out for wrapping around static buffer */
516 spin_lock_irqsave(&state->card->lock, flags);
517 rem = DMA_SIZE - dmabuf->wr_ptr;
518 if (cnt > rem)
519 cnt = rem;
520
521 rem = dmabuf->wr_ptr;
522
523 /* update dma pointers */
524 dmabuf->wr_ptr += cnt;
525 dmabuf->wr_ptr &= DMA_SIZE - 1; /* wrap ptr if necessary */
526 spin_unlock_irqrestore(&state->card->lock, flags);
527
528 /* transfer unwrapped chunk */
529 if (copy_from_user(dmabuf->rawbuf + rem, buffer, cnt)) {
530 ret = -EFAULT;
531 goto err2;
532 }
533
534 DBG("Writing 0x%lx bytes to +0x%lx\n", cnt, rem);
535
536 /* update counters */
537 count -= cnt;
538 buffer += cnt;
539 ret += cnt;
540
541 /* we have something to play - go play it! */
542 ad1889_trigger_playback(dev);
543 }
544
545err2:
546 remove_wait_queue(&state->dmabuf.wait, &wait);
547err1:
Ingo Molnar910f5d22006-03-23 03:00:39 -0800548 mutex_unlock(&state->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 return ret;
550}
551
552static unsigned int ad1889_poll(struct file *file, struct poll_table_struct *wait)
553{
554 unsigned int mask = 0;
555#if 0
556 ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
557 ad1889_state_t *state = NULL;
558 struct dmabuf *dmabuf;
559 unsigned long flags;
560
561 if (!(file->f_mode & (FMODE_READ | FMODE_WRITE)))
562 return -EINVAL;
563
564 if (file->f_mode & FMODE_WRITE) {
565 state = &dev->state[AD_WAV_STATE];
566 if (!state) return 0;
567 dmabuf = &state->dmabuf;
568 poll_wait(file, &dmabuf->wait, wait);
569 }
570
571 if (file->f_mode & FMODE_READ) {
572 state = &dev->state[AD_ADC_STATE];
573 if (!state) return 0;
574 dmabuf = &state->dmabuf;
575 poll_wait(file, &dmabuf->wait, wait);
576 }
577
578 spin_lock_irqsave(&dev->lock, flags);
579 ad1889_update_ptr(dev, 0);
580
581 if (file->f_mode & FMODE_WRITE) {
582 state = &dev->state[WAV_STATE];
583 dmabuf = &state->dmabuf;
584 if (dmabuf->mapped) {
585 if (dmabuf->count >= (int)dmabuf->fragsize)
586 mask |= POLLOUT | POLLWRNORM;
587 } else {
588 if ((int)dmabuf->dmasize >= dmabuf->count +
589 (int)dmabuf->fragsize)
590 mask |= POLLOUT | POLLWRNORM;
591 }
592 }
593
594 if (file ->f_mode & FMODE_READ) {
595 state = &dev->state[AD_ADC_STATE];
596 dmabuf = &state->dmabuf;
597 if (dmabuf->count >= (int)dmabuf->fragsize)
598 mask |= POLLIN | POLLRDNORM;
599 }
600 spin_unlock_irqrestore(&dev->lock, flags);
601
602#endif
603 return mask;
604}
605
606static int ad1889_mmap(struct file *file, struct vm_area_struct *vma)
607{
608 return 0;
609}
610
611static int ad1889_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
612 unsigned long arg)
613{
614 int val = 0;
615 ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
616 struct dmabuf *dmabuf;
617 audio_buf_info abinfo;
618 int __user *p = (int __user *)arg;
619
620 DBG("ad1889_ioctl cmd 0x%x arg %lu\n", cmd, arg);
621
622 switch (cmd)
623 {
624 case OSS_GETVERSION:
625 return put_user(SOUND_VERSION, p);
626
627 case SNDCTL_DSP_RESET:
628 break;
629
630 case SNDCTL_DSP_SYNC:
631 break;
632
633 case SNDCTL_DSP_SPEED:
634 /* set sampling rate */
635 if (get_user(val, p))
636 return -EFAULT;
637 if (val > 5400 && val < 48000)
638 {
639 if (file->f_mode & FMODE_WRITE)
Stuart Bradye74eb802005-03-01 23:00:56 +0000640 AD1889_WRITEW(ad1889_dev, AD_DS_WAS, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 if (file->f_mode & FMODE_READ)
Stuart Bradye74eb802005-03-01 23:00:56 +0000642 AD1889_WRITEW(ad1889_dev, AD_DS_RES, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 }
644 return 0;
645
646 case SNDCTL_DSP_STEREO: /* undocumented? */
647 if (get_user(val, p))
648 return -EFAULT;
649 if (file->f_mode & FMODE_READ) {
Stuart Bradye74eb802005-03-01 23:00:56 +0000650 val = AD1889_READW(ad1889_dev, AD_DS_WSMC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 if (val) {
652 val |= 0x0200; /* set WAST */
653 } else {
654 val &= ~0x0200; /* clear WAST */
655 }
Stuart Bradye74eb802005-03-01 23:00:56 +0000656 AD1889_WRITEW(ad1889_dev, AD_DS_WSMC, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 }
658 if (file->f_mode & FMODE_WRITE) {
Stuart Bradye74eb802005-03-01 23:00:56 +0000659 val = AD1889_READW(ad1889_dev, AD_DS_RAMC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 if (val) {
661 val |= 0x0002; /* set ADST */
662 } else {
663 val &= ~0x0002; /* clear ADST */
664 }
Stuart Bradye74eb802005-03-01 23:00:56 +0000665 AD1889_WRITEW(ad1889_dev, AD_DS_RAMC, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 }
667
668 return 0;
669
670 case SNDCTL_DSP_GETBLKSIZE:
671 return put_user(DMA_SIZE, p);
672
673 case SNDCTL_DSP_GETFMTS:
674 return put_user(AFMT_S16_LE|AFMT_U8, p);
675
676 case SNDCTL_DSP_SETFMT:
677 if (get_user(val, p))
678 return -EFAULT;
679
680 if (val == 0) {
681 if (file->f_mode & FMODE_READ)
682 ad1889_set_adc_fmt(dev, val);
683
684 if (file->f_mode & FMODE_WRITE)
685 ad1889_set_wav_fmt(dev, val);
686 } else {
687 val = AFMT_S16_LE | AFMT_U8;
688 }
689
690 return put_user(val, p);
691
692 case SNDCTL_DSP_CHANNELS:
693 break;
694
695 case SNDCTL_DSP_POST:
696 /* send all data to device */
697 break;
698
699 case SNDCTL_DSP_SUBDIVIDE:
700 break;
701
702 case SNDCTL_DSP_SETFRAGMENT:
703 /* not supported; uses fixed fragment sizes */
704 return put_user(DMA_SIZE, p);
705
706 case SNDCTL_DSP_GETOSPACE:
707 case SNDCTL_DSP_GETISPACE:
708 /* space left in dma buffers */
709 if (cmd == SNDCTL_DSP_GETOSPACE)
710 dmabuf = &dev->state[AD_WAV_STATE].dmabuf;
711 else
712 dmabuf = &dev->state[AD_ADC_STATE].dmabuf;
713 abinfo.fragments = 1;
714 abinfo.fragstotal = 1;
715 abinfo.fragsize = DMA_SIZE;
716 abinfo.bytes = DMA_SIZE;
717 return copy_to_user(p, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
718 case SNDCTL_DSP_NONBLOCK:
719 file->f_flags |= O_NONBLOCK;
720 return 0;
721
722 case SNDCTL_DSP_GETCAPS:
723 return put_user(0, p);
724
725 case SNDCTL_DSP_GETTRIGGER:
726 case SNDCTL_DSP_SETTRIGGER:
727 break;
728
729 case SNDCTL_DSP_GETIPTR:
730 case SNDCTL_DSP_GETOPTR:
731 break;
732
733 case SNDCTL_DSP_SETDUPLEX:
734 break;
735
736 case SNDCTL_DSP_GETODELAY:
737 break;
738
739 case SOUND_PCM_READ_RATE:
Stuart Bradye74eb802005-03-01 23:00:56 +0000740 return put_user(AD1889_READW(ad1889_dev, AD_DS_WAS), p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
742 case SOUND_PCM_READ_CHANNELS:
743 case SOUND_PCM_READ_BITS:
744 break;
745
746 case SNDCTL_DSP_MAPINBUF:
747 case SNDCTL_DSP_MAPOUTBUF:
748 case SNDCTL_DSP_SETSYNCRO:
749 case SOUND_PCM_WRITE_FILTER:
750 case SOUND_PCM_READ_FILTER:
751 break;
752
753 default:
754 break;
755 }
756
757 return -ENOTTY;
758}
759
760static int ad1889_open(struct inode *inode, struct file *file)
761{
762 /* check minor; only support /dev/dsp atm */
763 if (iminor(inode) != 3)
764 return -ENXIO;
765
766 file->private_data = ad1889_dev;
767
768 ad1889_set_wav_rate(ad1889_dev, 48000);
769 ad1889_set_wav_fmt(ad1889_dev, AFMT_S16_LE);
Stuart Bradye74eb802005-03-01 23:00:56 +0000770 AD1889_WRITEW(ad1889_dev, AD_DS_WADA, 0x0404); /* attenuation */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 return nonseekable_open(inode, file);
772}
773
774static int ad1889_release(struct inode *inode, struct file *file)
775{
776 /* if we have state free it here */
777 return 0;
778}
779
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800780static const struct file_operations ad1889_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 .owner = THIS_MODULE,
782 .llseek = no_llseek,
783 .read = ad1889_read,
784 .write = ad1889_write,
785 .poll = ad1889_poll,
786 .ioctl = ad1889_ioctl,
787 .mmap = ad1889_mmap,
788 .open = ad1889_open,
789 .release = ad1889_release,
790};
791
792/************************* /dev/mixer interfaces ************************ */
793static int ad1889_mixer_open(struct inode *inode, struct file *file)
794{
795 if (ad1889_dev->ac97_codec->dev_mixer != iminor(inode))
796 return -ENODEV;
797
798 file->private_data = ad1889_dev->ac97_codec;
799 return 0;
800}
801
802static int ad1889_mixer_release(struct inode *inode, struct file *file)
803{
804 return 0;
805}
806
807static int ad1889_mixer_ioctl(struct inode *inode, struct file *file,
808 unsigned int cmd, unsigned long arg)
809{
810 struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
811 return codec->mixer_ioctl(codec, cmd, arg);
812}
813
Arjan van de Ven9c2e08c2007-02-12 00:55:37 -0800814static const struct file_operations ad1889_mixer_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 .owner = THIS_MODULE,
816 .llseek = no_llseek,
817 .ioctl = ad1889_mixer_ioctl,
818 .open = ad1889_mixer_open,
819 .release = ad1889_mixer_release,
820};
821
822/************************* AC97 interfaces ****************************** */
823static void ad1889_codec_write(struct ac97_codec *ac97, u8 reg, u16 val)
824{
825 ad1889_dev_t *dev = ac97->private_data;
826
Stuart Bradye74eb802005-03-01 23:00:56 +0000827 //DBG("Writing 0x%x to 0x%lx\n", val, dev->regbase + AD_AC97_BASE + reg);
828 AD1889_WRITEW(dev, AD_AC97_BASE + reg, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829}
830
831static u16 ad1889_codec_read(struct ac97_codec *ac97, u8 reg)
832{
833 ad1889_dev_t *dev = ac97->private_data;
Stuart Bradye74eb802005-03-01 23:00:56 +0000834 //DBG("Reading from 0x%lx\n", dev->regbase + AD_AC97_BASE + reg);
835 return AD1889_READW(dev, AD_AC97_BASE + reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836}
837
838static int ad1889_ac97_init(ad1889_dev_t *dev, int id)
839{
840 struct ac97_codec *ac97;
841 u16 eid;
842
843 if ((ac97 = ac97_alloc_codec()) == NULL)
844 return -ENOMEM;
845
846 ac97->private_data = dev;
847 ac97->id = id;
848
849 ac97->codec_read = ad1889_codec_read;
850 ac97->codec_write = ad1889_codec_write;
851
852 if (ac97_probe_codec(ac97) == 0) {
853 printk(DEVNAME ": ac97_probe_codec failed\n");
854 goto out_free;
855 }
856
857 eid = ad1889_codec_read(ac97, AC97_EXTENDED_ID);
858 if (eid == 0xffff) {
859 printk(KERN_WARNING DEVNAME ": no codec attached?\n");
860 goto out_free;
861 }
862
863 dev->ac97_features = eid;
864
865 if ((ac97->dev_mixer = register_sound_mixer(&ad1889_mixer_fops, -1)) < 0) {
866 printk(KERN_ERR DEVNAME ": cannot register mixer\n");
867 goto out_free;
868 }
869
870 dev->ac97_codec = ac97;
871 return 0;
872
873out_free:
874 ac97_release_codec(ac97);
875 return -ENODEV;
876}
877
878static int ad1889_aclink_reset(struct pci_dev * pcidev)
879{
880 u16 stat;
881 int retry = 200;
882 ad1889_dev_t *dev = pci_get_drvdata(pcidev);
883
Stuart Bradye74eb802005-03-01 23:00:56 +0000884 AD1889_WRITEW(dev, AD_DS_CCS, 0x8000); /* turn on clock */
885 AD1889_READW(dev, AD_DS_CCS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
887 WAIT_10MS();
888
Stuart Bradye74eb802005-03-01 23:00:56 +0000889 stat = AD1889_READW(dev, AD_AC97_ACIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 stat |= 0x0002; /* Reset Disable */
Stuart Bradye74eb802005-03-01 23:00:56 +0000891 AD1889_WRITEW(dev, AD_AC97_ACIC, stat);
892 (void) AD1889_READW(dev, AD_AC97_ACIC); /* flush posted write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
894 udelay(10);
895
Stuart Bradye74eb802005-03-01 23:00:56 +0000896 stat = AD1889_READW(dev, AD_AC97_ACIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 stat |= 0x0001; /* Interface Enable */
Stuart Bradye74eb802005-03-01 23:00:56 +0000898 AD1889_WRITEW(dev, AD_AC97_ACIC, stat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899
900 do {
Stuart Bradye74eb802005-03-01 23:00:56 +0000901 if (AD1889_READW(dev, AD_AC97_ACIC) & 0x8000) /* Ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 break;
903 WAIT_10MS();
904 retry--;
905 } while (retry > 0);
906
907 if (!retry) {
908 printk(KERN_ERR "ad1889_aclink_reset: codec is not ready [0x%x]\n",
Stuart Bradye74eb802005-03-01 23:00:56 +0000909 AD1889_READW(dev, AD_AC97_ACIC));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 return -EBUSY;
911 }
912
913 /* TODO reset AC97 codec */
914 /* TODO set wave/adc pci ctrl status */
915
Stuart Bradye74eb802005-03-01 23:00:56 +0000916 stat = AD1889_READW(dev, AD_AC97_ACIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 stat |= 0x0004; /* Audio Stream Output Enable */
Stuart Bradye74eb802005-03-01 23:00:56 +0000918 AD1889_WRITEW(dev, AD_AC97_ACIC, stat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 return 0;
920}
921
922/************************* PCI interfaces ****************************** */
923/* PCI device table */
924static struct pci_device_id ad1889_id_tbl[] = {
925 { PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS, PCI_ANY_ID,
926 PCI_ANY_ID, 0, 0, (unsigned long)DEVNAME },
927 { },
928};
929MODULE_DEVICE_TABLE(pci, ad1889_id_tbl);
930
David Howells7d12e782006-10-05 14:55:46 +0100931static irqreturn_t ad1889_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932{
933 u32 stat;
934 ad1889_dev_t *dev = (ad1889_dev_t *)dev_id;
935
Stuart Bradye74eb802005-03-01 23:00:56 +0000936 stat = AD1889_READL(dev, AD_DMA_DISR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
938 /* clear ISR */
Stuart Bradye74eb802005-03-01 23:00:56 +0000939 AD1889_WRITEL(dev, AD_DMA_DISR, stat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
941 if (stat & 0x8) { /* WAVI */
942 DBG("WAV interrupt\n");
943 dev->stats.wav_intrs++;
944 if (dev->state[AD_WAV_STATE].dmabuf.ready) {
945 ad1889_stop_wav(&dev->state[AD_WAV_STATE]); /* clean up */
946 ad1889_start_wav(&dev->state[AD_WAV_STATE]); /* start new */
947 }
948 }
949
950 if ((stat & 0x2) && dev->state[AD_ADC_STATE].dmabuf.ready) { /* ADCI */
951 DBG("ADC interrupt\n");
952 dev->stats.adc_intrs++;
953 }
954 if(stat)
955 return IRQ_HANDLED;
956 return IRQ_NONE;
957}
958
959static void ad1889_initcfg(ad1889_dev_t *dev)
960{
961 u16 tmp16;
962 u32 tmp32;
963
964 /* make sure the interrupt bits are setup the way we want */
Stuart Bradye74eb802005-03-01 23:00:56 +0000965 tmp32 = AD1889_READL(dev, AD_DMA_WAVCTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 tmp32 &= ~0xff; /* flat dma, no sg, mask out the intr bits */
967 tmp32 |= 0x6; /* intr on count, loop */
Stuart Bradye74eb802005-03-01 23:00:56 +0000968 AD1889_WRITEL(dev, AD_DMA_WAVCTRL, tmp32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
970 /* unmute... */
Stuart Bradye74eb802005-03-01 23:00:56 +0000971 tmp16 = AD1889_READW(dev, AD_DS_WADA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 tmp16 &= ~0x8080;
Stuart Bradye74eb802005-03-01 23:00:56 +0000973 AD1889_WRITEW(dev, AD_DS_WADA, tmp16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974}
975
976static int __devinit ad1889_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
977{
978 int err;
979 ad1889_dev_t *dev;
980 unsigned long bar;
981 struct proc_dir_entry *proc_root = NULL;
982
983 if ((err = pci_enable_device(pcidev)) != 0) {
984 printk(KERN_ERR DEVNAME ": pci_enable_device failed\n");
985 return err;
986 }
987
988 pci_set_master(pcidev);
989 if ((dev = ad1889_alloc_dev(pcidev)) == NULL) {
990 printk(KERN_ERR DEVNAME ": cannot allocate memory for device\n");
991 return -ENOMEM;
992 }
993 pci_set_drvdata(pcidev, dev);
994 bar = pci_resource_start(pcidev, 0);
995
996 if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM)) {
997 printk(KERN_ERR DEVNAME ": memory region not assigned\n");
998 goto out1;
999 }
1000
1001 if (pci_request_region(pcidev, 0, DEVNAME)) {
1002 printk(KERN_ERR DEVNAME ": unable to request memory region\n");
1003 goto out1;
1004 }
1005
Stuart Bradye74eb802005-03-01 23:00:56 +00001006 dev->regbase = ioremap_nocache(bar, AD_DS_IOMEMSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 if (!dev->regbase) {
1008 printk(KERN_ERR DEVNAME ": unable to remap iomem\n");
1009 goto out2;
1010 }
1011
Thomas Gleixner65ca68b2006-07-01 19:29:46 -07001012 if (request_irq(pcidev->irq, ad1889_interrupt, IRQF_SHARED, DEVNAME, dev) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 printk(KERN_ERR DEVNAME ": unable to request interrupt\n");
1014 goto out3;
1015 }
1016
1017 printk(KERN_INFO DEVNAME ": %s at %p IRQ %d\n",
1018 (char *)ent->driver_data, dev->regbase, pcidev->irq);
1019
1020 if (ad1889_aclink_reset(pcidev) != 0)
1021 goto out4;
1022
1023 /* register /dev/dsp */
1024 if ((dev->dev_audio = register_sound_dsp(&ad1889_fops, -1)) < 0) {
1025 printk(KERN_ERR DEVNAME ": cannot register /dev/dsp\n");
1026 goto out4;
1027 }
1028
1029 if ((err = ad1889_ac97_init(dev, 0)) != 0)
1030 goto out5;
1031
1032 /* XXX: cleanups */
1033 if (((proc_root = proc_mkdir("driver/ad1889", NULL)) == NULL) ||
1034 create_proc_read_entry("ac97", S_IFREG|S_IRUGO, proc_root, ac97_read_proc, dev->ac97_codec) == NULL ||
1035 create_proc_read_entry("info", S_IFREG|S_IRUGO, proc_root, ad1889_read_proc, dev) == NULL)
1036 goto out5;
1037
1038 ad1889_initcfg(dev);
1039
1040 //DBG(DEVNAME ": Driver initialization done!\n");
1041
1042 ad1889_dev = dev;
1043
1044 return 0;
1045
1046out5:
1047 unregister_sound_dsp(dev->dev_audio);
1048out4:
1049 free_irq(pcidev->irq, dev);
1050out3:
1051 iounmap(dev->regbase);
1052out2:
1053 pci_release_region(pcidev, 0);
1054out1:
1055 ad1889_free_dev(dev);
1056 pci_set_drvdata(pcidev, NULL);
1057
1058 return -ENODEV;
1059}
1060
1061static void __devexit ad1889_remove(struct pci_dev *pcidev)
1062{
1063 ad1889_dev_t *dev = pci_get_drvdata(pcidev);
1064
1065 if (dev == NULL) return;
1066
1067 unregister_sound_mixer(dev->ac97_codec->dev_mixer);
1068 unregister_sound_dsp(dev->dev_audio);
1069 free_irq(pcidev->irq, dev);
1070 iounmap(dev->regbase);
1071 pci_release_region(pcidev, 0);
1072
1073 /* any hw programming needed? */
1074 ad1889_free_dev(dev);
1075 pci_set_drvdata(pcidev, NULL);
1076}
1077
1078MODULE_AUTHOR("Randolph Chung");
1079MODULE_DESCRIPTION("Analog Devices AD1889 PCI Audio");
1080MODULE_LICENSE("GPL");
1081
1082static struct pci_driver ad1889_driver = {
1083 .name = DEVNAME,
1084 .id_table = ad1889_id_tbl,
1085 .probe = ad1889_probe,
1086 .remove = __devexit_p(ad1889_remove),
1087};
1088
1089static int __init ad1889_init_module(void)
1090{
Greg Kroah-Hartman46654722005-12-06 15:33:15 -08001091 return pci_register_driver(&ad1889_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092}
1093
1094static void ad1889_exit_module(void)
1095{
1096 pci_unregister_driver(&ad1889_driver);
1097 return;
1098}
1099
1100module_init(ad1889_init_module);
1101module_exit(ad1889_exit_module);