Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / i386 / isa / sound / pss.c
1 /*
2  * sound/pss.c
3  * 
4  * The low level driver for the Personal Sound System (ECHO ESC614).
5  * 
6  * Copyright by Hannu Savolainen 1993
7  * 
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met: 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer. 2.
12  * Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23  * 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  */
29
30 #include <i386/isa/sound/sound_config.h>
31
32 #if defined(CONFIG_PSS) && defined(CONFIG_AUDIO)
33
34 /*
35  * PSS registers.
36  */
37 #define REG(x)  (devc->base+x)
38 #define PSS_DATA        0
39 #define PSS_STATUS      2
40 #define PSS_CONTROL     2
41 #define PSS_ID          4
42 #define PSS_IRQACK      4
43 #define PSS_PIO         0x1a
44
45 /*
46  * Config registers
47  */
48 #define CONF_PSS        0x10
49 #define CONF_WSS        0x12
50 #define CONF_SB         0x13
51 #define CONF_CDROM      0x16
52 #define CONF_MIDI       0x18
53
54 /*
55  * Status bits.
56  */
57 #define PSS_FLAG3     0x0800
58 #define PSS_FLAG2     0x0400
59 #define PSS_FLAG1     0x1000
60 #define PSS_FLAG0     0x0800
61 #define PSS_WRITE_EMPTY  0x8000
62 #define PSS_READ_FULL    0x4000
63
64 #include "coproc.h"
65
66 #ifdef PSS_HAVE_LD
67 #include "synth-ld.h"
68 #else
69 static int      pss_synthLen = 0;
70 static u_char pss_synth[1] =
71 {0};
72
73 #endif
74
75 typedef struct pss_config {
76         int             base;
77         int             irq;
78         int             dma;
79         sound_os_info  *osp;
80 } pss_config;
81
82 static pss_config pss_data;
83 static pss_config *devc = &pss_data;
84
85 static int      pss_initialized = 0;
86 static int      nonstandard_microcode = 0;
87
88 int
89 probe_pss(struct address_info * hw_config)
90 {
91         u_short  id;
92         int             irq, dma;
93
94         devc->base = hw_config->io_base;
95         irq = devc->irq = hw_config->irq;
96         dma = devc->dma = hw_config->dma;
97         devc->osp = hw_config->osp;
98
99         /* these are the possible addresses */
100         if (devc->base != 0x220 && devc->base != 0x240 &&
101             devc->base != 0x230 && devc->base != 0x250)
102                         return 0;
103
104         /* these are the possible irqs */
105         if (irq != 3 && irq != 5 && irq != 7 && irq != 9 &&
106             irq != 10 && irq != 11 && irq != 12)
107                 return 0;
108
109         /* and these are the possible dmas */
110         if (dma != 5 && dma != 6 && dma != 7)
111                 return 0;
112
113         id = inb(REG(PSS_ID));
114
115         /* XXX the following test cannot possibly succeed! - lr970714 */
116         if ((id >> 8) != 'E') {
117                 /*
118                  * printf ("No PSS signature detected at 0x%x (0x%x)\n",
119                  * devc->base, id);
120                  */
121                 return 0;
122         }
123         return 1;
124 }
125
126 static int
127 set_irq(pss_config * devc, int dev, int irq)
128 {
129         static u_short irq_bits[16] =
130         {
131                 0x0000, 0x0000, 0x0000, 0x0008,
132                 0x0000, 0x0010, 0x0000, 0x0018,
133                 0x0000, 0x0020, 0x0028, 0x0030,
134                 0x0038, 0x0000, 0x0000, 0x0000
135         };
136
137         u_short  tmp, bits;
138
139         if (irq < 0 || irq > 15)
140                 return 0;
141
142         tmp = inb(REG(dev)) & ~0x38;    /* Load confreg, mask IRQ bits out */
143
144         if ((bits = irq_bits[irq]) == 0 && irq != 0) {
145                 printf("PSS: Invalid IRQ %d\n", irq);
146                 return 0;
147         }
148         outw(REG(dev), tmp | bits);
149         return 1;
150 }
151
152 static int
153 set_io_base(pss_config * devc, int dev, int base)
154 {
155         u_short  tmp = inb(REG(dev)) & 0x003f;
156         u_short  bits = (base & 0x0ffc) << 4;
157
158         outw(REG(dev), bits | tmp);
159
160         return 1;
161 }
162
163 static int
164 set_dma(pss_config * devc, int dev, int dma)
165 {
166         static u_short dma_bits[8] =
167         {
168                 0x0001, 0x0002, 0x0000, 0x0003,
169                 0x0000, 0x0005, 0x0006, 0x0007
170         };
171
172         u_short  tmp, bits;
173
174         if (dma < 0 || dma > 7)
175                 return 0;
176
177         tmp = inb(REG(dev)) & ~0x07;    /* Load confreg, mask DMA bits out */
178
179         if ((bits = dma_bits[dma]) == 0 && dma != 4) {
180                 printf("PSS: Invalid DMA %d\n", dma);
181                 return 0;
182         }
183         outw(REG(dev), tmp | bits);
184         return 1;
185 }
186
187 static int
188 pss_reset_dsp(pss_config * devc)
189 {
190         u_long   i, limit = get_time() + 10;
191
192         outw(REG(PSS_CONTROL), 0x2000);
193
194         for (i = 0; i < 32768 && get_time() < limit; i++)
195                 inb(REG(PSS_CONTROL));
196
197         outw(REG(PSS_CONTROL), 0x0000);
198
199         return 1;
200 }
201
202 static int
203 pss_put_dspword(pss_config * devc, u_short word)
204 {
205         int             i, val;
206
207         for (i = 0; i < 327680; i++) {
208                 val = inb(REG(PSS_STATUS));
209                 if (val & PSS_WRITE_EMPTY) {
210                         outw(REG(PSS_DATA), word);
211                         return 1;
212                 }
213         }
214         return 0;
215 }
216
217 static int
218 pss_get_dspword(pss_config * devc, u_short *word)
219 {
220         int             i, val;
221
222         for (i = 0; i < 327680; i++) {
223                 val = inb(REG(PSS_STATUS));
224                 if (val & PSS_READ_FULL) {
225                         *word = inb(REG(PSS_DATA));
226                         return 1;
227                 }
228         }
229
230         return 0;
231 }
232
233 static int
234 pss_download_boot(pss_config * devc, u_char *block, int size, int flags)
235 {
236         int             i, limit, val, count;
237
238         if (flags & CPF_FIRST) {
239                 /* _____ Warn DSP software that a boot is coming */
240                 outw(REG(PSS_DATA), 0x00fe);
241
242                 limit = get_time() + 10;
243
244                 for (i = 0; i < 32768 && get_time() < limit; i++)
245                         if (inb(REG(PSS_DATA)) == 0x5500)
246                                 break;
247
248                 outw(REG(PSS_DATA), *block++);
249
250                 pss_reset_dsp(devc);
251         }
252         count = 1;
253         while (1) {
254                 int             j;
255
256                 for (j = 0; j < 327670; j++) {
257                         /* _____ Wait for BG to appear */
258                         if (inb(REG(PSS_STATUS)) & PSS_FLAG3)
259                                 break;
260                 }
261
262                 if (j == 327670) {
263                         /* It's ok we timed out when the file was empty */
264                         if (count >= size && flags & CPF_LAST)
265                                 break;
266                         else {
267                                 printf("\nPSS: DownLoad timeout problems, byte %d=%d\n",
268                                        count, size);
269                                 return 0;
270                         }
271                 }
272                 /* _____ Send the next byte */
273                 outw(REG(PSS_DATA), *block++);
274                 count++;
275         }
276
277         if (flags & CPF_LAST) {
278                 /* _____ Why */
279                 outw(REG(PSS_DATA), 0);
280
281                 limit = get_time() + 10;
282                 for (i = 0; i < 32768 && get_time() < limit; i++)
283                         val = inb(REG(PSS_STATUS));
284
285                 limit = get_time() + 10;
286                 for (i = 0; i < 32768 && get_time() < limit; i++) {
287                         val = inb(REG(PSS_STATUS));
288                         if (val & 0x4000)
289                                 break;
290                 }
291
292                 /* now read the version */
293                 for (i = 0; i < 32000; i++) {
294                         val = inb(REG(PSS_STATUS));
295                         if (val & PSS_READ_FULL)
296                                 break;
297                 }
298                 if (i == 32000)
299                         return 0;
300
301                 val = inb(REG(PSS_DATA));
302                 /*
303                  * printf("<PSS: microcode version %d.%d loaded>", val/16,
304                  * val % 16);
305                  */
306         }
307         return 1;
308 }
309
310 void
311 attach_pss(struct address_info * hw_config)
312 {
313         u_short  id;
314         char            tmp[100];
315
316         devc->base = hw_config->io_base;
317         devc->irq = hw_config->irq;
318         devc->dma = hw_config->dma;
319         devc->osp = hw_config->osp;
320
321         if (!probe_pss(hw_config))
322                 return;
323
324         id = inb(REG(PSS_ID)) & 0x00ff;
325
326         /*
327          * Disable all emulations. Will be enabled later (if required).
328          */
329         outw(REG(CONF_PSS), 0x0000);
330         outw(REG(CONF_WSS), 0x0000);
331         outw(REG(CONF_SB), 0x0000);
332         outw(REG(CONF_MIDI), 0x0000);
333         outw(REG(CONF_CDROM), 0x0000);
334
335 #if YOU_REALLY_WANT_TO_ALLOCATE_THESE_RESOURCES
336         if (0) {
337                 printf("pss.c: Can't allocate DMA channel\n");
338                 return;
339         }
340         if (!set_irq(devc, CONF_PSS, devc->irq)) {
341                 printf("PSS: IRQ error\n");
342                 return;
343         }
344         if (!set_dma(devc, CONF_PSS, devc->dma)) {
345                 printf("PSS: DRQ error\n");
346                 return;
347         }
348 #endif
349
350         pss_initialized = 1;
351         snprintf(tmp, sizeof(tmp), "ECHO-PSS  Rev. %d", id);
352         conf_printf(tmp, hw_config);
353
354         return;
355 }
356
357 int
358 probe_pss_mpu(struct address_info * hw_config)
359 {
360         int             timeout;
361
362         if (!pss_initialized)
363                 return 0;
364
365         if (0) {
366                 printf("PSS: MPU I/O port conflict\n");
367                 return 0;
368         }
369         if (!set_io_base(devc, CONF_MIDI, hw_config->io_base)) {
370                 printf("PSS: MIDI base error.\n");
371                 return 0;
372         }
373         if (!set_irq(devc, CONF_MIDI, hw_config->irq)) {
374                 printf("PSS: MIDI IRQ error.\n");
375                 return 0;
376         }
377         if (!pss_synthLen) {
378                 printf("PSS: Can't enable MPU. MIDI synth microcode not available.\n");
379                 return 0;
380         }
381         if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) {
382                 printf("PSS: Unable to load MIDI synth microcode to DSP.\n");
383                 return 0;
384         }
385         /*
386          * Finally wait until the DSP algorithm has initialized itself and
387          * deactivates receive interrupt.
388          */
389
390         for (timeout = 900000; timeout > 0; timeout--) {
391                 if ((inb(hw_config->io_base + 1) & 0x80) == 0)  /* Input data avail */
392                         inb(hw_config->io_base);        /* Discard it */
393                 else
394                         break;  /* No more input */
395         }
396
397 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
398         return probe_mpu401(hw_config);
399 #else
400         return 0
401 #endif
402 }
403
404 static int
405 pss_coproc_open(void *dev_info, int sub_device)
406 {
407         switch (sub_device) {
408                 case COPR_MIDI:
409
410                 if (pss_synthLen == 0) {
411                         printf("PSS: MIDI synth microcode not available.\n");
412                         return -(EIO);
413                 }
414                 if (nonstandard_microcode)
415                         if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) {
416                                 printf("PSS: Unable to load MIDI synth microcode to DSP.\n");
417                                 return -(EIO);
418                         }
419                 nonstandard_microcode = 0;
420                 break;
421
422         default:;
423         }
424         return 0;
425 }
426
427 static void
428 pss_coproc_close(void *dev_info, int sub_device)
429 {
430         return;
431 }
432
433 static void
434 pss_coproc_reset(void *dev_info)
435 {
436         if (pss_synthLen)
437                 if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) {
438                         printf("PSS: Unable to load MIDI synth microcode to DSP.\n");
439                 }
440         nonstandard_microcode = 0;
441 }
442
443 static int
444 download_boot_block(void *dev_info, copr_buffer * buf)
445 {
446         if (buf->len <= 0 || buf->len > sizeof(buf->data))
447                 return -(EINVAL);
448
449         if (!pss_download_boot(devc, buf->data, buf->len, buf->flags)) {
450                 printf("PSS: Unable to load microcode block to DSP.\n");
451                 return -(EIO);
452         }
453         nonstandard_microcode = 1;      /* The MIDI microcode has been
454                                          * overwritten */
455
456         return 0;
457 }
458
459 static int
460 pss_coproc_ioctl(void *dev_info, u_int cmd, ioctl_arg arg, int local)
461 {
462         /* printf("PSS coproc ioctl %x %x %d\n", cmd, arg, local); */
463
464         switch (cmd) {
465                 case SNDCTL_COPR_RESET:
466                 pss_coproc_reset(dev_info);
467                 return 0;
468                 break;
469
470         case SNDCTL_COPR_LOAD:
471                 {
472                         copr_buffer    *buf;
473                         int             err;
474
475                         buf = (copr_buffer *) malloc(sizeof(copr_buffer), M_TEMP, M_WAITOK);
476                         if (buf == NULL)
477                                 return -(ENOSPC);
478
479                         bcopy(&(((char *) arg)[0]), (char *) buf, sizeof(*buf));
480                         err = download_boot_block(dev_info, buf);
481                         free(buf, M_TEMP);
482                         return err;
483                 }
484                 break;
485
486         case SNDCTL_COPR_RDATA:
487                 {
488                         copr_debug_buf  buf;
489                         u_long   flags;
490                         u_short  tmp;
491
492                         bcopy(&(((char *) arg)[0]), (char *) &buf, sizeof(buf));
493
494                         flags = splhigh();
495                         if (!pss_put_dspword(devc, 0x00d0)) {
496                                 splx(flags);
497                                 return -(EIO);
498                         }
499                         if (!pss_put_dspword(devc, (u_short) (buf.parm1 & 0xffff))) {
500                                 splx(flags);
501                                 return -(EIO);
502                         }
503                         if (!pss_get_dspword(devc, &tmp)) {
504                                 splx(flags);
505                                 return -(EIO);
506                         }
507                         buf.parm1 = tmp;
508                         splx(flags);
509
510                         bcopy(&buf, &(((char *) arg)[0]), sizeof(buf));
511                         return 0;
512                 }
513                 break;
514
515         case SNDCTL_COPR_WDATA:
516                 {
517                         copr_debug_buf  buf;
518                         u_long   flags;
519                         u_short  tmp;
520
521                         bcopy(&(((char *) arg)[0]), (char *) &buf, sizeof(buf));
522
523                         flags = splhigh();
524                         if (!pss_put_dspword(devc, 0x00d1)) {
525                                 splx(flags);
526                                 return -(EIO);
527                         }
528                         if (!pss_put_dspword(devc, (u_short) (buf.parm1 & 0xffff))) {
529                                 splx(flags);
530                                 return -(EIO);
531                         }
532                         tmp = (u_int) buf.parm2 & 0xffff;
533                         if (!pss_put_dspword(devc, tmp)) {
534                                 splx(flags);
535                                 return -(EIO);
536                         }
537                         splx(flags);
538                         return 0;
539                 }
540                 break;
541
542         case SNDCTL_COPR_WCODE:
543                 {
544                         copr_debug_buf  buf;
545                         u_long   flags;
546                         u_short  tmp;
547
548                         bcopy(&(((char *) arg)[0]), (char *) &buf, sizeof(buf));
549
550                         flags = splhigh();
551                         if (!pss_put_dspword(devc, 0x00d3)) {
552                                 splx(flags);
553                                 return -(EIO);
554                         }
555                         if (!pss_put_dspword(devc, (u_short) (buf.parm1 & 0xffff))) {
556                                 splx(flags);
557                                 return -(EIO);
558                         }
559                         tmp = ((u_int) buf.parm2 >> 8) & 0xffff;
560                         if (!pss_put_dspword(devc, tmp)) {
561                                 splx(flags);
562                                 return -(EIO);
563                         }
564                         tmp = (u_int) buf.parm2 & 0x00ff;
565                         if (!pss_put_dspword(devc, tmp)) {
566                                 splx(flags);
567                                 return -(EIO);
568                         }
569                         splx(flags);
570                         return 0;
571                 }
572                 break;
573
574         case SNDCTL_COPR_RCODE:
575                 {
576                         copr_debug_buf  buf;
577                         u_long   flags;
578                         u_short  tmp;
579
580                         bcopy(&(((char *) arg)[0]), (char *) &buf, sizeof(buf));
581
582                         flags = splhigh();
583                         if (!pss_put_dspword(devc, 0x00d2)) {
584                                 splx(flags);
585                                 return -(EIO);
586                         }
587                         if (!pss_put_dspword(devc, (u_short) (buf.parm1 & 0xffff))) {
588                                 splx(flags);
589                                 return -(EIO);
590                         }
591                         if (!pss_get_dspword(devc, &tmp)) {     /* Read msb */
592                                 splx(flags);
593                                 return -(EIO);
594                         }
595                         buf.parm1 = tmp << 8;
596
597                         if (!pss_get_dspword(devc, &tmp)) {     /* Read lsb */
598                                 splx(flags);
599                                 return -(EIO);
600                         }
601                         buf.parm1 |= tmp & 0x00ff;
602
603                         splx(flags);
604
605                         bcopy(&buf, &(((char *) arg)[0]), sizeof(buf));
606                         return 0;
607                 }
608                 break;
609
610         default:
611                 return -(EINVAL);
612         }
613
614         return -(EINVAL);
615 }
616
617 static coproc_operations pss_coproc_operations =
618 {
619         "ADSP-2115",
620         pss_coproc_open,
621         pss_coproc_close,
622         pss_coproc_ioctl,
623         pss_coproc_reset,
624         &pss_data
625 };
626
627 void
628 attach_pss_mpu(struct address_info * hw_config)
629 {
630         int             prev_devs;
631
632 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
633         prev_devs = num_midis;
634         attach_mpu401(hw_config);
635
636         if (num_midis == (prev_devs + 1))       /* The MPU driver installed
637                                                  * itself */
638                 midi_devs[prev_devs]->coproc = &pss_coproc_operations;
639 #endif
640 }
641
642 int
643 probe_pss_mss(struct address_info * hw_config)
644 {
645         int             timeout;
646
647         if (!pss_initialized)
648                 return 0;
649
650         if (0) {
651                 printf("PSS: WSS I/O port conflict\n");
652                 return 0;
653         }
654         if (!set_io_base(devc, CONF_WSS, hw_config->io_base)) {
655                 printf("PSS: WSS base error.\n");
656                 return 0;
657         }
658         if (!set_irq(devc, CONF_WSS, hw_config->irq)) {
659                 printf("PSS: WSS IRQ error.\n");
660                 return 0;
661         }
662         if (!set_dma(devc, CONF_WSS, hw_config->dma)) {
663                 printf("PSS: WSS DRQ error\n");
664                 return 0;
665         }
666         /*
667          * For some reason the card returns 0xff in the WSS status register
668          * immediately after boot. Propably MIDI+SB emulation algorithm
669          * downloaded to the ADSP2115 spends some time initializing the card.
670          * Let's try to wait until it finishes this task.
671          */
672         for (timeout = 0;
673            timeout < 100000 && (inb(hw_config->io_base + 3) & 0x3f) != 0x04;
674              timeout++);
675
676         return probe_mss(hw_config);
677 }
678
679 void
680 attach_pss_mss(struct address_info * hw_config)
681 {
682         int             prev_devs;
683         long            ret;
684
685         prev_devs = num_audiodevs;
686         attach_mss(hw_config);
687
688         /* Check if The MSS driver installed itself */
689         if (num_audiodevs == (prev_devs + 1))
690                 audio_devs[prev_devs]->coproc = &pss_coproc_operations;
691 }
692
693 #endif