|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1992 Carnegie Mellon University
4: * All Rights Reserved.
5: *
6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
11: *
12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15: *
16: * Carnegie Mellon requests users of this software to return to
17: *
18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
22: *
23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26: /*
27: * File: isdn_79c30_hdw.c
28: * Author: Alessandro Forin, Carnegie Mellon University
29: * Date: 1/92
30: *
31: * Driver for the AMD 79c30 ISDN (Integrated Speech and
32: * Data Network) controller chip.
33: */
34:
35: /*-
36: * Copyright (c) 1991, 1992 The Regents of the University of California.
37: * All rights reserved.
38: *
39: * Redistribution and use in source and binary forms, with or without
40: * modification, are permitted provided that the following conditions
41: * are met:
42: * 1. Redistributions of source code must retain the above copyright
43: * notice, this list of conditions and the following disclaimer.
44: * 2. Redistributions in binary form must reproduce the above copyright
45: * notice, this list of conditions and the following disclaimer in the
46: * documentation and/or other materials provided with the distribution.
47: * 3. All advertising materials mentioning features or use of this software
48: * must display the following acknowledgement:
49: * This product includes software developed by the Computer Systems
50: * Engineering Group at Lawrence Berkeley Laboratory.
51: * 4. The name of the Laboratory may not be used to endorse or promote
52: * products derived from this software without specific prior written
53: * permission.
54: *
55: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65: * SUCH DAMAGE.
66: */
67:
68: #include <isdn.h>
69: #if NISDN > 0
70:
71: #include <platforms.h>
72:
73: #include <mach/std_types.h>
74: #include <machine/machspl.h>
75: #include <sys/ioctl.h> /* for Sun compat */
76: #include <chips/busses.h>
77:
78: #include <device/device_types.h>
79: #include <device/io_req.h>
80: #include <device/audio_status.h>
81: #include <chips/audio_defs.h>
82:
83: #include <chips/isdn_79c30.h>
84:
85: #include <chips/audio_config.h> /* machdep config */
86:
87: #define private static
88:
89: /*
90: * Autoconf info
91: */
92: private int isdn_probe (vm_offset_t reg, struct bus_ctlr *ui);
93: private void isdn_attach ( struct bus_device *ui);
94:
95: private vm_offset_t isdn_std[NISDN] = { 0 };
96: private struct bus_device *isdn_info[NISDN];
97:
98: struct bus_driver isdn_driver =
99: { isdn_probe, 0, isdn_attach, 0, isdn_std, "isdn", isdn_info, };
100:
101:
102: /*
103: * Externally visible functions and data
104: */
105: int isdn_intr();
106:
107:
108: /*
109: * Status bookeeping and globals
110: */
111: typedef struct {
112: amd79c30_padded_regs_t *regs;
113: void *audio_status; /* for upcalls */
114: struct mapreg sc_map; /* MAP status */
115: /*
116: * keep track of levels so we don't have to convert back from
117: * MAP gain constants
118: */
119: int sc_rlevel; /* record level */
120: int sc_plevel; /* play level */
121: int sc_mlevel; /* monitor level */
122: } isdn_softc_t;
123:
124: isdn_softc_t isdn_softc_data[NISDN];
125: isdn_softc_t *isdn_softc[NISDN];
126:
127: private int audio_default_level = 150;
128:
129:
130: /*
131: * Forward decls
132: */
133: audio_switch_t isdn_ops;
134:
135: private void isdn_init( isdn_softc_t *sc );
136:
137: private void isdn_set_mmr2(
138: register amd79c30_padded_regs_t *regs,
139: register int mmr2);
140:
141: private void isdn_setgains(
142: isdn_softc_t *sc,
143: int pgain,
144: int rgain,
145: int mgain);
146:
147: /*
148: * Probe chip to see if it is there
149: */
150: private isdn_probe(
151: vm_offset_t reg,
152: struct bus_ctlr *ui)
153: {
154: isdn_softc_t *sc = &isdn_softc_data[ui->unit];
155:
156: isdn_softc[ui->unit] = sc;
157: sc->regs = (amd79c30_padded_regs_t *)reg;
158:
159: return 1;
160: }
161:
162: /*
163: * Attach device to chip-indep driver(s)
164: */
165: private void
166: isdn_attach(
167: struct bus_device *ui)
168: {
169: register isdn_softc_t *sc = isdn_softc[ui->unit];
170: register amd79c30_padded_regs_t *regs = sc->regs;
171:
172: /* disable interrupts */
173: write_reg(regs->cr, AMDR_INIT);
174: write_reg(regs->dr, AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE);
175:
176: /*
177: * Initialize the mux unit. We use MCR3 to route audio (MAP)
178: * through channel Bb. MCR1 and MCR2 are unused.
179: * Setting the INT enable bit in MCR4 will generate an interrupt
180: * on each converted audio sample.
181: */
182: write_reg(regs->cr, AMDR_MUX_1_4);
183: write_reg(regs->dr, 0);
184: write_reg(regs->dr, 0);
185: write_reg(regs->dr, (AMD_MCRCHAN_BB << 4) | AMD_MCRCHAN_BA);
186: write_reg(regs->dr, AMD_MCR4_INT_ENABLE);
187:
188: printf(" AMD 79C30A/79C32A");
189:
190: audio_attach( sc, &isdn_ops, &sc->audio_status );
191: }
192:
193: /*
194: * Chip re-initialization
195: */
196: private void
197: isdn_init(
198: isdn_softc_t *sc)
199: {
200: register amd79c30_padded_regs_t *regs;
201:
202: bzero((char *)&sc->sc_map, sizeof sc->sc_map);
203: /* default to speaker */
204: sc->sc_map.mr_mmr2 = AMD_MMR2_AINB | AMD_MMR2_LS;
205:
206: /* enable interrupts and set parameters established above */
207: regs = sc->regs;
208: isdn_set_mmr2 (regs, sc->sc_map.mr_mmr2);
209: isdn_setgains (sc, audio_default_level, audio_default_level, 0);
210: write_reg(regs->cr, AMDR_INIT);
211: write_reg(regs->dr, AMD_INIT_PMS_ACTIVE);
212: }
213:
214: /*
215: * Chip shutdown
216: */
217: private void
218: isdn_close(
219: isdn_softc_t *sc)
220: {
221: register amd79c30_padded_regs_t *regs;
222:
223: regs = sc->regs;
224: write_reg(regs->cr, AMDR_INIT);
225: write_reg(regs->dr, AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE);
226: }
227:
228: /*
229: * Audio port selection
230: */
231: private void
232: isdn_setport(
233: isdn_softc_t *sc,
234: int port)
235: {
236: if (port == AUDIO_SPEAKER) {
237: sc->sc_map.mr_mmr2 |= AMD_MMR2_LS;
238: isdn_set_mmr2(sc->regs, sc->sc_map.mr_mmr2);
239: } else if (port == AUDIO_HEADPHONE) {
240: sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS;
241: isdn_set_mmr2(sc->regs, sc->sc_map.mr_mmr2);
242: }
243: }
244:
245: private int
246: isdn_getport(
247: isdn_softc_t *sc)
248: {
249: return (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ?
250: AUDIO_SPEAKER : AUDIO_HEADPHONE;
251: }
252:
253: /*
254: * Volume control
255: */
256: private void
257: isdn_setgains(
258: isdn_softc_t *sc,
259: int pgain,
260: int rgain,
261: int mgain)
262: {
263: private void isdn_set_pgain(), isdn_set_rgain(), isdn_set_mgain();
264:
265: if (pgain != ~0)
266: isdn_set_pgain(sc, pgain);
267: if (rgain != ~0)
268: isdn_set_rgain(sc, rgain);
269: if (mgain != ~0)
270: isdn_set_mgain(sc, mgain);
271:
272: }
273:
274: private void
275: isdn_getgains(
276: isdn_softc_t *sc,
277: int *pgain,
278: int *rgain,
279: int *mgain)
280: {
281: *mgain = sc->sc_mlevel;
282: *rgain = sc->sc_rlevel;
283: *pgain = sc->sc_plevel;
284: }
285:
286:
287: /*
288: * User control over MAP processor
289: */
290: private io_return_t
291: isdn_setstate(
292: isdn_softc_t *sc,
293: dev_flavor_t flavor,
294: register struct mapreg *map,
295: natural_t n_ints)
296: {
297: register amd79c30_padded_regs_t *regs = sc->regs;
298: register int i, v;
299: spl_t s;
300:
301: /* Sun compat */
302: if (flavor == AUDIOSETREG) {
303: register struct audio_ioctl *a = (struct audio_ioctl *)map;
304: s = splaudio();
305: write_reg(regs->cr, (a->control >> 8) & 0xff);
306: for (i = 0; i < (a->control & 0xff); i++) {
307: write_reg(regs->dr, a->data[i]);
308: }
309: splx(s);
310: return D_SUCCESS;
311: }
312:
313: if (flavor != AUDIO_SETMAP)
314: return D_INVALID_OPERATION;
315:
316: if ((n_ints * sizeof(int)) < sizeof(*map))
317: return D_INVALID_SIZE;
318:
319: bcopy(map, &sc->sc_map, sizeof(sc->sc_map));
320: sc->sc_map.mr_mmr2 &= 0x7f;
321:
322: s = splaudio();
323: write_reg(regs->cr, AMDR_MAP_1_10);
324: for (i = 0; i < 8; i++) {
325: v = map->mr_x[i];
326: WAMD16(regs, v);
327: }
328: for (i = 0; i < 8; ++i) {
329: v = map->mr_r[i];
330: WAMD16(regs, v);
331: }
332: v = map->mr_gx; WAMD16(regs, v);
333: v = map->mr_gr; WAMD16(regs, v);
334: v = map->mr_ger; WAMD16(regs, v);
335: v = map->mr_stgr; WAMD16(regs, v);
336: v = map->mr_ftgr; WAMD16(regs, v);
337: v = map->mr_atgr; WAMD16(regs, v);
338: write_reg(regs->dr, map->mr_mmr1);
339: write_reg(regs->dr, map->mr_mmr2);
340: splx(s);
341: return D_SUCCESS;
342: }
343:
344: private io_return_t
345: isdn_getstate(
346: isdn_softc_t *sc,
347: dev_flavor_t flavor,
348: register struct mapreg *map,
349: natural_t *count)
350: {
351: register amd79c30_padded_regs_t *regs = sc->regs;
352: spl_t s;
353: int i;
354:
355: /* Sun compat */
356: if (flavor == AUDIOGETREG) {
357: register struct audio_ioctl *a = (struct audio_ioctl *)map;
358: s = splaudio();
359: write_reg(regs->cr, (a->control >> 8) & 0xff);
360: for (i = 0; i < (a->control & 0xff); i++) {
361: read_reg(regs->dr,a->data[i]);
362: }
363: splx(s);
364: *count = sizeof(*a) / sizeof(int);
365: return D_SUCCESS;
366: }
367:
368: if ( (*count * sizeof(int)) < sizeof(*map))
369: return D_INVALID_SIZE;
370: bcopy(&sc->sc_map, map, sizeof(sc->sc_map));
371: *count = sizeof(*map) / sizeof(int);
372: return D_SUCCESS;
373: }
374:
375:
376:
377: /*
378: * Set the mmr1 register and one other 16 bit register in the audio chip.
379: * The other register is indicated by op and val.
380: */
381: private void
382: isdn_set_mmr1(
383: register amd79c30_padded_regs_t *regs,
384: register int mmr1,
385: register int op,
386: register int val)
387: {
388: register int s = splaudio();
389:
390: write_reg(regs->cr, AMDR_MAP_MMR1);
391: write_reg(regs->dr, mmr1);
392: write_reg(regs->cr, op);
393: WAMD16(regs, val);
394: splx(s);
395: }
396:
397: /*
398: * Set the mmr2 register.
399: */
400: private void
401: isdn_set_mmr2(
402: register amd79c30_padded_regs_t *regs,
403: register int mmr2)
404: {
405: register int s = splaudio();
406:
407: write_reg(regs->cr, AMDR_MAP_MMR2);
408: write_reg(regs->dr, mmr2);
409: splx(s);
410: }
411:
412: /*
413: * gx, gr & stg gains. this table must contain 256 elements with
414: * the 0th being "infinity" (the magic value 9008). The remaining
415: * elements match sun's gain curve (but with higher resolution):
416: * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
417: */
418: private const unsigned short gx_coeff[256] = {
419: 0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33,
420: 0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
421: 0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
422: 0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
423: 0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
424: 0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
425: 0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
426: 0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
427: 0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
428: 0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
429: 0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
430: 0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
431: 0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
432: 0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
433: 0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
434: 0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
435: 0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
436: 0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
437: 0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
438: 0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
439: 0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
440: 0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
441: 0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
442: 0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
443: 0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
444: 0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
445: 0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
446: 0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
447: 0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
448: 0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
449: 0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
450: 0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
451: };
452:
453: /*
454: * second stage play gain.
455: */
456: private const unsigned short ger_coeff[] = {
457: 0x431f, /* 5. dB */
458: 0x331f, /* 5.5 dB */
459: 0x40dd, /* 6. dB */
460: 0x11dd, /* 6.5 dB */
461: 0x440f, /* 7. dB */
462: 0x411f, /* 7.5 dB */
463: 0x311f, /* 8. dB */
464: 0x5520, /* 8.5 dB */
465: 0x10dd, /* 9. dB */
466: 0x4211, /* 9.5 dB */
467: 0x410f, /* 10. dB */
468: 0x111f, /* 10.5 dB */
469: 0x600b, /* 11. dB */
470: 0x00dd, /* 11.5 dB */
471: 0x4210, /* 12. dB */
472: 0x110f, /* 13. dB */
473: 0x7200, /* 14. dB */
474: 0x2110, /* 15. dB */
475: 0x2200, /* 15.9 dB */
476: 0x000b, /* 16.9 dB */
477: 0x000f /* 18. dB */
478: #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
479: };
480:
481: private void
482: isdn_set_rgain(
483: register isdn_softc_t *sc,
484: register int level)
485: {
486: level &= 0xff;
487: sc->sc_rlevel = level;
488: sc->sc_map.mr_mmr1 |= AMD_MMR1_GX;
489: sc->sc_map.mr_gx = gx_coeff[level];
490: isdn_set_mmr1(sc->regs, sc->sc_map.mr_mmr1,
491: AMDR_MAP_GX, sc->sc_map.mr_gx);
492: }
493:
494: private void
495: isdn_set_pgain(
496: register isdn_softc_t *sc,
497: register int level)
498: {
499: register int gi, s;
500: register amd79c30_padded_regs_t *regs;
501:
502: level &= 0xff;
503: sc->sc_plevel = level;
504: sc->sc_map.mr_mmr1 |= AMD_MMR1_GER|AMD_MMR1_GR;
505: level *= 256 + NGER;
506: level >>= 8;
507: if (level >= 256) {
508: gi = level - 256;
509: level = 255;
510: } else
511: gi = 0;
512: sc->sc_map.mr_ger = ger_coeff[gi];
513: sc->sc_map.mr_gr = gx_coeff[level];
514:
515: regs = sc->regs;
516: s = splaudio();
517: write_reg(regs->cr, AMDR_MAP_MMR1);
518: write_reg(regs->dr, sc->sc_map.mr_mmr1);
519: write_reg(regs->cr, AMDR_MAP_GR);
520: gi = sc->sc_map.mr_gr;
521: WAMD16(regs, gi);
522: write_reg(regs->cr, AMDR_MAP_GER);
523: gi = sc->sc_map.mr_ger;
524: WAMD16(regs, gi);
525: splx(s);
526: }
527:
528: private void
529: isdn_set_mgain(
530: register isdn_softc_t *sc,
531: register int level)
532: {
533: level &= 0xff;
534: sc->sc_mlevel = level;
535: sc->sc_map.mr_mmr1 |= AMD_MMR1_STG;
536: sc->sc_map.mr_stgr = gx_coeff[level];
537: isdn_set_mmr1(sc->regs, sc->sc_map.mr_mmr1,
538: AMDR_MAP_STG, sc->sc_map.mr_stgr);
539: }
540:
541: /*
542: * Interrupt routine
543: */
544: #if old
545: isdn_intr (unit, spllevel)
546: spl_t spllevel;
547: {
548: #ifdef MAXINE
549: xine_enable_interrupt(7, 0, 0);
550: #endif
551: #ifdef FLAMINGO
552: kn15aa_enable_interrupt(12, 0, 0);
553: #endif
554: printf("ISDN interrupt");
555: }
556: #else
557: isdn_intr (unit, spllevel)
558: spl_t spllevel;
559: {
560: isdn_softc_t *sc = isdn_softc[unit];
561: amd79c30_padded_regs_t *regs = sc->regs;
562: register int i;
563: unsigned int c;
564:
565: read_reg(regs->ir, i); mb(); /* clear interrupt, now */
566: #if mips
567: splx(spllevel); /* drop priority */
568: #endif
569:
570: #if 0
571: if (..this is an audio interrupt..)
572: #endif
573: {
574: read_reg(regs->bbrb, c);
575: if (audio_hwintr(sc->audio_status, c, &c))
576: write_reg(regs->bbtb, c);
577: }
578: }
579: #endif
580:
581:
582:
583: /*
584: * Standard operations vector
585: */
586: audio_switch_t isdn_ops = {
587: isdn_init,
588: isdn_close,
589: isdn_setport,
590: isdn_getport,
591: isdn_setgains,
592: isdn_getgains,
593: isdn_setstate,
594: isdn_getstate
595: };
596:
597: #if 1
598: write_an_int(int *where, int what) { *where = what;}
599: read_an_int(int *where) { return *where;}
600: #endif
601:
602: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.