1 /*
2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 /*
27 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30
31 /*
32 * Copyright (C) 4Front Technologies 1996-2008.
33 */
34
35 #include <sys/audio/audio_driver.h>
36 #include <sys/note.h>
37 #include <sys/pci.h>
38 #include <sys/stdbool.h>
39
40
41 /*
42 * NB: The Solo-1 is a bit schizophrenic compared to most devices.
43 * It has two separate DMA engines for PCM data. The first can do
44 * either capture or playback, and supports various Sound Blaster
45 * compatibility features. The second is dedicated to playback. The
46 * two engines have very little in common when it comes to programming
47 * them.
48 *
49 * We configure engine 1 for record, and engine 2 for playback. Both
50 * are configured for 48 kHz stereo 16-bit signed PCM.
51 */
52
53 /*
54 * ESS Solo-1 only implements the low 24-bits on Audio1, and requires
55 * 64KB alignment. For Audio2, it implements the full 32-bit address
56 * space, but requires a 1MB address boundary. Audio1 is used for
57 * recording, and Audio2 is used for playback.
58 */
59 static struct ddi_dma_attr dma_attr_audio1 = {
60 DMA_ATTR_VERSION, /* dma_attr_version */
61 0x0, /* dma_attr_addr_lo */
62 0x00ffffffU, /* dma_attr_addr_hi */
63 0xffff, /* dma_attr_count_max */
64 0x10000, /* dma_attr_align */
65 0x7f, /* dma_attr_burstsizes */
66 0x4, /* dma_attr_minxfer */
67 0xffff, /* dma_attr_maxxfer */
68 0xffff, /* dma_attr_seg */
69 0x1, /* dma_attr_sgllen */
70 0x1, /* dma_attr_granular */
71 0 /* dma_attr_flags */
72 };
73
74 static struct ddi_dma_attr dma_attr_audio2 = {
75 DMA_ATTR_VERSION, /* dma_attr_version */
76 0x0, /* dma_attr_addr_lo */
77 0xffffffffU, /* dma_attr_addr_hi */
78 0xfff0, /* dma_attr_count_max */
79 0x100000, /* dma_attr_align */
80 0x7f, /* dma_attr_burstsizes */
81 0x4, /* dma_attr_minxfer */
82 0xfff0, /* dma_attr_maxxfer */
83 0xffff, /* dma_attr_seg */
84 0x1, /* dma_attr_sgllen */
85 0x1, /* dma_attr_granular */
86 0 /* dma_attr_flags */
87 };
88
89 static ddi_device_acc_attr_t acc_attr = {
90 DDI_DEVICE_ATTR_V0,
91 DDI_STRUCTURE_LE_ACC,
92 DDI_STRICTORDER_ACC
93 };
94
95 static ddi_device_acc_attr_t buf_attr = {
96 DDI_DEVICE_ATTR_V0,
97 DDI_NEVERSWAP_ACC,
98 DDI_STRICTORDER_ACC
99 };
100
101
102 /*
103 * For the sake of simplicity, this driver fixes a few parameters with
104 * constants.
105 */
106 #define SOLO_RATE 48000
107 #define SOLO_FRAGFR 1024
108 #define SOLO_NFRAGS 2
109 #define SOLO_NCHAN 2
110 #define SOLO_SAMPSZ 2
111 #define SOLO_FRAGSZ (SOLO_FRAGFR * (SOLO_NCHAN * SOLO_SAMPSZ))
112 #define SOLO_BUFFR (SOLO_NFRAGS * SOLO_FRAGFR)
113 #define SOLO_BUFSZ (SOLO_NFRAGS * SOLO_FRAGSZ)
114
115 #define INPUT_MIC 0
116 #define INPUT_LINE 1
117 #define INPUT_CD 2
118 #define INPUT_AUX 3
119 #define INPUT_MONO 4
120 #define INSRCS 0x1f /* bits 0-4 */
121
122 #define DRVNAME "audiosolo"
123
124 static const char *solo_insrcs[] = {
125 AUDIO_PORT_MIC,
126 AUDIO_PORT_LINEIN,
127 AUDIO_PORT_CD,
128 AUDIO_PORT_AUX1IN,
129 AUDIO_PORT_AUX2IN, /* this is really mono-in */
130 NULL
131 };
132
133 typedef struct solo_regs {
134 ddi_acc_handle_t acch;
135 caddr_t base;
136 } solo_regs_t;
137
138 typedef struct solo_engine {
139 struct solo_dev *dev;
140 audio_engine_t *engine;
141 ddi_dma_handle_t dmah;
142 ddi_acc_handle_t acch;
143 caddr_t kaddr;
144 uint32_t paddr;
145
146 bool started;
147 bool trigger;
148 uint64_t count;
149 uint16_t offset;
150 int syncdir;
151 int format;
152 bool swapped;
153
154 void (*start)(struct solo_engine *);
155 void (*stop)(struct solo_engine *);
156 void (*update)(struct solo_engine *);
157 } solo_engine_t;
158
159 typedef enum {
160 CTL_FRONT = 0,
161 CTL_VOLUME,
162 CTL_MIC,
163 CTL_LINE,
164 CTL_CD,
165 CTL_AUX,
166 CTL_MONO,
167 CTL_MICBOOST,
168 CTL_RECGAIN,
169 CTL_RECSRC,
170 CTL_MONSRC,
171 CTL_SPEAKER,
172 CTL_LOOPBACK,
173 CTL_NUM, /* must be last */
174 } solo_ctrl_num_t;
175
176 typedef struct solo_ctrl {
177 struct solo_dev *dev;
178 audio_ctrl_t *ctrl;
179 solo_ctrl_num_t num;
180 uint64_t val;
181 } solo_ctrl_t;
182
183 typedef struct solo_dev {
184 dev_info_t *dip;
185 audio_dev_t *adev;
186 kmutex_t mutex;
187 ddi_intr_handle_t ihandle;
188
189 bool suspended;
190
191 /*
192 * Audio engines
193 */
194 solo_engine_t rec;
195 solo_engine_t play;
196 uint32_t last_capture;
197
198 /*
199 * Controls.
200 */
201 solo_ctrl_t ctrls[CTL_NUM];
202
203 /*
204 * Mapped registers
205 */
206 ddi_acc_handle_t pcih;
207 solo_regs_t io;
208 solo_regs_t sb;
209 solo_regs_t vc;
210
211 } solo_dev_t;
212
213 /*
214 * Common code for the pcm function
215 *
216 * solo_cmd write a single byte to the CMD port.
217 * solo_cmd1 write a CMD + 1 byte arg
218 * ess_get_byte returns a single byte from the DSP data port
219 *
220 * solo_write is actually solo_cmd1
221 * solo_read access ext. regs via solo_cmd(0xc0, reg) followed by solo_get_byte
222 */
223
224 #define PORT_RD8(port, regno) \
225 ddi_get8(port.acch, (void *)(port.base + (regno)))
226 #define PORT_RD16(port, regno) \
227 ddi_get16(port.acch, (void *)(port.base + (regno)))
228 #define PORT_RD32(port, regno) \
229 ddi_get32(port.acch, (void *)(port.base + (regno)))
230 #define PORT_WR8(port, regno, data) \
231 ddi_put8(port.acch, (void *)(port.base + (regno)), data)
232 #define PORT_WR16(port, regno, data) \
233 ddi_put16(port.acch, (void *)(port.base + (regno)), data)
234 #define PORT_WR32(port, regno, data) \
235 ddi_put32(port.acch, (void *)(port.base + (regno)), data)
236
237 static bool
solo_dspready(solo_dev_t * dev)238 solo_dspready(solo_dev_t *dev)
239 {
240 return ((PORT_RD8(dev->sb, 0xc) & 0x80) == 0 ? true : false);
241 }
242
243 static bool
solo_dspwr(solo_dev_t * dev,uint8_t val)244 solo_dspwr(solo_dev_t *dev, uint8_t val)
245 {
246 int i;
247
248 for (i = 0; i < 1000; i++) {
249 if (solo_dspready(dev)) {
250 PORT_WR8(dev->sb, 0xc, val);
251 return (true);
252 }
253 if (i > 10)
254 drv_usecwait((i > 100)? 1000 : 10);
255 }
256 audio_dev_warn(dev->adev, "solo_dspwr(0x%02x) timed out", val);
257 return (false);
258 }
259
260 static bool
solo_cmd(solo_dev_t * dev,uint8_t val)261 solo_cmd(solo_dev_t *dev, uint8_t val)
262 {
263 return (solo_dspwr(dev, val));
264 }
265
266 static void
solo_cmd1(solo_dev_t * dev,uint8_t cmd,uint8_t val)267 solo_cmd1(solo_dev_t *dev, uint8_t cmd, uint8_t val)
268 {
269 if (solo_dspwr(dev, cmd)) {
270 (void) solo_dspwr(dev, val);
271 }
272 }
273
274 static void
solo_setmixer(solo_dev_t * dev,uint8_t port,uint8_t value)275 solo_setmixer(solo_dev_t *dev, uint8_t port, uint8_t value)
276 {
277 PORT_WR8(dev->sb, 0x4, port); /* Select register */
278 drv_usecwait(10);
279 PORT_WR8(dev->sb, 0x5, value);
280 drv_usecwait(10);
281 }
282
283 static uint8_t
solo_getmixer(solo_dev_t * dev,uint8_t port)284 solo_getmixer(solo_dev_t *dev, uint8_t port)
285 {
286 uint8_t val;
287
288 PORT_WR8(dev->sb, 0x4, port); /* Select register */
289 drv_usecwait(10);
290 val = PORT_RD8(dev->sb, 0x5);
291 drv_usecwait(10);
292
293 return (val);
294 }
295
296 static uint8_t
solo_get_byte(solo_dev_t * dev)297 solo_get_byte(solo_dev_t *dev)
298 {
299 for (int i = 1000; i > 0; i--) {
300 if (PORT_RD8(dev->sb, 0xc) & 0x40)
301 return (PORT_RD8(dev->sb, 0xa));
302 else
303 drv_usecwait(20);
304 }
305 audio_dev_warn(dev->adev, "timeout waiting to read DSP port");
306 return (0xff);
307 }
308
309 static void
solo_write(solo_dev_t * dev,uint8_t reg,uint8_t val)310 solo_write(solo_dev_t *dev, uint8_t reg, uint8_t val)
311 {
312 solo_cmd1(dev, reg, val);
313 }
314
315 static uint8_t
solo_read(solo_dev_t * dev,uint8_t reg)316 solo_read(solo_dev_t *dev, uint8_t reg)
317 {
318 if (solo_cmd(dev, 0xc0) && solo_cmd(dev, reg)) {
319 return (solo_get_byte(dev));
320 }
321 return (0xff);
322 }
323
324 static bool
solo_reset_dsp(solo_dev_t * dev)325 solo_reset_dsp(solo_dev_t *dev)
326 {
327 PORT_WR8(dev->sb, 0x6, 3);
328 drv_usecwait(100);
329 PORT_WR8(dev->sb, 0x6, 0);
330 if (solo_get_byte(dev) != 0xAA) {
331 audio_dev_warn(dev->adev, "solo_reset_dsp failed");
332 return (false); /* Sorry */
333 }
334 return (true);
335 }
336
337 static uint_t
solo_intr(caddr_t arg1,caddr_t arg2)338 solo_intr(caddr_t arg1, caddr_t arg2)
339 {
340 solo_dev_t *dev = (void *)arg1;
341 uint8_t status;
342 uint_t rv = DDI_INTR_UNCLAIMED;
343
344 _NOTE(ARGUNUSED(arg2));
345
346 mutex_enter(&dev->mutex);
347
348 if (dev->suspended) {
349 mutex_exit(&dev->mutex);
350 return (rv);
351 }
352
353 status = PORT_RD8(dev->io, 0x7);
354 if (status & 0x20) {
355 rv = DDI_INTR_CLAIMED;
356 /* ack the interrupt */
357 solo_setmixer(dev, 0x7a, solo_getmixer(dev, 0x7a) & ~0x80);
358 }
359
360 if (status & 0x10) {
361 rv = DDI_INTR_CLAIMED;
362 /* ack the interrupt */
363 (void) PORT_RD8(dev->sb, 0xe);
364 }
365 mutex_exit(&dev->mutex);
366
367 return (rv);
368 }
369
370 static uint8_t
solo_mixer_scale(solo_dev_t * dev,solo_ctrl_num_t num)371 solo_mixer_scale(solo_dev_t *dev, solo_ctrl_num_t num)
372 {
373 uint32_t l, r;
374 uint64_t value = dev->ctrls[num].val;
375
376 l = (value >> 8) & 0xff;
377 r = value & 0xff;
378
379 l = (l * 15) / 100;
380 r = (r * 15) / 100;
381 return ((uint8_t)((l << 4) | (r)));
382 }
383
384 static void
solo_configure_mixer(solo_dev_t * dev)385 solo_configure_mixer(solo_dev_t *dev)
386 {
387 uint32_t v;
388 uint32_t mon, rec;
389
390 /*
391 * We disable hardware volume control (i.e. async updates to volume).
392 * We could in theory support this, but making it work right can be
393 * tricky, and we doubt it is widely used.
394 */
395 solo_setmixer(dev, 0x64, solo_getmixer(dev, 0x64) | 0xc);
396 solo_setmixer(dev, 0x66, 0);
397
398 /* master volume has 6 bits per channel, bit 6 indicates mute */
399 /* left */
400 v = (dev->ctrls[CTL_FRONT].val >> 8) & 0xff;
401 v = v ? (v * 63) / 100 : 64;
402 solo_setmixer(dev, 0x60, v & 0xff);
403
404 /* right */
405 v = dev->ctrls[CTL_FRONT].val & 0xff;
406 v = v ? (v * 63) / 100 : 64;
407 solo_setmixer(dev, 0x62, v & 0xff);
408
409 v = solo_mixer_scale(dev, CTL_VOLUME);
410 v = v | (v << 4);
411 solo_setmixer(dev, 0x7c, v & 0xff);
412 solo_setmixer(dev, 0x14, v & 0xff);
413
414 mon = dev->ctrls[CTL_MONSRC].val;
415 rec = dev->ctrls[CTL_RECSRC].val;
416
417 /*
418 * The Solo-1 has dual stereo mixers (one for input and one for output),
419 * with separate volume controls for each.
420 */
421 v = solo_mixer_scale(dev, CTL_MIC);
422 solo_setmixer(dev, 0x68, rec & (1 << INPUT_MIC) ? v : 0);
423 solo_setmixer(dev, 0x1a, mon & (1 << INPUT_MIC) ? v : 0);
424
425 v = solo_mixer_scale(dev, CTL_LINE);
426 solo_setmixer(dev, 0x6e, rec & (1 << INPUT_LINE) ? v : 0);
427 solo_setmixer(dev, 0x3e, mon & (1 << INPUT_LINE) ? v : 0);
428
429 v = solo_mixer_scale(dev, CTL_CD);
430 solo_setmixer(dev, 0x6a, rec & (1 << INPUT_CD) ? v : 0);
431 solo_setmixer(dev, 0x38, mon & (1 << INPUT_CD) ? v : 0);
432
433 v = solo_mixer_scale(dev, CTL_AUX);
434 solo_setmixer(dev, 0x6c, rec & (1 << INPUT_AUX) ? v : 0);
435 solo_setmixer(dev, 0x3a, mon & (1 << INPUT_AUX) ? v : 0);
436
437 v = solo_mixer_scale(dev, CTL_MONO);
438 v = v | (v << 4);
439 solo_setmixer(dev, 0x6f, rec & (1 << INPUT_MONO) ? v : 0);
440 solo_setmixer(dev, 0x6d, mon & (1 << INPUT_MONO) ? v : 0);
441
442 if (dev->ctrls[CTL_MICBOOST].val) {
443 solo_setmixer(dev, 0x7d, solo_getmixer(dev, 0x7d) | 0x8);
444 } else {
445 solo_setmixer(dev, 0x7d, solo_getmixer(dev, 0x7d) & ~(0x8));
446 }
447
448 v = solo_mixer_scale(dev, CTL_RECGAIN);
449 v = v | (v << 4);
450 solo_write(dev, 0xb4, v & 0xff);
451
452 v = dev->ctrls[CTL_SPEAKER].val & 0xff;
453 v = (v * 7) / 100;
454 solo_setmixer(dev, 0x3c, v & 0xff);
455
456 if (dev->ctrls[CTL_LOOPBACK].val) {
457 /* record-what-you-hear mode */
458 solo_setmixer(dev, 0x1c, 0x3);
459 } else {
460 /* use record mixer */
461 solo_setmixer(dev, 0x1c, 0x5);
462 }
463
464 }
465
466 static int
solo_set_mixsrc(void * arg,uint64_t val)467 solo_set_mixsrc(void *arg, uint64_t val)
468 {
469 solo_ctrl_t *pc = arg;
470 solo_dev_t *dev = pc->dev;
471
472 if ((val & ~INSRCS) != 0)
473 return (EINVAL);
474
475 mutex_enter(&dev->mutex);
476 pc->val = val;
477 solo_configure_mixer(dev);
478 mutex_exit(&dev->mutex);
479 return (0);
480 }
481
482 static int
solo_set_mono(void * arg,uint64_t val)483 solo_set_mono(void *arg, uint64_t val)
484 {
485 solo_ctrl_t *pc = arg;
486 solo_dev_t *dev = pc->dev;
487
488 val &= 0xff;
489 if (val > 100)
490 return (EINVAL);
491
492 val = (val & 0xff) | ((val & 0xff) << 8);
493
494 mutex_enter(&dev->mutex);
495 pc->val = val;
496 solo_configure_mixer(dev);
497 mutex_exit(&dev->mutex);
498 return (0);
499 }
500
501 static int
solo_set_stereo(void * arg,uint64_t val)502 solo_set_stereo(void *arg, uint64_t val)
503 {
504 solo_ctrl_t *pc = arg;
505 solo_dev_t *dev = pc->dev;
506 uint8_t l;
507 uint8_t r;
508
509 l = (val & 0xff00) >> 8;
510 r = val & 0xff;
511
512 if ((l > 100) || (r > 100))
513 return (EINVAL);
514
515 mutex_enter(&dev->mutex);
516 pc->val = val;
517 solo_configure_mixer(dev);
518 mutex_exit(&dev->mutex);
519 return (0);
520 }
521
522 static int
solo_set_bool(void * arg,uint64_t val)523 solo_set_bool(void *arg, uint64_t val)
524 {
525 solo_ctrl_t *pc = arg;
526 solo_dev_t *dev = pc->dev;
527
528 mutex_enter(&dev->mutex);
529 pc->val = val;
530 solo_configure_mixer(dev);
531 mutex_exit(&dev->mutex);
532 return (0);
533 }
534
535 static int
solo_get_value(void * arg,uint64_t * val)536 solo_get_value(void *arg, uint64_t *val)
537 {
538 solo_ctrl_t *pc = arg;
539 solo_dev_t *dev = pc->dev;
540
541 mutex_enter(&dev->mutex);
542 *val = pc->val;
543 mutex_exit(&dev->mutex);
544 return (0);
545 }
546
547 #define PLAYCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_PLAY)
548 #define RECCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC)
549 #define MONCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_MONITOR)
550 #define PCMVOL (PLAYCTL | AUDIO_CTRL_FLAG_PCMVOL)
551 #define MAINVOL (PLAYCTL | AUDIO_CTRL_FLAG_MAINVOL)
552 #define RECVOL (RECCTL | AUDIO_CTRL_FLAG_RECVOL)
553
554 static void
solo_alloc_ctrl(solo_dev_t * dev,uint32_t num,uint64_t val)555 solo_alloc_ctrl(solo_dev_t *dev, uint32_t num, uint64_t val)
556 {
557 audio_ctrl_desc_t desc;
558 audio_ctrl_wr_t fn;
559 solo_ctrl_t *pc;
560
561 bzero(&desc, sizeof (desc));
562
563 pc = &dev->ctrls[num];
564 pc->num = num;
565 pc->dev = dev;
566
567 switch (num) {
568 case CTL_VOLUME:
569 desc.acd_name = AUDIO_CTRL_ID_VOLUME;
570 desc.acd_type = AUDIO_CTRL_TYPE_MONO;
571 desc.acd_minvalue = 0;
572 desc.acd_maxvalue = 100;
573 desc.acd_flags = PCMVOL;
574 fn = solo_set_mono;
575 break;
576
577 case CTL_FRONT:
578 desc.acd_name = AUDIO_CTRL_ID_LINEOUT;
579 desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
580 desc.acd_minvalue = 0;
581 desc.acd_maxvalue = 100;
582 desc.acd_flags = MAINVOL;
583 fn = solo_set_stereo;
584 break;
585
586 case CTL_SPEAKER:
587 desc.acd_name = AUDIO_CTRL_ID_SPEAKER;
588 desc.acd_type = AUDIO_CTRL_TYPE_MONO;
589 desc.acd_minvalue = 0;
590 desc.acd_maxvalue = 100;
591 desc.acd_flags = MAINVOL;
592 fn = solo_set_mono;
593 break;
594
595 case CTL_MIC:
596 desc.acd_name = AUDIO_CTRL_ID_MIC;
597 desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
598 desc.acd_minvalue = 0;
599 desc.acd_maxvalue = 100;
600 desc.acd_flags = RECVOL;
601 fn = solo_set_stereo;
602 break;
603
604 case CTL_LINE:
605 desc.acd_name = AUDIO_CTRL_ID_LINEIN;
606 desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
607 desc.acd_minvalue = 0;
608 desc.acd_maxvalue = 100;
609 desc.acd_flags = RECVOL;
610 fn = solo_set_stereo;
611 break;
612
613 case CTL_CD:
614 desc.acd_name = AUDIO_CTRL_ID_CD;
615 desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
616 desc.acd_minvalue = 0;
617 desc.acd_maxvalue = 100;
618 desc.acd_flags = RECVOL;
619 fn = solo_set_stereo;
620 break;
621
622 case CTL_AUX:
623 desc.acd_name = AUDIO_CTRL_ID_AUX1IN;
624 desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
625 desc.acd_minvalue = 0;
626 desc.acd_maxvalue = 100;
627 desc.acd_flags = RECVOL;
628 fn = solo_set_stereo;
629 break;
630
631 case CTL_MONO:
632 desc.acd_name = AUDIO_CTRL_ID_AUX2IN;
633 desc.acd_type = AUDIO_CTRL_TYPE_MONO;
634 desc.acd_minvalue = 0;
635 desc.acd_maxvalue = 100;
636 desc.acd_flags = RECVOL;
637 fn = solo_set_mono;
638 break;
639
640 case CTL_RECSRC:
641 desc.acd_name = AUDIO_CTRL_ID_RECSRC;
642 desc.acd_type = AUDIO_CTRL_TYPE_ENUM;
643 desc.acd_minvalue = INSRCS;
644 desc.acd_maxvalue = INSRCS;
645 desc.acd_flags = RECCTL | AUDIO_CTRL_FLAG_MULTI;
646 for (int i = 0; solo_insrcs[i]; i++) {
647 desc.acd_enum[i] = solo_insrcs[i];
648 }
649 fn = solo_set_mixsrc;
650 break;
651
652 case CTL_MONSRC:
653 desc.acd_name = AUDIO_CTRL_ID_MONSRC;
654 desc.acd_type = AUDIO_CTRL_TYPE_ENUM;
655 desc.acd_minvalue = INSRCS;
656 desc.acd_maxvalue = INSRCS;
657 desc.acd_flags = MONCTL | AUDIO_CTRL_FLAG_MULTI;
658 for (int i = 0; solo_insrcs[i]; i++) {
659 desc.acd_enum[i] = solo_insrcs[i];
660 }
661 fn = solo_set_mixsrc;
662 break;
663
664 case CTL_MICBOOST:
665 desc.acd_name = AUDIO_CTRL_ID_MICBOOST;
666 desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN;
667 desc.acd_minvalue = 0;
668 desc.acd_maxvalue = 1;
669 desc.acd_flags = RECCTL;
670 fn = solo_set_bool;
671 break;
672
673 case CTL_LOOPBACK:
674 desc.acd_name = AUDIO_CTRL_ID_LOOPBACK;
675 desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN;
676 desc.acd_minvalue = 0;
677 desc.acd_maxvalue = 1;
678 desc.acd_flags = RECCTL;
679 fn = solo_set_bool;
680 break;
681
682 case CTL_RECGAIN:
683 desc.acd_name = AUDIO_CTRL_ID_RECGAIN;
684 desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
685 desc.acd_minvalue = 0;
686 desc.acd_maxvalue = 100;
687 desc.acd_flags = RECCTL;
688 fn = solo_set_stereo;
689 break;
690 }
691
692 pc->val = val;
693 pc->ctrl = audio_dev_add_control(dev->adev, &desc,
694 solo_get_value, fn, pc);
695 }
696
697 static bool
solo_add_controls(solo_dev_t * dev)698 solo_add_controls(solo_dev_t *dev)
699 {
700 solo_alloc_ctrl(dev, CTL_VOLUME, 0x4b);
701 solo_alloc_ctrl(dev, CTL_FRONT, 0x5a5a);
702 solo_alloc_ctrl(dev, CTL_SPEAKER, 0x4b);
703 solo_alloc_ctrl(dev, CTL_MIC, 0x3232);
704 solo_alloc_ctrl(dev, CTL_LINE, 0x4b4b);
705 solo_alloc_ctrl(dev, CTL_CD, 0x4b4b);
706 solo_alloc_ctrl(dev, CTL_AUX, 0);
707 solo_alloc_ctrl(dev, CTL_MONO, 0);
708 solo_alloc_ctrl(dev, CTL_RECSRC, (1U << INPUT_MIC));
709 solo_alloc_ctrl(dev, CTL_MONSRC, 0);
710 solo_alloc_ctrl(dev, CTL_RECGAIN, 0x4b4b);
711 solo_alloc_ctrl(dev, CTL_MICBOOST, 1);
712 solo_alloc_ctrl(dev, CTL_LOOPBACK, 0);
713
714 return (true);
715 }
716
717
718 /* utility functions for ESS */
719 static uint8_t
solo_calcfilter(int spd)720 solo_calcfilter(int spd)
721 {
722 int cutoff;
723
724 cutoff = (spd * 9 * 82) / 20;
725 return (256 - (7160000 / cutoff));
726 }
727
728 static void
solo_aud1_update(solo_engine_t * e)729 solo_aud1_update(solo_engine_t *e)
730 {
731 solo_dev_t *dev = e->dev;
732 uint16_t offset, n;
733 uint32_t ptr;
734 uint32_t count;
735 uint32_t diff;
736 int tries;
737
738 ASSERT(mutex_owned(&dev->mutex));
739
740 /*
741 * During recording, this register is known to give back
742 * garbage if it's not quiescent while being read. This hack
743 * attempts to work around it. We also suspend the DMA
744 * while we do this, to minimize record distortion.
745 */
746 if (e->trigger) {
747 drv_usecwait(20);
748 }
749 for (tries = 10; tries; tries--) {
750 drv_usecwait(10);
751 ptr = PORT_RD32(dev->vc, 0);
752 count = PORT_RD16(dev->vc, 4);
753 diff = e->paddr + SOLO_BUFSZ - ptr - count;
754 if ((diff > 3) || (ptr < e->paddr) ||
755 (ptr >= (e->paddr + SOLO_BUFSZ))) {
756 ptr = dev->last_capture;
757 } else {
758 break;
759 }
760 }
761 if (e->trigger) {
762 PORT_WR8(dev->vc, 0xf, 0); /* restart DMA */
763 }
764 if (!tries) {
765 /*
766 * Note, this is a pretty bad situation, because we'll
767 * not have an accurate idea of our position. But its
768 * better than making a bad alteration. If we had FMA
769 * for audio devices, this would be a good point to
770 * raise a fault.
771 */
772 return;
773 }
774 dev->last_capture = ptr;
775 offset = ptr - e->paddr;
776 offset /= (SOLO_NCHAN * SOLO_SAMPSZ);
777
778 n = offset >= e->offset ?
779 offset - e->offset :
780 offset + SOLO_BUFSZ - e->offset;
781
782 e->offset = offset;
783 e->count += n / (SOLO_NCHAN * SOLO_SAMPSZ);
784 }
785
786 static void
solo_aud1_start(solo_engine_t * e)787 solo_aud1_start(solo_engine_t *e)
788 {
789 solo_dev_t *dev = e->dev;
790 int len;
791 uint32_t v;
792
793 ASSERT(mutex_owned(&dev->mutex));
794
795 e->offset = 0;
796 len = SOLO_FRAGSZ / 2;
797 len = -len;
798
799 /* sample rate - 48 kHz */
800 solo_write(dev, 0xa1, 0xf0);
801 /* filter cutoff */
802 solo_write(dev, 0xa2, solo_calcfilter(SOLO_RATE));
803
804
805 /* mono/stereo - bit 0 set, bit 1 clear */
806 solo_write(dev, 0xa8, (solo_read(dev, 0xa8) & ~0x03) | 1);
807
808 (void) solo_cmd(dev, 0xd3); /* turn off DAC1 output */
809
810 /* setup fifo for signed 16-bit stereo */
811 solo_write(dev, 0xb7, 0x71);
812 solo_write(dev, 0xb7, 0xbc);
813
814 v = solo_mixer_scale(dev, CTL_RECGAIN);
815 v = v | (v << 4);
816 solo_write(dev, 0xb4, v & 0xff);
817
818 PORT_WR8(dev->vc, 0x8, 0xc4); /* command */
819 PORT_WR8(dev->vc, 0xd, 0xff); /* clear DMA */
820 PORT_WR8(dev->vc, 0xf, 0x01); /* stop DMA */
821
822 PORT_WR8(dev->vc, 0xd, 0xff); /* reset */
823 PORT_WR8(dev->vc, 0xf, 0x01); /* mask */
824 PORT_WR8(dev->vc, 0xb, 0x14); /* mode */
825
826 PORT_WR32(dev->vc, 0x0, e->paddr);
827 PORT_WR16(dev->vc, 0x4, SOLO_BUFSZ - 1);
828
829 /* transfer length low, high */
830 solo_write(dev, 0xa4, len & 0x00ff);
831 solo_write(dev, 0xa5, (len & 0xff00) >> 8);
832
833 /* autoinit, dma dir, go for it */
834 solo_write(dev, 0xb8, 0x0f);
835 PORT_WR8(dev->vc, 0xf, 0); /* start DMA */
836
837 dev->last_capture = e->paddr;
838 e->trigger = true;
839 }
840
841 static void
solo_aud1_stop(solo_engine_t * e)842 solo_aud1_stop(solo_engine_t *e)
843 {
844 solo_dev_t *dev = e->dev;
845
846 /* NB: We might be in quiesce, without a lock held */
847 solo_write(dev, 0xb8, solo_read(dev, 0xb8) & ~0x01);
848 e->trigger = false;
849 }
850
851 static void
solo_aud2_update(solo_engine_t * e)852 solo_aud2_update(solo_engine_t *e)
853 {
854 solo_dev_t *dev = e->dev;
855 uint16_t offset = 0, n;
856
857 ASSERT(mutex_owned(&dev->mutex));
858
859 offset = SOLO_BUFSZ - PORT_RD16(dev->io, 0x4);
860 offset /= (SOLO_NCHAN * SOLO_SAMPSZ);
861
862 n = offset >= e->offset ?
863 offset - e->offset :
864 offset + SOLO_BUFFR - e->offset;
865
866 e->offset = offset;
867 e->count += n;
868 }
869
870 static void
solo_aud2_start(solo_engine_t * e)871 solo_aud2_start(solo_engine_t *e)
872 {
873 solo_dev_t *dev = e->dev;
874 int len;
875 uint32_t v;
876
877 ASSERT(mutex_owned(&dev->mutex));
878
879 e->offset = 0;
880 len = SOLO_FRAGSZ / 2;
881 len = -len;
882
883 /* program transfer type */
884 solo_setmixer(dev, 0x78, 0x10);
885 /* sample rate - 48 kHz */
886 solo_setmixer(dev, 0x70, 0xf0);
887 solo_setmixer(dev, 0x72, solo_calcfilter(SOLO_RATE));
888 /* transfer length low & high */
889 solo_setmixer(dev, 0x74, len & 0x00ff);
890 solo_setmixer(dev, 0x76, (len & 0xff00) >> 8);
891 /* enable irq, set signed 16-bit stereo format */
892 solo_setmixer(dev, 0x7a, 0x47);
893
894 PORT_WR8(dev->io, 0x6, 0);
895 PORT_WR32(dev->io, 0x0, e->paddr);
896 PORT_WR16(dev->io, 0x4, SOLO_BUFSZ);
897
898 /* this crazy initialization appears to help with fifo weirdness */
899 /* start the engine running */
900 solo_setmixer(dev, 0x78, 0x92);
901 drv_usecwait(10);
902 solo_setmixer(dev, 0x78, 0x93);
903
904 PORT_WR8(dev->io, 0x6, 0x0a); /* autoinit, enable */
905
906 v = solo_mixer_scale(dev, CTL_VOLUME);
907 v = v | (v << 4);
908 solo_setmixer(dev, 0x7c, v & 0xff);
909
910 e->trigger = true;
911 }
912
913 static void
solo_aud2_stop(solo_engine_t * e)914 solo_aud2_stop(solo_engine_t *e)
915 {
916 solo_dev_t *dev = e->dev;
917
918 /* NB: We might be in quiesce, without a lock held */
919 PORT_WR8(dev->io, 0x6, 0);
920 solo_setmixer(dev, 0x78, solo_getmixer(dev, 0x78) & ~0x03);
921
922 e->trigger = false;
923 }
924
925 /*
926 * Audio entry points.
927 */
928 static int
solo_format(void * arg)929 solo_format(void *arg)
930 {
931 solo_engine_t *e = arg;
932 return (e->format);
933 }
934
935 static int
solo_channels(void * arg)936 solo_channels(void *arg)
937 {
938 _NOTE(ARGUNUSED(arg));
939 return (SOLO_NCHAN);
940 }
941
942 static int
solo_rate(void * arg)943 solo_rate(void *arg)
944 {
945 _NOTE(ARGUNUSED(arg));
946 return (SOLO_RATE);
947 }
948
949 static void
solo_chinfo(void * arg,int chan,unsigned * offset,unsigned * incr)950 solo_chinfo(void *arg, int chan, unsigned *offset, unsigned *incr)
951 {
952 solo_engine_t *e = arg;
953
954 if (e->swapped) {
955 *offset = !chan;
956 } else {
957 *offset = chan;
958 }
959 *incr = 2;
960 }
961
962 static void
solo_sync(void * arg,unsigned nframes)963 solo_sync(void *arg, unsigned nframes)
964 {
965 solo_engine_t *e = arg;
966
967 _NOTE(ARGUNUSED(nframes));
968
969 (void) ddi_dma_sync(e->dmah, 0, 0, e->syncdir);
970 }
971
972
973 static uint64_t
solo_count(void * arg)974 solo_count(void *arg)
975 {
976 solo_engine_t *e = arg;
977 solo_dev_t *dev = e->dev;
978 uint64_t count;
979
980 mutex_enter(&dev->mutex);
981 e->update(e);
982 count = e->count;
983 mutex_exit(&dev->mutex);
984
985 return (count);
986 }
987
988 static int
solo_open(void * arg,int f,unsigned * nframes,caddr_t * buf)989 solo_open(void *arg, int f, unsigned *nframes, caddr_t *buf)
990 {
991 solo_engine_t *e = arg;
992 solo_dev_t *dev = e->dev;
993
994 _NOTE(ARGUNUSED(f));
995
996 *nframes = SOLO_NFRAGS * SOLO_FRAGFR;
997 *buf = e->kaddr;
998
999 mutex_enter(&dev->mutex);
1000 e->started = false;
1001 e->count = 0;
1002 mutex_exit(&dev->mutex);
1003
1004 return (0);
1005 }
1006
1007 void
solo_close(void * arg)1008 solo_close(void *arg)
1009 {
1010 solo_engine_t *e = arg;
1011 solo_dev_t *dev = e->dev;
1012
1013 mutex_enter(&dev->mutex);
1014 e->stop(e);
1015 e->started = false;
1016 mutex_exit(&dev->mutex);
1017 }
1018
1019
1020 static int
solo_start(void * arg)1021 solo_start(void *arg)
1022 {
1023 solo_engine_t *e = arg;
1024 solo_dev_t *dev = e->dev;
1025
1026 mutex_enter(&dev->mutex);
1027 if (!e->started) {
1028 e->start(e);
1029 e->started = true;
1030 }
1031 mutex_exit(&dev->mutex);
1032
1033 return (0);
1034 }
1035
1036 static void
solo_stop(void * arg)1037 solo_stop(void *arg)
1038 {
1039 solo_engine_t *e = arg;
1040 solo_dev_t *dev = e->dev;
1041
1042 mutex_enter(&dev->mutex);
1043 if (e->started) {
1044 e->stop(e);
1045 e->started = false;
1046 }
1047 mutex_exit(&dev->mutex);
1048
1049 }
1050
1051 static audio_engine_ops_t solo_engine_ops = {
1052 AUDIO_ENGINE_VERSION,
1053 solo_open,
1054 solo_close,
1055 solo_start,
1056 solo_stop,
1057 solo_count,
1058 solo_format,
1059 solo_channels,
1060 solo_rate,
1061 solo_sync,
1062 NULL,
1063 solo_chinfo,
1064 NULL,
1065 };
1066
1067 static void
solo_release_resources(solo_dev_t * dev)1068 solo_release_resources(solo_dev_t *dev)
1069 {
1070 if (dev->ihandle != NULL) {
1071 (void) ddi_intr_disable(dev->ihandle);
1072 (void) ddi_intr_remove_handler(dev->ihandle);
1073 (void) ddi_intr_free(dev->ihandle);
1074 mutex_destroy(&dev->mutex);
1075 }
1076
1077 if (dev->io.acch != NULL) {
1078 ddi_regs_map_free(&dev->io.acch);
1079 }
1080
1081 if (dev->sb.acch != NULL) {
1082 ddi_regs_map_free(&dev->sb.acch);
1083 }
1084
1085 if (dev->vc.acch != NULL) {
1086 ddi_regs_map_free(&dev->vc.acch);
1087 }
1088
1089 if (dev->pcih != NULL) {
1090 pci_config_teardown(&dev->pcih);
1091 }
1092
1093 /* release play resources */
1094 if (dev->play.paddr != 0)
1095 (void) ddi_dma_unbind_handle(dev->play.dmah);
1096 if (dev->play.acch != NULL)
1097 ddi_dma_mem_free(&dev->play.acch);
1098 if (dev->play.dmah != NULL)
1099 ddi_dma_free_handle(&dev->play.dmah);
1100
1101 if (dev->play.engine != NULL) {
1102 audio_dev_remove_engine(dev->adev, dev->play.engine);
1103 audio_engine_free(dev->play.engine);
1104 }
1105
1106 /* release record resources */
1107 if (dev->rec.paddr != 0)
1108 (void) ddi_dma_unbind_handle(dev->rec.dmah);
1109 if (dev->rec.acch != NULL)
1110 ddi_dma_mem_free(&dev->rec.acch);
1111 if (dev->rec.dmah != NULL)
1112 ddi_dma_free_handle(&dev->rec.dmah);
1113
1114 if (dev->rec.engine != NULL) {
1115 audio_dev_remove_engine(dev->adev, dev->rec.engine);
1116 audio_engine_free(dev->rec.engine);
1117 }
1118
1119 for (int i = 0; i < CTL_NUM; i++) {
1120 if (dev->ctrls[i].ctrl != NULL) {
1121 audio_dev_del_control(dev->ctrls[i].ctrl);
1122 }
1123 }
1124
1125 if (dev->adev != NULL) {
1126 audio_dev_free(dev->adev);
1127 }
1128
1129 kmem_free(dev, sizeof (*dev));
1130 }
1131
1132 static bool
solo_setup_interrupts(solo_dev_t * dev)1133 solo_setup_interrupts(solo_dev_t *dev)
1134 {
1135 int actual;
1136 uint_t ipri;
1137
1138 if ((ddi_intr_alloc(dev->dip, &dev->ihandle, DDI_INTR_TYPE_FIXED,
1139 0, 1, &actual, DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) ||
1140 (actual != 1)) {
1141 audio_dev_warn(dev->adev, "can't alloc intr handle");
1142 return (false);
1143 }
1144
1145 if (ddi_intr_get_pri(dev->ihandle, &ipri) != DDI_SUCCESS) {
1146 audio_dev_warn(dev->adev, "can't determine intr priority");
1147 (void) ddi_intr_free(dev->ihandle);
1148 dev->ihandle = NULL;
1149 return (false);
1150 }
1151
1152 if (ddi_intr_add_handler(dev->ihandle, solo_intr, dev,
1153 NULL) != DDI_SUCCESS) {
1154 audio_dev_warn(dev->adev, "can't add intr handler");
1155 (void) ddi_intr_free(dev->ihandle);
1156 dev->ihandle = NULL;
1157 return (false);
1158 }
1159
1160 mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
1161
1162 return (true);
1163 }
1164
1165 static bool
solo_map_registers(solo_dev_t * dev)1166 solo_map_registers(solo_dev_t *dev)
1167 {
1168 dev_info_t *dip = dev->dip;
1169
1170 /* map registers */
1171 if (ddi_regs_map_setup(dip, 1, &dev->io.base, 0, 0, &acc_attr,
1172 &dev->io.acch) != DDI_SUCCESS) {
1173 audio_dev_warn(dev->adev, "can't map IO registers");
1174 return (false);
1175 }
1176 if (ddi_regs_map_setup(dip, 2, &dev->sb.base, 0, 0, &acc_attr,
1177 &dev->sb.acch) != DDI_SUCCESS) {
1178 audio_dev_warn(dev->adev, "can't map SB registers");
1179 return (false);
1180 }
1181 if (ddi_regs_map_setup(dip, 3, &dev->vc.base, 0, 0, &acc_attr,
1182 &dev->vc.acch) != DDI_SUCCESS) {
1183 audio_dev_warn(dev->adev, "can't map VC registers");
1184 return (false);
1185 }
1186
1187 return (true);
1188 }
1189
1190 #define ESS_PCI_LEGACYCONTROL 0x40
1191 #define ESS_PCI_CONFIG 0x50
1192 #define ESS_PCI_DDMACONTROL 0x60
1193
1194 static bool
solo_init_hw(solo_dev_t * dev)1195 solo_init_hw(solo_dev_t *dev)
1196 {
1197 uint32_t data;
1198
1199 /*
1200 * Legacy audio register -- disable legacy audio. We also
1201 * arrange for 16-bit I/O address decoding.
1202 */
1203 /* this version disables the MPU, FM synthesis (Adlib), and Game Port */
1204 pci_config_put16(dev->pcih, ESS_PCI_LEGACYCONTROL, 0x8041);
1205
1206 /*
1207 * Note that Solo-1 uses I/O space for all BARs, and hardwires
1208 * the upper 32-bits to zero.
1209 */
1210 data = pci_config_get32(dev->pcih, PCI_CONF_BASE2);
1211 data |= 1;
1212 pci_config_put16(dev->pcih, ESS_PCI_DDMACONTROL, data & 0xffff);
1213
1214 /*
1215 * Make sure that legacy IRQ and DRQ are disbled. We disable most
1216 * other legacy features too.
1217 */
1218 pci_config_put16(dev->pcih, ESS_PCI_CONFIG, 0);
1219
1220 if (!solo_reset_dsp(dev))
1221 return (false);
1222
1223 /* enable extended mode */
1224 (void) solo_cmd(dev, 0xc6);
1225
1226
1227 PORT_WR8(dev->io, 0x7, 0x30); /* enable audio irqs */
1228
1229 /* demand mode, 4 bytes/xfer */
1230 solo_write(dev, 0xb9, 0x01);
1231
1232 /*
1233 * This sets Audio 2 (playback) to use its own independent
1234 * rate control, and gives us 48 kHz compatible divisors. It
1235 * also bypasses the switched capacitor filter.
1236 */
1237 solo_setmixer(dev, 0x71, 0x2a);
1238
1239 /* irq control */
1240 solo_write(dev, 0xb1, (solo_read(dev, 0xb1) & 0x0f) | 0x50);
1241 /* drq control */
1242 solo_write(dev, 0xb2, (solo_read(dev, 0xb2) & 0x0f) | 0x50);
1243
1244 solo_setmixer(dev, 0, 0); /* reset mixer settings */
1245
1246 solo_configure_mixer(dev);
1247 return (true);
1248 }
1249
1250 static bool
solo_alloc_engine(solo_dev_t * dev,int engno)1251 solo_alloc_engine(solo_dev_t *dev, int engno)
1252 {
1253 size_t rlen;
1254 ddi_dma_attr_t *dattr;
1255 ddi_dma_cookie_t c;
1256 unsigned ccnt;
1257 unsigned caps;
1258 unsigned dflags;
1259 const char *desc;
1260 solo_engine_t *e;
1261
1262 ASSERT((engno == 1) || (engno = 2));
1263
1264 switch (engno) {
1265 case 1: /* record */
1266 e = &dev->rec;
1267 desc = "record";
1268 dattr = &dma_attr_audio1;
1269 caps = ENGINE_INPUT_CAP;
1270 dflags = DDI_DMA_READ | DDI_DMA_CONSISTENT;
1271 e->syncdir = DDI_DMA_SYNC_FORKERNEL;
1272 e->update = solo_aud1_update;
1273 e->start = solo_aud1_start;
1274 e->stop = solo_aud1_stop;
1275 e->format = AUDIO_FORMAT_S16_BE;
1276 e->swapped = true;
1277 break;
1278
1279 case 2: /* playback */
1280 e = &dev->play;
1281 desc = "playback";
1282 dattr = &dma_attr_audio2;
1283 caps = ENGINE_OUTPUT_CAP;
1284 dflags = DDI_DMA_WRITE | DDI_DMA_CONSISTENT;
1285 e->syncdir = DDI_DMA_SYNC_FORDEV;
1286 e->update = solo_aud2_update;
1287 e->start = solo_aud2_start;
1288 e->stop = solo_aud2_stop;
1289 e->format = AUDIO_FORMAT_S16_LE;
1290 e->swapped = false;
1291 break;
1292
1293 default:
1294 audio_dev_warn(dev->adev, "bad engine number!");
1295 return (false);
1296 }
1297
1298 e->dev = dev;
1299
1300 if (ddi_dma_alloc_handle(dev->dip, dattr, DDI_DMA_SLEEP, NULL,
1301 &e->dmah) != DDI_SUCCESS) {
1302 audio_dev_warn(dev->adev, "%s dma handle alloc failed", desc);
1303 return (false);
1304 }
1305 if (ddi_dma_mem_alloc(e->dmah, SOLO_BUFSZ, &buf_attr,
1306 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &e->kaddr,
1307 &rlen, &e->acch) != DDI_SUCCESS) {
1308 audio_dev_warn(dev->adev, "%s dma memory alloc failed", desc);
1309 return (false);
1310 }
1311 /* ensure that the buffer is zeroed out properly */
1312 bzero(e->kaddr, rlen);
1313 if (ddi_dma_addr_bind_handle(e->dmah, NULL, e->kaddr, SOLO_BUFSZ,
1314 dflags, DDI_DMA_SLEEP, NULL, &c, &ccnt) != DDI_DMA_MAPPED) {
1315 audio_dev_warn(dev->adev, "%s dma binding failed", desc);
1316 return (false);
1317 }
1318 e->paddr = c.dmac_address;
1319
1320 /*
1321 * Allocate and configure audio engine.
1322 */
1323 e->engine = audio_engine_alloc(&solo_engine_ops, caps);
1324 if (e->engine == NULL) {
1325 audio_dev_warn(dev->adev, "record audio_engine_alloc failed");
1326 return (false);
1327 }
1328
1329 audio_engine_set_private(e->engine, e);
1330 audio_dev_add_engine(dev->adev, e->engine);
1331
1332 return (true);
1333 }
1334
1335
1336 static int
solo_suspend(solo_dev_t * dev)1337 solo_suspend(solo_dev_t *dev)
1338 {
1339 audio_dev_suspend(dev->adev);
1340
1341 mutex_enter(&dev->mutex);
1342 dev->suspended = true;
1343 mutex_exit(&dev->mutex);
1344
1345 return (DDI_SUCCESS);
1346 }
1347
1348 static int
solo_resume(solo_dev_t * dev)1349 solo_resume(solo_dev_t *dev)
1350 {
1351 mutex_enter(&dev->mutex);
1352 if (!solo_init_hw(dev)) {
1353 /* yikes! */
1354 audio_dev_warn(dev->adev, "unable to resume audio!");
1355 audio_dev_warn(dev->adev, "reboot or reload driver to reset");
1356 }
1357 dev->suspended = false;
1358 mutex_exit(&dev->mutex);
1359
1360 audio_dev_resume(dev->adev);
1361
1362 return (DDI_SUCCESS);
1363 }
1364
1365 static int
solo_attach(dev_info_t * dip)1366 solo_attach(dev_info_t *dip)
1367 {
1368 solo_dev_t *dev;
1369 uint32_t data;
1370
1371 dev = kmem_zalloc(sizeof (*dev), KM_SLEEP);
1372 dev->dip = dip;
1373 ddi_set_driver_private(dip, dev);
1374
1375 dev->adev = audio_dev_alloc(dip, 0);
1376 if (dev->adev == NULL)
1377 goto no;
1378
1379 audio_dev_set_description(dev->adev, "ESS Solo-1 PCI AudioDrive");
1380 audio_dev_set_version(dev->adev, "ES1938");
1381
1382 if (pci_config_setup(dip, &dev->pcih) != DDI_SUCCESS) {
1383 audio_dev_warn(NULL, "pci_config_setup failed");
1384 goto no;
1385 }
1386
1387 data = pci_config_get16(dev->pcih, PCI_CONF_COMM);
1388 data |= PCI_COMM_ME | PCI_COMM_IO;
1389 pci_config_put16(dev->pcih, PCI_CONF_COMM, data);
1390
1391 if ((!solo_map_registers(dev)) ||
1392 (!solo_setup_interrupts(dev)) ||
1393 (!solo_alloc_engine(dev, 1)) ||
1394 (!solo_alloc_engine(dev, 2)) ||
1395 (!solo_add_controls(dev)) ||
1396 (!solo_init_hw(dev))) {
1397 goto no;
1398 }
1399
1400 if (audio_dev_register(dev->adev) != DDI_SUCCESS) {
1401 audio_dev_warn(dev->adev,
1402 "unable to register with audio framework");
1403 goto no;
1404 }
1405
1406 (void) ddi_intr_enable(dev->ihandle);
1407 ddi_report_dev(dip);
1408
1409 return (DDI_SUCCESS);
1410
1411 no:
1412 solo_release_resources(dev);
1413 return (DDI_FAILURE);
1414 }
1415
1416 static int
solo_detach(solo_dev_t * dev)1417 solo_detach(solo_dev_t *dev)
1418 {
1419 if (audio_dev_unregister(dev->adev) != DDI_SUCCESS) {
1420 return (DDI_FAILURE);
1421 }
1422
1423 solo_release_resources(dev);
1424 return (DDI_SUCCESS);
1425 }
1426
1427 static int
solo_ddi_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1428 solo_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1429 {
1430 solo_dev_t *dev;
1431
1432 switch (cmd) {
1433 case DDI_ATTACH:
1434 return (solo_attach(dip));
1435
1436 case DDI_RESUME:
1437 if ((dev = ddi_get_driver_private(dip)) == NULL) {
1438 return (DDI_FAILURE);
1439 }
1440 return (solo_resume(dev));
1441
1442 default:
1443 return (DDI_FAILURE);
1444 }
1445 }
1446
1447 static int
solo_ddi_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)1448 solo_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1449 {
1450 solo_dev_t *dev;
1451
1452 if ((dev = ddi_get_driver_private(dip)) == NULL) {
1453 return (DDI_FAILURE);
1454 }
1455
1456 switch (cmd) {
1457 case DDI_DETACH:
1458 return (solo_detach(dev));
1459
1460 case DDI_SUSPEND:
1461 return (solo_suspend(dev));
1462 default:
1463 return (DDI_FAILURE);
1464 }
1465 }
1466
1467 static int
solo_quiesce(dev_info_t * dip)1468 solo_quiesce(dev_info_t *dip)
1469 {
1470 solo_dev_t *dev;
1471
1472 dev = ddi_get_driver_private(dip);
1473
1474 solo_aud1_stop(&dev->rec);
1475 solo_aud2_stop(&dev->play);
1476
1477 solo_setmixer(dev, 0, 0);
1478 PORT_WR8(dev->io, 0x7, 0); /* disable all irqs */
1479 return (0);
1480 }
1481
1482 struct dev_ops solo_dev_ops = {
1483 DEVO_REV, /* rev */
1484 0, /* refcnt */
1485 NULL, /* getinfo */
1486 nulldev, /* identify */
1487 nulldev, /* probe */
1488 solo_ddi_attach, /* attach */
1489 solo_ddi_detach, /* detach */
1490 nodev, /* reset */
1491 NULL, /* cb_ops */
1492 NULL, /* bus_ops */
1493 NULL, /* power */
1494 solo_quiesce, /* quiesce */
1495 };
1496
1497 static struct modldrv solo_modldrv = {
1498 &mod_driverops, /* drv_modops */
1499 "ESS Solo-1 Audio", /* linkinfo */
1500 &solo_dev_ops, /* dev_ops */
1501 };
1502
1503 static struct modlinkage modlinkage = {
1504 MODREV_1,
1505 { &solo_modldrv, NULL }
1506 };
1507
1508 int
_init(void)1509 _init(void)
1510 {
1511 int rv;
1512
1513 audio_init_ops(&solo_dev_ops, DRVNAME);
1514 if ((rv = mod_install(&modlinkage)) != 0) {
1515 audio_fini_ops(&solo_dev_ops);
1516 }
1517 return (rv);
1518 }
1519
1520 int
_fini(void)1521 _fini(void)
1522 {
1523 int rv;
1524
1525 if ((rv = mod_remove(&modlinkage)) == 0) {
1526 audio_fini_ops(&solo_dev_ops);
1527 }
1528 return (rv);
1529 }
1530
1531 int
_info(struct modinfo * modinfop)1532 _info(struct modinfo *modinfop)
1533 {
1534 return (mod_info(&modlinkage, modinfop));
1535 }
1536