Rename sprintf -> ksprintf
[dragonfly.git] / sys / dev / sound / isa / ad1816.c
1 /*
2  * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
3  * Copyright Luigi Rizzo, 1997,1998
4  * Copyright by Hannu Savolainen 1994, 1995
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/dev/sound/isa/ad1816.c,v 1.7.2.9 2002/12/24 21:17:41 semenu Exp $
29  * $DragonFly: src/sys/dev/sound/isa/ad1816.c,v 1.5 2006/12/20 18:14:40 dillon Exp $
30  */
31
32 #include <dev/sound/pcm/sound.h>
33 #include <dev/sound/isa/ad1816.h>
34
35 #include "mixer_if.h"
36
37 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/isa/ad1816.c,v 1.5 2006/12/20 18:14:40 dillon Exp $");
38
39 struct ad1816_info;
40
41 struct ad1816_chinfo {
42         struct ad1816_info *parent;
43         struct pcm_channel *channel;
44         struct snd_dbuf *buffer;
45         int dir, blksz;
46 };
47
48 struct ad1816_info {
49         struct resource *io_base;       /* primary I/O address for the board */
50         int io_rid;
51         struct resource *irq;
52         int irq_rid;
53         struct resource *drq1;          /* play */
54         int drq1_rid;
55         struct resource *drq2;          /* rec */
56         int drq2_rid;
57         void *ih;
58         bus_dma_tag_t parent_dmat;
59         void *lock;
60
61         unsigned int bufsize;
62         struct ad1816_chinfo pch, rch;
63 };
64
65 static u_int32_t ad1816_fmt[] = {
66         AFMT_U8,
67         AFMT_STEREO | AFMT_U8,
68         AFMT_S16_LE,
69         AFMT_STEREO | AFMT_S16_LE,
70         AFMT_MU_LAW,
71         AFMT_STEREO | AFMT_MU_LAW,
72         AFMT_A_LAW,
73         AFMT_STEREO | AFMT_A_LAW,
74         0
75 };
76
77 static struct pcmchan_caps ad1816_caps = {4000, 55200, ad1816_fmt, 0};
78
79 #define AD1816_MUTE 31          /* value for mute */
80
81 static void
82 ad1816_lock(struct ad1816_info *ad1816)
83 {
84         snd_mtxlock(ad1816->lock);
85 }
86
87 static void
88 ad1816_unlock(struct ad1816_info *ad1816)
89 {
90         snd_mtxunlock(ad1816->lock);
91 }
92
93 static int
94 port_rd(struct resource *port, int off)
95 {
96         if (port)
97                 return bus_space_read_1(rman_get_bustag(port),
98                                         rman_get_bushandle(port),
99                                         off);
100         else
101                 return -1;
102 }
103
104 static void
105 port_wr(struct resource *port, int off, u_int8_t data)
106 {
107         if (port)
108                 bus_space_write_1(rman_get_bustag(port),
109                                   rman_get_bushandle(port),
110                                   off, data);
111 }
112
113 static int
114 io_rd(struct ad1816_info *ad1816, int reg)
115 {
116         return port_rd(ad1816->io_base, reg);
117 }
118
119 static void
120 io_wr(struct ad1816_info *ad1816, int reg, u_int8_t data)
121 {
122         port_wr(ad1816->io_base, reg, data);
123 }
124
125 static void
126 ad1816_intr(void *arg)
127 {
128         struct ad1816_info *ad1816 = (struct ad1816_info *)arg;
129         unsigned char   c, served = 0;
130
131         ad1816_lock(ad1816);
132         /* get interupt status */
133         c = io_rd(ad1816, AD1816_INT);
134
135         /* check for stray interupts */
136         if (c & ~(AD1816_INTRCI | AD1816_INTRPI)) {
137                 printf("pcm: stray int (%x)\n", c);
138                 c &= AD1816_INTRCI | AD1816_INTRPI;
139         }
140         /* check for capture interupt */
141         if (sndbuf_runsz(ad1816->rch.buffer) && (c & AD1816_INTRCI)) {
142                 chn_intr(ad1816->rch.channel);
143                 served |= AD1816_INTRCI;                /* cp served */
144         }
145         /* check for playback interupt */
146         if (sndbuf_runsz(ad1816->pch.buffer) && (c & AD1816_INTRPI)) {
147                 chn_intr(ad1816->pch.channel);
148                 served |= AD1816_INTRPI;                /* pb served */
149         }
150         if (served == 0) {
151                 /* this probably means this is not a (working) ad1816 chip, */
152                 /* or an error in dma handling                              */
153                 printf("pcm: int without reason (%x)\n", c);
154                 c = 0;
155         } else c &= ~served;
156         io_wr(ad1816, AD1816_INT, c);
157         c = io_rd(ad1816, AD1816_INT);
158         if (c != 0) printf("pcm: int clear failed (%x)\n", c);
159         ad1816_unlock(ad1816);
160 }
161
162 static int
163 ad1816_wait_init(struct ad1816_info *ad1816, int x)
164 {
165         int             n = 0;  /* to shut up the compiler... */
166
167         for (; x--;)
168                 if ((n = (io_rd(ad1816, AD1816_ALE) & AD1816_BUSY)) == 0) DELAY(10);
169                 else return n;
170         printf("ad1816_wait_init failed 0x%02x.\n", n);
171         return -1;
172 }
173
174 static unsigned short
175 ad1816_read(struct ad1816_info *ad1816, unsigned int reg)
176 {
177         u_short         x = 0;
178
179         if (ad1816_wait_init(ad1816, 100) == -1) return 0;
180         io_wr(ad1816, AD1816_ALE, 0);
181         io_wr(ad1816, AD1816_ALE, (reg & AD1816_ALEMASK));
182         if (ad1816_wait_init(ad1816, 100) == -1) return 0;
183         x = (io_rd(ad1816, AD1816_HIGH) << 8) | io_rd(ad1816, AD1816_LOW);
184         return x;
185 }
186
187 static void
188 ad1816_write(struct ad1816_info *ad1816, unsigned int reg, unsigned short data)
189 {
190         if (ad1816_wait_init(ad1816, 100) == -1) return;
191         io_wr(ad1816, AD1816_ALE, (reg & AD1816_ALEMASK));
192         io_wr(ad1816, AD1816_LOW,  (data & 0x000000ff));
193         io_wr(ad1816, AD1816_HIGH, (data & 0x0000ff00) >> 8);
194 }
195
196 /* -------------------------------------------------------------------- */
197
198 static int
199 ad1816mix_init(struct snd_mixer *m)
200 {
201         mix_setdevs(m, AD1816_MIXER_DEVICES);
202         mix_setrecdevs(m, AD1816_REC_DEVICES);
203         return 0;
204 }
205
206 static int
207 ad1816mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
208 {
209         struct ad1816_info *ad1816 = mix_getdevinfo(m);
210         u_short reg = 0;
211
212         /* Scale volumes */
213         left = AD1816_MUTE - (AD1816_MUTE * left) / 100;
214         right = AD1816_MUTE - (AD1816_MUTE * right) / 100;
215
216         reg = (left << 8) | right;
217
218         /* do channel selective muting if volume is zero */
219         if (left == AD1816_MUTE)        reg |= 0x8000;
220         if (right == AD1816_MUTE)       reg |= 0x0080;
221
222         ad1816_lock(ad1816);
223         switch (dev) {
224         case SOUND_MIXER_VOLUME:        /* Register 14 master volume */
225                 ad1816_write(ad1816, 14, reg);
226                 break;
227
228         case SOUND_MIXER_CD:    /* Register 15 cd */
229         case SOUND_MIXER_LINE1:
230                 ad1816_write(ad1816, 15, reg);
231                 break;
232
233         case SOUND_MIXER_SYNTH: /* Register 16 synth */
234                 ad1816_write(ad1816, 16, reg);
235                 break;
236
237         case SOUND_MIXER_PCM:   /* Register 4 pcm */
238                 ad1816_write(ad1816, 4, reg);
239                 break;
240
241         case SOUND_MIXER_LINE:
242         case SOUND_MIXER_LINE3: /* Register 18 line in */
243                 ad1816_write(ad1816, 18, reg);
244                 break;
245
246         case SOUND_MIXER_MIC:   /* Register 19 mic volume */
247                 ad1816_write(ad1816, 19, reg & ~0xff);  /* mic is mono */
248                 break;
249
250         case SOUND_MIXER_IGAIN:
251                 /* and now to something completely different ... */
252                 ad1816_write(ad1816, 20, ((ad1816_read(ad1816, 20) & ~0x0f0f)
253                 | (((AD1816_MUTE - left) / 2) << 8) /* four bits of adc gain */
254                 | ((AD1816_MUTE - right) / 2)));
255                 break;
256
257         default:
258                 printf("ad1816_mixer_set(): unknown device.\n");
259                 break;
260         }
261         ad1816_unlock(ad1816);
262
263         left = ((AD1816_MUTE - left) * 100) / AD1816_MUTE;
264         right = ((AD1816_MUTE - right) * 100) / AD1816_MUTE;
265
266         return left | (right << 8);
267 }
268
269 static int
270 ad1816mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
271 {
272         struct ad1816_info *ad1816 = mix_getdevinfo(m);
273         int dev;
274
275         switch (src) {
276         case SOUND_MASK_LINE:
277         case SOUND_MASK_LINE3:
278                 dev = 0x00;
279                 break;
280
281         case SOUND_MASK_CD:
282         case SOUND_MASK_LINE1:
283                 dev = 0x20;
284                 break;
285
286         case SOUND_MASK_MIC:
287         default:
288                 dev = 0x50;
289                 src = SOUND_MASK_MIC;
290         }
291
292         dev |= dev << 8;
293         ad1816_lock(ad1816);
294         ad1816_write(ad1816, 20, (ad1816_read(ad1816, 20) & ~0x7070) | dev);
295         ad1816_unlock(ad1816);
296         return src;
297 }
298
299 static kobj_method_t ad1816mixer_methods[] = {
300         KOBJMETHOD(mixer_init,          ad1816mix_init),
301         KOBJMETHOD(mixer_set,           ad1816mix_set),
302         KOBJMETHOD(mixer_setrecsrc,     ad1816mix_setrecsrc),
303         { 0, 0 }
304 };
305 MIXER_DECLARE(ad1816mixer);
306
307 /* -------------------------------------------------------------------- */
308 /* channel interface */
309 static void *
310 ad1816chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
311 {
312         struct ad1816_info *ad1816 = devinfo;
313         struct ad1816_chinfo *ch = (dir == PCMDIR_PLAY)? &ad1816->pch : &ad1816->rch;
314
315         ch->parent = ad1816;
316         ch->channel = c;
317         ch->buffer = b;
318         if (sndbuf_alloc(ch->buffer, ad1816->parent_dmat, ad1816->bufsize) == -1) return NULL;
319         return ch;
320 }
321
322 static int
323 ad1816chan_setdir(kobj_t obj, void *data, int dir)
324 {
325         struct ad1816_chinfo *ch = data;
326         struct ad1816_info *ad1816 = ch->parent;
327
328         sndbuf_isadmasetup(ch->buffer, (dir == PCMDIR_PLAY)? ad1816->drq1 : ad1816->drq2);
329         ch->dir = dir;
330         return 0;
331 }
332
333 static int
334 ad1816chan_setformat(kobj_t obj, void *data, u_int32_t format)
335 {
336         struct ad1816_chinfo *ch = data;
337         struct ad1816_info *ad1816 = ch->parent;
338         int fmt = AD1816_U8, reg;
339
340         ad1816_lock(ad1816);
341         if (ch->dir == PCMDIR_PLAY) {
342                 reg = AD1816_PLAY;
343                 ad1816_write(ad1816, 8, 0x0000);        /* reset base and current counter */
344                 ad1816_write(ad1816, 9, 0x0000);        /* for playback and capture */
345         } else {
346                 reg = AD1816_CAPT;
347                 ad1816_write(ad1816, 10, 0x0000);
348                 ad1816_write(ad1816, 11, 0x0000);
349         }
350         switch (format & ~AFMT_STEREO) {
351         case AFMT_A_LAW:
352                 fmt = AD1816_ALAW;
353                 break;
354
355         case AFMT_MU_LAW:
356                 fmt = AD1816_MULAW;
357                 break;
358
359         case AFMT_S16_LE:
360                 fmt = AD1816_S16LE;
361                 break;
362
363         case AFMT_S16_BE:
364                 fmt = AD1816_S16BE;
365                 break;
366
367         case AFMT_U8:
368                 fmt = AD1816_U8;
369                 break;
370         }
371         if (format & AFMT_STEREO) fmt |= AD1816_STEREO;
372         io_wr(ad1816, reg, fmt);
373         ad1816_unlock(ad1816);
374
375         return (0);
376 }
377
378 static int
379 ad1816chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
380 {
381         struct ad1816_chinfo *ch = data;
382         struct ad1816_info *ad1816 = ch->parent;
383
384         RANGE(speed, 4000, 55200);
385         ad1816_lock(ad1816);
386         ad1816_write(ad1816, (ch->dir == PCMDIR_PLAY)? 2 : 3, speed);
387         ad1816_unlock(ad1816);
388         return speed;
389 }
390
391 static int
392 ad1816chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
393 {
394         struct ad1816_chinfo *ch = data;
395
396         ch->blksz = blocksize;
397         return ch->blksz;
398 }
399
400 static int
401 ad1816chan_trigger(kobj_t obj, void *data, int go)
402 {
403         struct ad1816_chinfo *ch = data;
404         struct ad1816_info *ad1816 = ch->parent;
405         int wr, reg;
406
407         if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
408                 return 0;
409
410         sndbuf_isadma(ch->buffer, go);
411         wr = (ch->dir == PCMDIR_PLAY);
412         reg = wr? AD1816_PLAY : AD1816_CAPT;
413         ad1816_lock(ad1816);
414         switch (go) {
415         case PCMTRIG_START:
416                 /* start only if not already running */
417                 if (!(io_rd(ad1816, reg) & AD1816_ENABLE)) {
418                         int cnt = ((ch->blksz) >> 2) - 1;
419                         ad1816_write(ad1816, wr? 8 : 10, cnt); /* count */
420                         ad1816_write(ad1816, wr? 9 : 11, 0); /* reset cur cnt */
421                         ad1816_write(ad1816, 1, ad1816_read(ad1816, 1) |
422                                      (wr? 0x8000 : 0x4000)); /* enable int */
423                         /* enable playback */
424                         io_wr(ad1816, reg, io_rd(ad1816, reg) | AD1816_ENABLE);
425                         if (!(io_rd(ad1816, reg) & AD1816_ENABLE))
426                                 printf("ad1816: failed to start %s DMA!\n",
427                                        wr? "play" : "rec");
428                 }
429                 break;
430
431         case PCMTRIG_STOP:
432         case PCMTRIG_ABORT:             /* XXX check this... */
433                 /* we don't test here if it is running... */
434                 if (wr) {
435                         ad1816_write(ad1816, 1, ad1816_read(ad1816, 1) &
436                                      ~(wr? 0x8000 : 0x4000));
437                         /* disable int */
438                         io_wr(ad1816, reg, io_rd(ad1816, reg) & ~AD1816_ENABLE);
439                         /* disable playback */
440                         if (io_rd(ad1816, reg) & AD1816_ENABLE)
441                                 printf("ad1816: failed to stop %s DMA!\n",
442                                        wr? "play" : "rec");
443                         ad1816_write(ad1816, wr? 8 : 10, 0); /* reset base cnt */
444                         ad1816_write(ad1816, wr? 9 : 11, 0); /* reset cur cnt */
445                 }
446                 break;
447         }
448         ad1816_unlock(ad1816);
449         return 0;
450 }
451
452 static int
453 ad1816chan_getptr(kobj_t obj, void *data)
454 {
455         struct ad1816_chinfo *ch = data;
456         return sndbuf_isadmaptr(ch->buffer);
457 }
458
459 static struct pcmchan_caps *
460 ad1816chan_getcaps(kobj_t obj, void *data)
461 {
462         return &ad1816_caps;
463 }
464
465 static kobj_method_t ad1816chan_methods[] = {
466         KOBJMETHOD(channel_init,                ad1816chan_init),
467         KOBJMETHOD(channel_setdir,              ad1816chan_setdir),
468         KOBJMETHOD(channel_setformat,           ad1816chan_setformat),
469         KOBJMETHOD(channel_setspeed,            ad1816chan_setspeed),
470         KOBJMETHOD(channel_setblocksize,        ad1816chan_setblocksize),
471         KOBJMETHOD(channel_trigger,             ad1816chan_trigger),
472         KOBJMETHOD(channel_getptr,              ad1816chan_getptr),
473         KOBJMETHOD(channel_getcaps,             ad1816chan_getcaps),
474         { 0, 0 }
475 };
476 CHANNEL_DECLARE(ad1816chan);
477
478 /* -------------------------------------------------------------------- */
479
480 static void
481 ad1816_release_resources(struct ad1816_info *ad1816, device_t dev)
482 {
483         if (ad1816->irq) {
484                 if (ad1816->ih)
485                         bus_teardown_intr(dev, ad1816->irq, ad1816->ih);
486                 bus_release_resource(dev, SYS_RES_IRQ, ad1816->irq_rid, ad1816->irq);
487                 ad1816->irq = 0;
488         }
489         if (ad1816->drq1) {
490                 isa_dma_release(rman_get_start(ad1816->drq1));
491                 bus_release_resource(dev, SYS_RES_DRQ, ad1816->drq1_rid, ad1816->drq1);
492                 ad1816->drq1 = 0;
493         }
494         if (ad1816->drq2) {
495                 isa_dma_release(rman_get_start(ad1816->drq2));
496                 bus_release_resource(dev, SYS_RES_DRQ, ad1816->drq2_rid, ad1816->drq2);
497                 ad1816->drq2 = 0;
498         }
499         if (ad1816->io_base) {
500                 bus_release_resource(dev, SYS_RES_IOPORT, ad1816->io_rid, ad1816->io_base);
501                 ad1816->io_base = 0;
502         }
503         if (ad1816->parent_dmat) {
504                 bus_dma_tag_destroy(ad1816->parent_dmat);
505                 ad1816->parent_dmat = 0;
506         }
507         if (ad1816->lock)
508                 snd_mtxfree(ad1816->lock);
509
510         kfree(ad1816, M_DEVBUF);
511 }
512
513 static int
514 ad1816_alloc_resources(struct ad1816_info *ad1816, device_t dev)
515 {
516         int ok = 1, pdma, rdma;
517
518         if (!ad1816->io_base)
519                 ad1816->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &ad1816->io_rid,
520                                                   0, ~0, 1, RF_ACTIVE);
521         if (!ad1816->irq)
522                 ad1816->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &ad1816->irq_rid,
523                                               0, ~0, 1, RF_ACTIVE);
524         if (!ad1816->drq1)
525                 ad1816->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ, &ad1816->drq1_rid,
526                                                0, ~0, 1, RF_ACTIVE);
527         if (!ad1816->drq2)
528                 ad1816->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ, &ad1816->drq2_rid,
529                                                0, ~0, 1, RF_ACTIVE);
530
531         if (!ad1816->io_base || !ad1816->drq1 || !ad1816->irq) ok = 0;
532
533         if (ok) {
534                 pdma = rman_get_start(ad1816->drq1);
535                 isa_dma_acquire(pdma);
536                 isa_dmainit(pdma, ad1816->bufsize);
537                 if (ad1816->drq2) {
538                         rdma = rman_get_start(ad1816->drq2);
539                         isa_dma_acquire(rdma);
540                         isa_dmainit(rdma, ad1816->bufsize);
541                 } else
542                         rdma = pdma;
543                 if (pdma == rdma)
544                         pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
545         }
546
547         return ok;
548 }
549
550 static int
551 ad1816_init(struct ad1816_info *ad1816, device_t dev)
552 {
553         ad1816_write(ad1816, 1, 0x2);   /* disable interrupts */
554         ad1816_write(ad1816, 32, 0x90F0);       /* SoundSys Mode, split fmt */
555
556         ad1816_write(ad1816, 5, 0x8080);        /* FM volume mute */
557         ad1816_write(ad1816, 6, 0x8080);        /* I2S1 volume mute */
558         ad1816_write(ad1816, 7, 0x8080);        /* I2S0 volume mute */
559         ad1816_write(ad1816, 17, 0x8888);       /* VID Volume mute */
560         ad1816_write(ad1816, 20, 0x5050);       /* recsrc mic, agc off */
561         /* adc gain is set to 0 */
562
563         return 0;
564 }
565
566 static int
567 ad1816_probe(device_t dev)
568 {
569         char *s = NULL;
570         u_int32_t logical_id = isa_get_logicalid(dev);
571
572         switch (logical_id) {
573         case 0x80719304: /* ADS7180 */
574                 s = "AD1816";
575                 break;
576         }
577
578         if (s) {
579                 device_set_desc(dev, s);
580                 return 0;
581         }
582         return ENXIO;
583 }
584
585 static int
586 ad1816_attach(device_t dev)
587 {
588         struct ad1816_info *ad1816;
589         char status[SND_STATUSLEN], status2[SND_STATUSLEN];
590
591         ad1816 = (struct ad1816_info *)kmalloc(sizeof *ad1816, M_DEVBUF, M_NOWAIT | M_ZERO);
592         if (!ad1816) return ENXIO;
593
594         ad1816->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc");
595         ad1816->io_rid = 2;
596         ad1816->irq_rid = 0;
597         ad1816->drq1_rid = 0;
598         ad1816->drq2_rid = 1;
599         ad1816->bufsize = pcm_getbuffersize(dev, 4096, DSP_BUFFSIZE, 65536);
600
601         if (!ad1816_alloc_resources(ad1816, dev)) goto no;
602         ad1816_init(ad1816, dev);
603         if (mixer_init(dev, &ad1816mixer_class, ad1816)) goto no;
604
605         snd_setup_intr(dev, ad1816->irq, INTR_MPSAFE, ad1816_intr, ad1816,
606                         &ad1816->ih, NULL);
607         if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
608                         /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
609                         /*highaddr*/BUS_SPACE_MAXADDR,
610                         /*filter*/NULL, /*filterarg*/NULL,
611                         /*maxsize*/ad1816->bufsize, /*nsegments*/1,
612                         /*maxsegz*/0x3ffff,
613                         /*flags*/0, &ad1816->parent_dmat) != 0) {
614                 device_printf(dev, "unable to create dma tag\n");
615                 goto no;
616         }
617         if (ad1816->drq2)
618                 ksnprintf(status2, SND_STATUSLEN, ":%ld", rman_get_start(ad1816->drq2));
619         else
620                 status2[0] = '\0';
621
622         ksnprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %u",
623                 rman_get_start(ad1816->io_base),
624                 rman_get_start(ad1816->irq),
625                 rman_get_start(ad1816->drq1),
626                 status2,
627                 ad1816->bufsize);
628
629         if (pcm_register(dev, ad1816, 1, 1)) goto no;
630         pcm_addchan(dev, PCMDIR_REC, &ad1816chan_class, ad1816);
631         pcm_addchan(dev, PCMDIR_PLAY, &ad1816chan_class, ad1816);
632         pcm_setstatus(dev, status);
633
634         return 0;
635 no:
636         ad1816_release_resources(ad1816, dev);
637
638         return ENXIO;
639
640 }
641
642 static int
643 ad1816_detach(device_t dev)
644 {
645         int r;
646         struct ad1816_info *ad1816;
647
648         r = pcm_unregister(dev);
649         if (r)
650                 return r;
651
652         ad1816 = pcm_getdevinfo(dev);
653         ad1816_release_resources(ad1816, dev);
654         return 0;
655 }
656
657 static device_method_t ad1816_methods[] = {
658         /* Device interface */
659         DEVMETHOD(device_probe,         ad1816_probe),
660         DEVMETHOD(device_attach,        ad1816_attach),
661         DEVMETHOD(device_detach,        ad1816_detach),
662
663         { 0, 0 }
664 };
665
666 static driver_t ad1816_driver = {
667         "pcm",
668         ad1816_methods,
669         PCM_SOFTC_SIZE,
670 };
671
672 DRIVER_MODULE(snd_ad1816, isa, ad1816_driver, pcm_devclass, 0, 0);
673 MODULE_DEPEND(snd_ad1816, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
674 MODULE_VERSION(snd_ad1816, 1);
675
676