* better
[mascara-docs.git] / i386 / linux-2.3.21 / drivers / sbus / audio / amd7930.c
blobe61d74793fa7cbc7bbcd1cc0bd99fcddcfd7b767
1 /*
2 * drivers/sbus/audio/amd7930.c
4 * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu)
6 * This is the lowlevel driver for the AMD7930 audio chip found on all
7 * sun4c machines and some sun4m machines.
9 * The amd7930 is actually an ISDN chip which has a very simple
10 * integrated audio encoder/decoder. When Sun decided on what chip to
11 * use for audio, they had the brilliant idea of using the amd7930 and
12 * only connecting the audio encoder/decoder pins.
14 * Thanks to the AMD engineer who was able to get us the AMD79C30
15 * databook which has all the programming information and gain tables.
17 * Advanced Micro Devices' Am79C30A is an ISDN/audio chip used in the
18 * SparcStation 1+. The chip provides microphone and speaker interfaces
19 * which provide mono-channel audio at 8K samples per second via either
20 * 8-bit A-law or 8-bit mu-law encoding. Also, the chip features an
21 * ISDN BRI Line Interface Unit (LIU), I.430 S/T physical interface,
22 * which performs basic D channel LAPD processing and provides raw
23 * B channel data. The digital audio channel, the two ISDN B channels,
24 * and two 64 Kbps channels to the microprocessor are all interconnected
25 * via a multiplexer.
27 * This driver interfaces to the Linux HiSax ISDN driver, which performs
28 * all high-level Q.921 and Q.931 ISDN functions. The file is not
29 * itself a hardware driver; rather it uses functions exported by
30 * the AMD7930 driver in the sparcaudio subsystem (drivers/sbus/audio),
31 * allowing the chip to be simultaneously used for both audio and ISDN data.
32 * The hardware driver does _no_ buffering, but provides several callbacks
33 * which are called during interrupt service and should therefore run quickly.
35 * D channel transmission is performed by passing the hardware driver the
36 * address and size of an skb's data area, then waiting for a callback
37 * to signal successful transmission of the packet. A task is then
38 * queued to notify the HiSax driver that another packet may be transmitted.
40 * D channel reception is quite simple, mainly because of:
41 * 1) the slow speed of the D channel - 16 kbps, and
42 * 2) the presence of an 8- or 32-byte (depending on chip version) FIFO
43 * to buffer the D channel data on the chip
44 * Worst case scenario of back-to-back packets with the 8 byte buffer
45 * at 16 kbps yields an service time of 4 ms - long enough to preclude
46 * the need for fancy buffering. We queue a background task that copies
47 * data out of the receive buffer into an skb, and the hardware driver
48 * simply does nothing until we're done with the receive buffer and
49 * reset it for a new packet.
51 * B channel processing is more complex, because of:
52 * 1) the faster speed - 64 kbps,
53 * 2) the lack of any on-chip buffering (it interrupts for every byte), and
54 * 3) the lack of any chip support for HDLC encapsulation
56 * The HiSax driver can put each B channel into one of three modes -
57 * L1_MODE_NULL (channel disabled), L1_MODE_TRANS (transparent data relay),
58 * and L1_MODE_HDLC (HDLC encapsulation by low-level driver).
59 * L1_MODE_HDLC is the most common, used for almost all "pure" digital
60 * data sessions. L1_MODE_TRANS is used for ISDN audio.
62 * HDLC B channel transmission is performed via a large buffer into
63 * which the skb is copied while performing HDLC bit-stuffing. A CRC
64 * is computed and attached to the end of the buffer, which is then
65 * passed to the low-level routines for raw transmission. Once
66 * transmission is complete, the hardware driver is set to enter HDLC
67 * idle by successive transmission of mark (all 1) bytes, waiting for
68 * the ISDN driver to prepare another packet for transmission and
69 * deliver it.
71 * HDLC B channel reception is performed via an X-byte ring buffer
72 * divided into N sections of X/N bytes each. Defaults: X=256 bytes, N=4.
73 * As the hardware driver notifies us that each section is full, we
74 * hand it the next section and schedule a background task to peruse
75 * the received section, bit-by-bit, with an HDLC decoder. As
76 * packets are detected, they are copied into a large buffer while
77 * decoding HDLC bit-stuffing. The ending CRC is verified, and if
78 * it is correct, we alloc a new skb of the correct length (which we
79 * now know), copy the packet into it, and hand it to the upper layers.
80 * Optimization: for large packets, we hand the buffer (which also
81 * happens to be an skb) directly to the upper layer after an skb_trim,
82 * and alloc a new large buffer for future packets, thus avoiding a copy.
83 * Then we return to HDLC processing; state is saved between calls.
86 #include <linux/module.h>
87 #include <linux/kernel.h>
88 #include <linux/sched.h>
89 #include <linux/errno.h>
90 #include <linux/interrupt.h>
91 #include <linux/malloc.h>
92 #include <linux/init.h>
93 #include <linux/version.h>
94 #include <linux/soundcard.h>
95 #include <asm/openprom.h>
96 #include <asm/oplib.h>
97 #include <asm/system.h>
98 #include <asm/irq.h>
99 #include <asm/io.h>
100 #include <asm/sbus.h>
102 #include <asm/audioio.h>
103 #include "amd7930.h"
105 static __u8 bilinear2mulaw(__u8 data);
106 static __u8 mulaw2bilinear(__u8 data);
107 static __u8 linear2mulaw(__u16 data);
108 static __u16 mulaw2linear(__u8 data);
110 #if defined (AMD79C30_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff
111 #include "../../isdn/hisax/hisax.h"
112 #include "../../isdn/hisax/isdnl1.h"
113 #include "../../isdn/hisax/foreign.h"
114 #endif
116 #define MAX_DRIVERS 1
118 static struct sparcaudio_driver drivers[MAX_DRIVERS];
119 static int num_drivers;
121 /* Each amd7930 chip has two bi-directional B channels and a D
122 * channel available to the uproc. This structure handles all
123 * the buffering needed to transmit and receive via a single channel.
126 #define CHANNEL_AVAILABLE 0x00
127 #define CHANNEL_INUSE_AUDIO_IN 0x01
128 #define CHANNEL_INUSE_AUDIO_OUT 0x02
129 #define CHANNEL_INUSE_ISDN_B1 0x04
130 #define CHANNEL_INUSE_ISDN_B2 0x08
131 #define CHANNEL_INUSE 0xff
133 struct amd7930_channel {
134 /* Channel status */
135 unsigned char channel_status;
137 /* Current buffer that the driver is playing on channel */
138 volatile __u8 * output_ptr;
139 volatile unsigned long output_count;
140 unsigned char xmit_idle_char;
142 /* Callback routine (and argument) when output is done on */
143 void (*output_callback)();
144 void * output_callback_arg;
146 /* Current buffer that the driver is recording on channel */
147 volatile __u8 * input_ptr;
148 volatile unsigned long input_count;
149 volatile unsigned long input_limit;
151 /* Callback routine (and argument) when input is done on */
152 void (*input_callback)();
153 void * input_callback_arg;
155 int input_format;
156 int output_format;
160 /* Private information we store for each amd7930 chip. */
161 struct amd7930_info {
162 struct amd7930_channel D;
163 struct amd7930_channel Bb;
164 struct amd7930_channel Bc;
166 /* Pointers to which B channels are being used for what
167 * These three fields (Baudio, Bisdn[0], and Bisdn[1]) will either
168 * be NULL or point to one of the Bb/Bc structures above.
170 struct amd7930_channel *Baudio;
171 struct amd7930_channel *Bisdn[2];
173 /* Device registers information. */
174 struct amd7930 *regs;
175 unsigned long regs_size;
176 struct amd7930_map map;
178 /* Volume information. */
179 int pgain, rgain, mgain;
181 /* Device interrupt information. */
182 int irq;
183 volatile int ints_on;
185 /* Format type */
186 int format_type;
189 /* Someone to signal when the ISDN LIU state changes */
190 int liu_state;
191 void (*liu_callback)(void *);
192 void *liu_callback_arg;
197 /* Output a 16-bit quantity in the order that the amd7930 expects. */
198 #define amd7930_out16(regs,v) ({ regs->dr = v & 0xFF; regs->dr = (v >> 8) & 0xFF; })
202 * gx, gr & stg gains. this table must contain 256 elements with
203 * the 0th being "infinity" (the magic value 9008). The remaining
204 * elements match sun's gain curve (but with higher resolution):
205 * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
207 static __const__ __u16 gx_coeff[256] = {
208 0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33,
209 0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
210 0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
211 0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
212 0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
213 0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
214 0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
215 0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
216 0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
217 0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
218 0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
219 0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
220 0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
221 0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
222 0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
223 0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
224 0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
225 0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
226 0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
227 0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
228 0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
229 0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
230 0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
231 0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
232 0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
233 0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
234 0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
235 0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
236 0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
237 0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
238 0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
239 0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
242 static __const__ __u16 ger_coeff[] = {
243 0x431f, /* 5. dB */
244 0x331f, /* 5.5 dB */
245 0x40dd, /* 6. dB */
246 0x11dd, /* 6.5 dB */
247 0x440f, /* 7. dB */
248 0x411f, /* 7.5 dB */
249 0x311f, /* 8. dB */
250 0x5520, /* 8.5 dB */
251 0x10dd, /* 9. dB */
252 0x4211, /* 9.5 dB */
253 0x410f, /* 10. dB */
254 0x111f, /* 10.5 dB */
255 0x600b, /* 11. dB */
256 0x00dd, /* 11.5 dB */
257 0x4210, /* 12. dB */
258 0x110f, /* 13. dB */
259 0x7200, /* 14. dB */
260 0x2110, /* 15. dB */
261 0x2200, /* 15.9 dB */
262 0x000b, /* 16.9 dB */
263 0x000f /* 18. dB */
265 #define NR_GER_COEFFS (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
267 /* Enable amd7930 interrupts atomically. */
268 static __inline__ void amd7930_enable_ints(struct amd7930_info *info)
270 register unsigned long flags;
272 if (info->ints_on)
273 return;
275 save_and_cli(flags);
276 info->regs->cr = AMR_INIT;
277 info->regs->dr = AM_INIT_ACTIVE;
278 restore_flags(flags);
280 info->ints_on = 1;
283 /* Disable amd7930 interrupts atomically. */
284 static __inline__ void amd7930_disable_ints(struct amd7930_info *info)
286 register unsigned long flags;
288 if (!info->ints_on)
289 return;
291 save_and_cli(flags);
292 info->regs->cr = AMR_INIT;
293 info->regs->dr = AM_INIT_ACTIVE | AM_INIT_DISABLE_INTS;
294 restore_flags(flags);
296 info->ints_on = 0;
299 /* Idle amd7930 (no interrupts, no audio, no data) */
300 static __inline__ void amd7930_idle(struct amd7930_info *info)
302 register unsigned long flags;
304 if (!info->ints_on)
305 return;
307 save_and_cli(flags);
308 info->regs->cr = AMR_INIT;
309 info->regs->dr = 0;
310 restore_flags(flags);
312 info->ints_on = 0;
315 /* Commit the local copy of the MAP registers to the amd7930. */
316 static void amd7930_write_map(struct sparcaudio_driver *drv)
318 struct amd7930_info *info = (struct amd7930_info *)drv->private;
319 struct amd7930 *regs = info->regs;
320 struct amd7930_map *map = &info->map;
321 unsigned long flags;
323 save_and_cli(flags);
325 regs->cr = AMR_MAP_GX;
326 amd7930_out16(regs, map->gx);
328 regs->cr = AMR_MAP_GR;
329 amd7930_out16(regs, map->gr);
331 regs->cr = AMR_MAP_STGR;
332 amd7930_out16(regs, map->stgr);
334 regs->cr = AMR_MAP_GER;
335 amd7930_out16(regs, map->ger);
337 regs->cr = AMR_MAP_MMR1;
338 regs->dr = map->mmr1;
340 regs->cr = AMR_MAP_MMR2;
341 regs->dr = map->mmr2;
343 restore_flags(flags);
346 /* Update the MAP registers with new settings. */
347 static void amd7930_update_map(struct sparcaudio_driver *drv)
349 struct amd7930_info *info = (struct amd7930_info *)drv->private;
350 struct amd7930_map *map = &info->map;
351 int level;
353 map->gx = gx_coeff[info->rgain];
354 map->stgr = gx_coeff[info->mgain];
356 level = (info->pgain * (256 + NR_GER_COEFFS)) >> 8;
357 if (level >= 256) {
358 map->ger = ger_coeff[level - 256];
359 map->gr = gx_coeff[255];
360 } else {
361 map->ger = ger_coeff[0];
362 map->gr = gx_coeff[level];
365 amd7930_write_map(drv);
368 /* Bit of a hack here - if the HISAX ISDN driver has got INTSTAT debugging
369 * turned on, we send debugging characters to the ISDN driver:
371 * i# - Interrupt received - number from 0 to 7 is low three bits of IR
372 * > - Loaded a single char into the Dchan xmit FIFO
373 * + - Finished loading an xmit packet into the Dchan xmit FIFO
374 * < - Read a single char from the Dchan recv FIFO
375 * ! - Finished reading a packet from the Dchan recv FIFO
377 * This code needs to be removed if anything other than HISAX uses the ISDN
378 * driver, since D.output_callback_arg is assumed to be a certain struct ptr
381 #ifdef L2FRAME_DEBUG
383 inline void debug_info(struct amd7930_info *info, char c) {
384 struct IsdnCardState *cs;
386 if (!info || !info->D.output_callback_arg) return;
388 cs = (struct IsdnCardState *)info->D.output_callback_arg;
390 if (!cs || !cs->status_write) return;
392 if (cs->debug & L1_DEB_INTSTAT) {
393 *(cs->status_write++) = c;
394 if (cs->status_write > cs->status_end)
395 cs->status_write = cs->status_buf;
399 #else
401 #define debug_info(info,c)
403 #endif
406 static void fill_D_xmit_fifo(struct amd7930_info *info)
408 /* Send next byte(s) of outgoing data. */
409 while (info->D.output_ptr && info->D.output_count > 0 &&
410 (info->regs->dsr2 & AMR_DSR2_TBE)) {
412 /* Send the next byte and advance buffer pointer. */
413 info->regs->dctb = *(info->D.output_ptr);
414 info->D.output_ptr++;
415 info->D.output_count--;
417 debug_info(info, '>');
421 static void transceive_Dchannel(struct amd7930_info *info)
423 __u8 dummy;
425 #define D_XMIT_ERRORS (AMR_DER_COLLISION | AMR_DER_UNRN)
426 #define D_RECV_ERRORS (AMR_DER_RABRT | AMR_DER_RFRAME | AMR_DER_FCS | \
427 AMR_DER_OVFL | AMR_DER_UNFL | AMR_DER_OVRN)
429 /* Transmit if we can */
430 fill_D_xmit_fifo(info);
432 /* Done with the xmit buffer? Notify the midlevel driver. */
433 if (info->D.output_ptr != NULL && info->D.output_count == 0) {
434 info->D.output_ptr = NULL;
435 info->D.output_count = 0;
436 debug_info(info, '+');
437 if (info->D.output_callback)
438 (*info->D.output_callback)
439 (info->D.output_callback_arg,
440 info->regs->der);
441 /* info->regs->der & D_XMIT_ERRORS); */
444 /* Read the next byte(s) of incoming data. */
446 while (info->regs->dsr2 & AMR_DSR2_RBA) {
448 if (info->D.input_ptr &&
449 (info->D.input_count < info->D.input_limit)) {
451 /* Get the next byte and advance buffer pointer. */
453 *(info->D.input_ptr) = info->regs->dcrb;
454 info->D.input_ptr++;
455 info->D.input_count++;
457 } else {
459 /* Overflow - should be detected by chip via RBLR
460 * so we'll just consume data until we see LBRP
463 dummy = info->regs->dcrb;
467 debug_info(info, '<');
469 if (info->regs->dsr2 & AMR_DSR2_LBRP) {
471 /* End of recv packet? Notify the midlevel driver. */
473 __u8 der;
475 debug_info(info, '!');
477 info->D.input_ptr = NULL;
479 der = info->regs->der & D_RECV_ERRORS;
481 /* Read receive byte count - advances FIFOs */
482 info->regs->cr = AMR_DLC_DRCR;
483 dummy = info->regs->dr;
484 dummy = info->regs->dr;
486 if (info->D.input_callback)
487 (*info->D.input_callback)
488 (info->D.input_callback_arg, der,
489 info->D.input_count);
495 long amd7930_xmit_idles=0;
497 static void transceive_Bchannel(struct amd7930_channel *channel,
498 __volatile__ __u8 *io_reg)
500 /* Send the next byte of outgoing data. */
501 if (channel->output_ptr && channel->output_count > 0) {
503 /* Send the next byte and advance buffer pointer. */
504 switch(channel->output_format) {
505 case AUDIO_ENCODING_ULAW:
506 case AUDIO_ENCODING_ALAW:
507 *io_reg = *(channel->output_ptr);
508 break;
509 case AUDIO_ENCODING_LINEAR8:
510 *io_reg = bilinear2mulaw(*(channel->output_ptr));
511 break;
512 case AUDIO_ENCODING_LINEAR:
513 if (channel->output_count >= 2) {
514 *io_reg = linear2mulaw(*((__u16*)(channel->output_ptr)));
515 channel->output_ptr++;
516 channel->output_count--;
519 channel->output_ptr++;
520 channel->output_count--;
523 /* Done with the buffer? Notify the midlevel driver. */
524 if (channel->output_count == 0) {
525 channel->output_ptr = NULL;
526 channel->output_count = 0;
527 if (channel->output_callback)
528 (*channel->output_callback)
529 (channel->output_callback_arg,1);
531 } else {
532 *io_reg = channel->xmit_idle_char;
533 amd7930_xmit_idles++;
536 /* Read the next byte of incoming data. */
537 if (channel->input_ptr && channel->input_count > 0) {
539 /* Get the next byte and advance buffer pointer. */
540 switch(channel->input_format) {
541 case AUDIO_ENCODING_ULAW:
542 case AUDIO_ENCODING_ALAW:
543 *(channel->input_ptr) = *io_reg;
544 break;
545 case AUDIO_ENCODING_LINEAR8:
546 *(channel->input_ptr) = mulaw2bilinear(*io_reg);
547 break;
548 case AUDIO_ENCODING_LINEAR:
549 if (channel->input_count >= 2) {
550 *((__u16*)(channel->input_ptr)) = mulaw2linear(*io_reg);
551 channel->input_ptr++;
552 channel->input_count--;
553 } else *(channel->input_ptr) = 0;
555 channel->input_ptr++;
556 channel->input_count--;
558 /* Done with the buffer? Notify the midlevel driver. */
559 if (channel->input_count == 0) {
560 channel->input_ptr = NULL;
561 channel->input_count = 0;
562 if (channel->input_callback)
563 (*channel->input_callback)
564 (channel->input_callback_arg, 1);
569 /* Interrupt handler (The chip takes only one byte per interrupt. Grrr!) */
570 static void amd7930_interrupt(int irq, void *dev_id, struct pt_regs *intr_regs)
572 struct sparcaudio_driver *drv = (struct sparcaudio_driver *)dev_id;
573 struct amd7930_info *info = (struct amd7930_info *)drv->private;
574 struct amd7930 *regs = info->regs;
575 __u8 ir;
576 __u8 lsr;
578 /* Clear the interrupt. */
579 ir = regs->ir;
581 if (ir & AMR_IR_BBUF) {
582 if (info->Bb.channel_status == CHANNEL_INUSE)
583 transceive_Bchannel(&info->Bb, &info->regs->bbtb);
584 if (info->Bc.channel_status == CHANNEL_INUSE)
585 transceive_Bchannel(&info->Bc, &info->regs->bctb);
588 if (ir & (AMR_IR_DRTHRSH | AMR_IR_DTTHRSH | AMR_IR_DSRI)) {
589 debug_info(info, 'i');
590 debug_info(info, '0' + (ir&7));
591 transceive_Dchannel(info);
594 if (ir & AMR_IR_LSRI) {
595 regs->cr = AMR_LIU_LSR;
596 lsr = regs->dr;
598 info->liu_state = (lsr&0x7) + 2;
600 if (info->liu_callback)
601 (*info->liu_callback)(info->liu_callback_arg);
606 static int amd7930_open(struct inode * inode, struct file * file,
607 struct sparcaudio_driver *drv)
609 struct amd7930_info *info = (struct amd7930_info *)drv->private;
611 switch(MINOR(inode->i_rdev) & 0xf) {
612 case SPARCAUDIO_AUDIO_MINOR:
613 info->format_type = AUDIO_ENCODING_ULAW;
614 break;
615 case SPARCAUDIO_DSP_MINOR:
616 info->format_type = AUDIO_ENCODING_LINEAR8;
617 break;
618 case SPARCAUDIO_DSP16_MINOR:
619 info->format_type = AUDIO_ENCODING_LINEAR;
620 break;
623 MOD_INC_USE_COUNT;
624 return 0;
627 static void amd7930_release(struct inode * inode, struct file * file,
628 struct sparcaudio_driver *drv)
630 /* amd7930_disable_ints(drv->private); */
631 MOD_DEC_USE_COUNT;
634 static void request_Baudio(struct amd7930_info *info)
636 if (info->Bb.channel_status == CHANNEL_AVAILABLE) {
638 info->Bb.channel_status = CHANNEL_INUSE;
639 info->Baudio = &info->Bb;
641 /* Multiplexor map - audio (Ba) to Bb */
642 info->regs->cr = AMR_MUX_MCR1;
643 info->regs->dr = AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bb << 4);
645 /* Enable B channel interrupts */
646 info->regs->cr = AMR_MUX_MCR4;
647 info->regs->dr = AM_MUX_MCR4_ENABLE_INTS;
649 } else if (info->Bc.channel_status == CHANNEL_AVAILABLE) {
651 info->Bc.channel_status = CHANNEL_INUSE;
652 info->Baudio = &info->Bc;
654 /* Multiplexor map - audio (Ba) to Bc */
655 info->regs->cr = AMR_MUX_MCR1;
656 info->regs->dr = AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bc << 4);
658 /* Enable B channel interrupts */
659 info->regs->cr = AMR_MUX_MCR4;
660 info->regs->dr = AM_MUX_MCR4_ENABLE_INTS;
665 static void release_Baudio(struct amd7930_info *info)
667 if (info->Baudio) {
668 info->Baudio->channel_status = CHANNEL_AVAILABLE;
669 info->regs->cr = AMR_MUX_MCR1;
670 info->regs->dr = 0;
671 info->Baudio = NULL;
673 if (info->Bb.channel_status == CHANNEL_AVAILABLE &&
674 info->Bc.channel_status == CHANNEL_AVAILABLE) {
676 /* Disable B channel interrupts */
677 info->regs->cr = AMR_MUX_MCR4;
678 info->regs->dr = 0;
683 static void amd7930_start_output(struct sparcaudio_driver *drv,
684 __u8 * buffer, unsigned long count)
686 struct amd7930_info *info = (struct amd7930_info *)drv->private;
688 if (! info->Baudio) {
689 request_Baudio(info);
692 if (info->Baudio) {
693 info->Baudio->output_ptr = buffer;
694 info->Baudio->output_count = count;
695 info->Baudio->output_format = info->format_type;
696 info->Baudio->output_callback = (void *) &sparcaudio_output_done;
697 info->Baudio->output_callback_arg = (void *) drv;
698 info->Baudio->xmit_idle_char = 0;
702 static void amd7930_stop_output(struct sparcaudio_driver *drv)
704 struct amd7930_info *info = (struct amd7930_info *)drv->private;
706 if (info->Baudio) {
707 info->Baudio->output_ptr = NULL;
708 info->Baudio->output_count = 0;
709 if (! info->Baudio->input_ptr)
710 release_Baudio(info);
714 static void amd7930_start_input(struct sparcaudio_driver *drv,
715 __u8 * buffer, unsigned long count)
717 struct amd7930_info *info = (struct amd7930_info *)drv->private;
719 if (! info->Baudio) {
720 request_Baudio(info);
723 if (info->Baudio) {
724 info->Baudio->input_ptr = buffer;
725 info->Baudio->input_count = count;
726 info->Baudio->input_format = info->format_type;
727 info->Baudio->input_callback = (void *) &sparcaudio_input_done;
728 info->Baudio->input_callback_arg = (void *) drv;
732 static void amd7930_stop_input(struct sparcaudio_driver *drv)
734 struct amd7930_info *info = (struct amd7930_info *)drv->private;
736 if (info->Baudio) {
737 info->Baudio->input_ptr = NULL;
738 info->Baudio->input_count = 0;
739 if (! info->Baudio->output_ptr)
740 release_Baudio(info);
745 static void amd7930_sunaudio_getdev(struct sparcaudio_driver *drv,
746 audio_device_t * audinfo)
748 strncpy(audinfo->name, "SUNW,am79c30", sizeof(audinfo->name) - 1);
749 strncpy(audinfo->version, "a", sizeof(audinfo->version) - 1);
750 strncpy(audinfo->config, "onboard1", sizeof(audinfo->config) - 1);
753 static int amd7930_sunaudio_getdev_sunos(struct sparcaudio_driver *drv)
755 return AUDIO_DEV_AMD;
758 static int amd7930_get_formats(struct sparcaudio_driver *drv)
760 return (AFMT_MU_LAW | AFMT_A_LAW | AFMT_U8 | AFMT_S16_BE);
763 static int amd7930_get_output_ports(struct sparcaudio_driver *drv)
765 return (AUDIO_SPEAKER | AUDIO_HEADPHONE);
768 static int amd7930_get_input_ports(struct sparcaudio_driver *drv)
770 return (AUDIO_MICROPHONE);
773 static int amd7930_set_output_volume(struct sparcaudio_driver *drv, int vol)
775 struct amd7930_info *info = (struct amd7930_info *)drv->private;
777 info->pgain = vol;
778 amd7930_update_map(drv);
779 return 0;
782 static int amd7930_get_output_volume(struct sparcaudio_driver *drv)
784 struct amd7930_info *info = (struct amd7930_info *)drv->private;
786 return info->pgain;
789 static int amd7930_set_input_volume(struct sparcaudio_driver *drv, int vol)
791 struct amd7930_info *info = (struct amd7930_info *)drv->private;
793 info->rgain = vol;
794 amd7930_update_map(drv);
795 return 0;
798 static int amd7930_get_input_volume(struct sparcaudio_driver *drv)
800 struct amd7930_info *info = (struct amd7930_info *)drv->private;
802 return info->rgain;
805 static int amd7930_set_monitor_volume(struct sparcaudio_driver *drv, int vol)
807 struct amd7930_info *info = (struct amd7930_info *)drv->private;
809 info->mgain = vol;
810 amd7930_update_map(drv);
811 return 0;
814 static int amd7930_get_monitor_volume(struct sparcaudio_driver *drv)
816 struct amd7930_info *info = (struct amd7930_info *)drv->private;
818 return info->mgain;
821 /* Cheats. The amd has the minimum capabilities we support */
822 static int amd7930_get_output_balance(struct sparcaudio_driver *drv)
824 return AUDIO_MID_BALANCE;
827 static int amd7930_get_input_balance(struct sparcaudio_driver *drv)
829 return AUDIO_MID_BALANCE;
832 static int amd7930_get_output_channels(struct sparcaudio_driver *drv)
834 return AUDIO_MIN_PLAY_CHANNELS;
837 static int amd7930_set_output_channels(struct sparcaudio_driver *drv,
838 int value)
840 return (value == AUDIO_MIN_PLAY_CHANNELS) ? 0 : -EINVAL;
843 static int amd7930_get_input_channels(struct sparcaudio_driver *drv)
845 return AUDIO_MIN_REC_CHANNELS;
848 static int
849 amd7930_set_input_channels(struct sparcaudio_driver *drv, int value)
851 return (value == AUDIO_MIN_REC_CHANNELS) ? 0 : -EINVAL;
854 static int amd7930_get_output_precision(struct sparcaudio_driver *drv)
856 return AUDIO_MIN_PLAY_PRECISION;
859 static int
860 amd7930_set_output_precision(struct sparcaudio_driver *drv, int value)
862 return (value == AUDIO_MIN_PLAY_PRECISION) ? 0 : -EINVAL;
865 static int amd7930_get_input_precision(struct sparcaudio_driver *drv)
867 return AUDIO_MIN_REC_PRECISION;
870 static int
871 amd7930_set_input_precision(struct sparcaudio_driver *drv, int value)
873 return (value == AUDIO_MIN_REC_PRECISION) ? 0 : -EINVAL;
876 static int amd7930_get_output_port(struct sparcaudio_driver *drv)
878 struct amd7930_info *info = (struct amd7930_info *)drv->private;
879 if (info->map.mmr2 & AM_MAP_MMR2_LS)
880 return AUDIO_SPEAKER;
881 return AUDIO_HEADPHONE;
884 static int amd7930_set_output_port(struct sparcaudio_driver *drv, int value)
886 struct amd7930_info *info = (struct amd7930_info *)drv->private;
887 switch (value) {
888 case AUDIO_HEADPHONE:
889 info->map.mmr2 &= ~AM_MAP_MMR2_LS;
890 break;
891 case AUDIO_SPEAKER:
892 info->map.mmr2 |= AM_MAP_MMR2_LS;
893 break;
894 default:
895 return -EINVAL;
897 amd7930_update_map(drv);
898 return 0;
901 /* Only a microphone here, so no troubles */
902 static int amd7930_get_input_port(struct sparcaudio_driver *drv)
904 return AUDIO_MICROPHONE;
907 static int amd7930_get_encoding(struct sparcaudio_driver *drv)
909 struct amd7930_info *info = (struct amd7930_info *)drv->private;
910 if ((info->map.mmr1 & AM_MAP_MMR1_ALAW) &&
911 (info->format_type == AUDIO_ENCODING_ALAW))
912 return AUDIO_ENCODING_ALAW;
914 return info->format_type;
917 static int
918 amd7930_set_encoding(struct sparcaudio_driver *drv, int value)
920 struct amd7930_info *info = (struct amd7930_info *)drv->private;
922 switch (value) {
923 case AUDIO_ENCODING_ALAW:
924 info->map.mmr1 |= AM_MAP_MMR1_ALAW;
925 break;
926 case AUDIO_ENCODING_LINEAR8:
927 case AUDIO_ENCODING_LINEAR:
928 case AUDIO_ENCODING_ULAW:
929 info->map.mmr1 &= ~AM_MAP_MMR1_ALAW;
930 break;
931 default:
932 return -EINVAL;
935 info->format_type = value;
937 amd7930_update_map(drv);
938 return 0;
941 /* This is what you get. Take it or leave it */
942 static int amd7930_get_output_rate(struct sparcaudio_driver *drv)
944 return AMD7930_RATE;
947 static int
948 amd7930_set_output_rate(struct sparcaudio_driver *drv, int value)
950 return (value == AMD7930_RATE) ? 0 : -EINVAL;
953 static int amd7930_get_input_rate(struct sparcaudio_driver *drv)
955 return AMD7930_RATE;
958 static int
959 amd7930_set_input_rate(struct sparcaudio_driver *drv, int value)
961 return (value == AMD7930_RATE) ? 0 : -EINVAL;
964 static int amd7930_get_output_muted(struct sparcaudio_driver *drv)
966 return 0;
969 static void amd7930_loopback(struct sparcaudio_driver *drv, unsigned int value)
971 struct amd7930_info *info = (struct amd7930_info *)drv->private;
973 if (value)
974 info->map.mmr1 |= AM_MAP_MMR1_LOOPBACK;
975 else
976 info->map.mmr1 &= ~AM_MAP_MMR1_LOOPBACK;
977 amd7930_update_map(drv);
978 return;
981 static int amd7930_ioctl(struct inode * inode, struct file * file,
982 unsigned int cmd, unsigned long arg,
983 struct sparcaudio_driver *drv)
985 int retval = 0;
987 switch (cmd) {
988 case AUDIO_DIAG_LOOPBACK:
989 amd7930_loopback(drv, (unsigned int)arg);
990 break;
991 default:
992 retval = -EINVAL;
995 return retval;
1000 * ISDN operations
1002 * Many of these routines take an "int dev" argument, which is simply
1003 * an index into the drivers[] array. Currently, we only support a
1004 * single AMD 7930 chip, so the value should always be 0. B channel
1005 * operations require an "int chan", which should be 0 for channel B1
1006 * and 1 for channel B2
1008 * int amd7930_get_irqnum(int dev)
1010 * returns the interrupt number being used by the chip. ISDN4linux
1011 * uses this number to watch the interrupt during initialization and
1012 * make sure something is happening.
1014 * int amd7930_get_liu_state(int dev)
1016 * returns the current state of the ISDN Line Interface Unit (LIU)
1017 * as a number between 2 (state F2) and 7 (state F7). 0 may also be
1018 * returned if the chip doesn't exist or the LIU hasn't been
1019 * activated. The meanings of the states are defined in I.430, ISDN
1020 * BRI Physical Layer Interface. The most important two states are
1021 * F3 (shutdown) and F7 (syncronized).
1023 * void amd7930_liu_init(int dev, void (*callback)(), void *callback_arg)
1025 * initializes the LIU and optionally registers a callback to be
1026 * signaled upon a change of LIU state. The callback will be called
1027 * with a single opaque callback_arg Once the callback has been
1028 * triggered, amd7930_get_liu_state can be used to determine the LIU
1029 * current state.
1031 * void amd7930_liu_activate(int dev, int priority)
1033 * requests LIU activation at a given D-channel priority.
1034 * Successful activatation is achieved upon entering state F7, which
1035 * will trigger any callback previously registered with
1036 * amd7930_liu_init.
1038 * void amd7930_liu_deactivate(int dev)
1040 * deactivates LIU. Outstanding D and B channel transactions are
1041 * terminated rudely and without callback notification. LIU change
1042 * of state callback will be triggered, however.
1044 * void amd7930_dxmit(int dev, __u8 *buffer, unsigned int count,
1045 * void (*callback)(void *, int), void *callback_arg)
1047 * transmits a packet - specified with buffer, count - over the D-channel
1048 * interface. Buffer should begin with the LAPD address field and
1049 * end with the information field. FCS and flag sequences should not
1050 * be included, nor is bit-stuffing required - all these functions are
1051 * performed by the chip. The callback function will be called
1052 * DURING THE TOP HALF OF AN INTERRUPT HANDLER and will be passed
1053 * both the arbitrary callback_arg and an integer error indication:
1055 * 0 - successful transmission; ready for next packet
1056 * non-0 - error value from chip's DER (D-Channel Error Register):
1057 * 4 - collision detect
1058 * 128 - underrun; irq routine didn't service chip fast enough
1060 * The callback routine should defer any time-consuming operations
1061 * to a bottom-half handler; however, amd7930_dxmit may be called
1062 * from within the callback to request back-to-back transmission of
1063 * a second packet (without repeating the priority/collision mechanism)
1065 * A comment about the "collision detect" error, which is signalled
1066 * whenever the echoed D-channel data didn't match the transmitted
1067 * data. This is part of ISDN's normal multi-drop T-interface
1068 * operation, indicating that another device has attempted simultaneous
1069 * transmission, but can also result from line noise. An immediate
1070 * requeue via amd7930_dxmit is suggested, but repeated collision
1071 * errors may indicate a more serious problem.
1073 * void amd7930_drecv(int dev, __u8 *buffer, unsigned int size,
1074 * void (*callback)(void *, int, unsigned int),
1075 * void *callback_arg)
1077 * register a buffer - buffer, size - into which a D-channel packet
1078 * can be received. The callback function will be called DURING
1079 * THE TOP HALF OF AN INTERRUPT HANDLER and will be passed an
1080 * arbitrary callback_arg, an integer error indication and the length
1081 * of the received packet, which will start with the address field,
1082 * end with the information field, and not contain flag or FCS
1083 * bytes. Bit-stuffing will already have been corrected for.
1084 * Possible values of second callback argument "error":
1086 * 0 - successful reception
1087 * non-0 - error value from chip's DER (D-Channel Error Register):
1088 * 1 - received packet abort
1089 * 2 - framing error; non-integer number of bytes received
1090 * 8 - FCS error; CRC sequence indicated corrupted data
1091 * 16 - overflow error; packet exceeded size of buffer
1092 * 32 - underflow error; packet smaller than required five bytes
1093 * 64 - overrun error; irq routine didn't service chip fast enough
1095 * int amd7930_bopen(int dev, int chan, u_char xmit_idle_char)
1097 * This function should be called before any other operations on a B
1098 * channel. In addition to arranging for interrupt handling and
1099 * channel multiplexing, it sets the xmit_idle_char which is
1100 * transmitted on the interface when no data buffer is available.
1101 * Suggested values are: 0 for ISDN audio; FF for HDLC mark idle; 7E
1102 * for HDLC flag idle. Returns 0 on a successful open; -1 on error,
1103 * which is quite possible if audio and the other ISDN channel are
1104 * already in use, since the Am7930 can only send two of the three
1105 * channels to the processor
1107 * void amd7930_bclose(int dev, int chan)
1109 * Shuts down a B channel when no longer in use.
1111 * void amd7930_bxmit(int dev, int chan, __u8 *buffer, unsigned int count,
1112 * void (*callback)(void *), void *callback_arg)
1114 * transmits a raw data block - specified with buffer, count - over
1115 * the B channel interface specified by dev/chan. The callback
1116 * function will be called DURING THE TOP HALF OF AN INTERRUPT
1117 * HANDLER and will be passed the arbitrary callback_arg
1119 * The callback routine should defer any time-consuming operations
1120 * to a bottom-half handler; however, amd7930_bxmit may be called
1121 * from within the callback to request back-to-back transmission of
1122 * another data block
1124 * void amd7930_brecv(int dev, int chan, __u8 *buffer, unsigned int size,
1125 * void (*callback)(void *), void *callback_arg)
1127 * receive a raw data block - specified with buffer, size - over the
1128 * B channel interface specified by dev/chan. The callback function
1129 * will be called DURING THE TOP HALF OF AN INTERRUPT HANDLER and
1130 * will be passed the arbitrary callback_arg
1132 * The callback routine should defer any time-consuming operations
1133 * to a bottom-half handler; however, amd7930_brecv may be called
1134 * from within the callback to register another buffer and ensure
1135 * continuous B channel reception without loss of data
1139 #if defined (AMD79C30_ISDN) || defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x200ff
1140 static int amd7930_get_irqnum(int dev)
1142 struct amd7930_info *info;
1144 if (dev > num_drivers) {
1145 return(0);
1148 info = (struct amd7930_info *) drivers[dev].private;
1150 return info->irq;
1153 static int amd7930_get_liu_state(int dev)
1155 struct amd7930_info *info;
1157 if (dev > num_drivers) {
1158 return(0);
1161 info = (struct amd7930_info *) drivers[dev].private;
1163 return info->liu_state;
1166 static void amd7930_liu_init(int dev, void (*callback)(), void *callback_arg)
1168 struct amd7930_info *info;
1169 register unsigned long flags;
1171 if (dev > num_drivers) {
1172 return;
1175 info = (struct amd7930_info *) drivers[dev].private;
1177 save_and_cli(flags);
1179 /* Set callback for LIU state change */
1180 info->liu_callback = callback;
1181 info->liu_callback_arg = callback_arg;
1183 /* De-activate the ISDN Line Interface Unit (LIU) */
1184 info->regs->cr = AMR_LIU_LMR1;
1185 info->regs->dr = 0;
1187 /* Request interrupt when LIU changes state from/to F3/F7/F8 */
1188 info->regs->cr = AMR_LIU_LMR2;
1189 info->regs->dr = AM_LIU_LMR2_EN_F3_INT |
1190 AM_LIU_LMR2_EN_F7_INT | AM_LIU_LMR2_EN_F8_INT;
1192 /* amd7930_enable_ints(info); */
1194 /* Activate the ISDN Line Interface Unit (LIU) */
1195 info->regs->cr = AMR_LIU_LMR1;
1196 info->regs->dr = AM_LIU_LMR1_LIU_ENABL;
1198 restore_flags(flags);
1201 static void amd7930_liu_activate(int dev, int priority)
1203 struct amd7930_info *info;
1204 register unsigned long flags;
1206 if (dev > num_drivers) {
1207 return;
1210 info = (struct amd7930_info *) drivers[dev].private;
1212 save_and_cli(flags);
1214 /* Set D-channel access priority
1216 * I.430 defines a priority mechanism based on counting 1s
1217 * in the echo channel before transmitting
1219 * Priority 0 is eight 1s; priority 1 is ten 1s; etc
1222 info->regs->cr = AMR_LIU_LPR;
1223 info->regs->dr = priority & 0x0f;
1225 /* request LIU activation */
1227 info->regs->cr = AMR_LIU_LMR1;
1228 info->regs->dr = AM_LIU_LMR1_LIU_ENABL | AM_LIU_LMR1_REQ_ACTIV;
1230 restore_flags(flags);
1233 static void amd7930_liu_deactivate(int dev)
1235 struct amd7930_info *info;
1236 register unsigned long flags;
1238 if (dev > num_drivers) {
1239 return;
1242 info = (struct amd7930_info *) drivers[dev].private;
1244 save_and_cli(flags);
1246 /* deactivate LIU */
1248 info->regs->cr = AMR_LIU_LMR1;
1249 info->regs->dr = 0;
1251 restore_flags(flags);
1254 static void amd7930_dxmit(int dev, __u8 *buffer, unsigned int count,
1255 void (*callback)(void *, int), void *callback_arg)
1257 struct amd7930_info *info;
1258 register unsigned long flags;
1259 __u8 dmr1;
1261 if (dev > num_drivers) {
1262 return;
1265 info = (struct amd7930_info *) drivers[dev].private;
1267 save_and_cli(flags);
1269 if (info->D.output_ptr) {
1270 restore_flags(flags);
1271 printk("amd7930_dxmit: transmitter in use\n");
1272 return;
1275 info->D.output_ptr = buffer;
1276 info->D.output_count = count;
1277 info->D.output_callback = callback;
1278 info->D.output_callback_arg = callback_arg;
1280 /* Enable D-channel Transmit Threshold interrupt; disable addressing */
1281 info->regs->cr = AMR_DLC_DMR1;
1282 dmr1 = info->regs->dr;
1283 dmr1 |= AMR_DLC_DMR1_DTTHRSH_INT;
1284 dmr1 &= ~AMR_DLC_DMR1_EN_ADDRS;
1285 info->regs->dr = dmr1;
1287 /* Begin xmit by setting D-channel Transmit Byte Count Reg (DTCR) */
1288 info->regs->cr = AMR_DLC_DTCR;
1289 info->regs->dr = count & 0xff;
1290 info->regs->dr = (count >> 8) & 0xff;
1292 /* Prime xmit FIFO */
1293 /* fill_D_xmit_fifo(info); */
1294 transceive_Dchannel(info);
1296 restore_flags(flags);
1299 static void amd7930_drecv(int dev, __u8 *buffer, unsigned int size,
1300 void (*callback)(void *, int, unsigned int),
1301 void *callback_arg)
1303 struct amd7930_info *info;
1304 register unsigned long flags;
1305 __u8 dmr1;
1307 if (dev > num_drivers) {
1308 return;
1311 info = (struct amd7930_info *) drivers[dev].private;
1313 save_and_cli(flags);
1315 if (info->D.input_ptr) {
1316 restore_flags(flags);
1317 printk("amd7930_drecv: receiver already has buffer!\n");
1318 return;
1321 info->D.input_ptr = buffer;
1322 info->D.input_count = 0;
1323 info->D.input_limit = size;
1324 info->D.input_callback = callback;
1325 info->D.input_callback_arg = callback_arg;
1327 /* Enable D-channel Receive Threshold interrupt;
1328 * Enable D-channel End of Receive Packet interrupt;
1329 * Disable address recognition
1331 info->regs->cr = AMR_DLC_DMR1;
1332 dmr1 = info->regs->dr;
1333 dmr1 |= AMR_DLC_DMR1_DRTHRSH_INT | AMR_DLC_DMR1_EORP_INT;
1334 dmr1 &= ~AMR_DLC_DMR1_EN_ADDRS;
1335 info->regs->dr = dmr1;
1337 /* Set D-channel Receive Byte Count Limit Register */
1338 info->regs->cr = AMR_DLC_DRCR;
1339 info->regs->dr = size & 0xff;
1340 info->regs->dr = (size >> 8) & 0xff;
1342 restore_flags(flags);
1345 static int amd7930_bopen(int dev, unsigned int chan,
1346 int mode, u_char xmit_idle_char)
1348 struct amd7930_info *info;
1349 register unsigned long flags;
1351 if (dev > num_drivers || chan<0 || chan>1) {
1352 return -1;
1355 if (mode == L1_MODE_HDLC) {
1356 return -1;
1359 info = (struct amd7930_info *) drivers[dev].private;
1361 save_and_cli(flags);
1363 if (info->Bb.channel_status == CHANNEL_AVAILABLE) {
1365 info->Bb.channel_status = CHANNEL_INUSE;
1366 info->Bb.xmit_idle_char = xmit_idle_char;
1367 info->Bisdn[chan] = &info->Bb;
1369 /* Multiplexor map - isdn (B1/2) to Bb */
1370 info->regs->cr = AMR_MUX_MCR2 + chan;
1371 info->regs->dr = (AM_MUX_CHANNEL_B1 + chan) |
1372 (AM_MUX_CHANNEL_Bb << 4);
1374 } else if (info->Bc.channel_status == CHANNEL_AVAILABLE) {
1376 info->Bc.channel_status = CHANNEL_INUSE;
1377 info->Bc.xmit_idle_char = xmit_idle_char;
1378 info->Bisdn[chan] = &info->Bc;
1380 /* Multiplexor map - isdn (B1/2) to Bc */
1381 info->regs->cr = AMR_MUX_MCR2 + chan;
1382 info->regs->dr = (AM_MUX_CHANNEL_B1 + chan) |
1383 (AM_MUX_CHANNEL_Bc << 4);
1385 } else {
1386 restore_flags(flags);
1387 return (-1);
1390 /* Enable B channel transmit */
1391 info->regs->cr = AMR_LIU_LMR1;
1392 info->regs->dr |= AM_LIU_LMR1_B1_ENABL + chan;
1394 /* Enable B channel interrupts */
1395 info->regs->cr = AMR_MUX_MCR4;
1396 info->regs->dr = AM_MUX_MCR4_ENABLE_INTS | AM_MUX_MCR4_REVERSE_Bb | AM_MUX_MCR4_REVERSE_Bc;
1398 restore_flags(flags);
1399 return 0;
1402 static void amd7930_bclose(int dev, unsigned int chan)
1404 struct amd7930_info *info;
1405 register unsigned long flags;
1407 if (dev > num_drivers || chan<0 || chan>1) {
1408 return;
1411 info = (struct amd7930_info *) drivers[dev].private;
1413 save_and_cli(flags);
1415 if (info->Bisdn[chan]) {
1416 info->Bisdn[chan]->channel_status = CHANNEL_AVAILABLE;
1417 info->regs->cr = AMR_MUX_MCR2 + chan;
1418 info->regs->dr = 0;
1419 info->Bisdn[chan] = NULL;
1421 /* Disable B channel transmit */
1422 info->regs->cr = AMR_LIU_LMR1;
1423 info->regs->dr &= ~(AM_LIU_LMR1_B1_ENABL + chan);
1425 if (info->Bb.channel_status == CHANNEL_AVAILABLE &&
1426 info->Bc.channel_status == CHANNEL_AVAILABLE) {
1428 /* Disable B channel interrupts */
1429 info->regs->cr = AMR_MUX_MCR4;
1430 info->regs->dr = 0;
1434 restore_flags(flags);
1437 static void amd7930_bxmit(int dev, unsigned int chan,
1438 __u8 * buffer, unsigned long count,
1439 void (*callback)(void *, int), void *callback_arg)
1441 struct amd7930_info *info;
1442 struct amd7930_channel *Bchan;
1443 register unsigned long flags;
1445 if (dev > num_drivers) {
1446 return;
1449 info = (struct amd7930_info *) drivers[dev].private;
1450 Bchan = info->Bisdn[chan];
1452 if (Bchan) {
1453 save_and_cli(flags);
1455 Bchan->output_ptr = buffer;
1456 Bchan->output_count = count;
1457 Bchan->output_format = AUDIO_ENCODING_ULAW;
1458 Bchan->output_callback = (void *) callback;
1459 Bchan->output_callback_arg = callback_arg;
1461 restore_flags(flags);
1465 static void amd7930_brecv(int dev, unsigned int chan,
1466 __u8 * buffer, unsigned long size,
1467 void (*callback)(void *, int, unsigned int),
1468 void *callback_arg)
1470 struct amd7930_info *info;
1471 struct amd7930_channel *Bchan;
1472 register unsigned long flags;
1474 if (dev > num_drivers) {
1475 return;
1478 info = (struct amd7930_info *) drivers[dev].private;
1479 Bchan = info->Bisdn[chan];
1481 if (Bchan) {
1482 save_and_cli(flags);
1484 Bchan->input_ptr = buffer;
1485 Bchan->input_count = size;
1486 Bchan->input_format = AUDIO_ENCODING_ULAW;
1487 Bchan->input_callback = (void *) callback;
1488 Bchan->input_callback_arg = callback_arg;
1490 restore_flags(flags);
1494 struct foreign_interface amd7930_foreign_interface = {
1495 amd7930_get_irqnum,
1496 amd7930_get_liu_state,
1497 amd7930_liu_init,
1498 amd7930_liu_activate,
1499 amd7930_liu_deactivate,
1500 amd7930_dxmit,
1501 amd7930_drecv,
1502 amd7930_bopen,
1503 amd7930_bclose,
1504 amd7930_bxmit,
1505 amd7930_brecv
1507 EXPORT_SYMBOL(amd7930_foreign_interface);
1508 #endif
1512 * Device detection and initialization.
1515 static struct sparcaudio_operations amd7930_ops = {
1516 amd7930_open,
1517 amd7930_release,
1518 amd7930_ioctl,
1519 amd7930_start_output,
1520 amd7930_stop_output,
1521 amd7930_start_input,
1522 amd7930_stop_input,
1523 amd7930_sunaudio_getdev,
1524 amd7930_set_output_volume,
1525 amd7930_get_output_volume,
1526 amd7930_set_input_volume,
1527 amd7930_get_input_volume,
1528 amd7930_set_monitor_volume,
1529 amd7930_get_monitor_volume,
1530 NULL, /* amd7930_set_output_balance */
1531 amd7930_get_output_balance,
1532 NULL, /* amd7930_set_input_balance */
1533 amd7930_get_input_balance,
1534 amd7930_set_output_channels,
1535 amd7930_get_output_channels,
1536 amd7930_set_input_channels,
1537 amd7930_get_input_channels,
1538 amd7930_set_output_precision,
1539 amd7930_get_output_precision,
1540 amd7930_set_input_precision,
1541 amd7930_get_input_precision,
1542 amd7930_set_output_port,
1543 amd7930_get_output_port,
1544 NULL, /* amd7930_set_input_port */
1545 amd7930_get_input_port,
1546 amd7930_set_encoding,
1547 amd7930_get_encoding,
1548 amd7930_set_encoding,
1549 amd7930_get_encoding,
1550 amd7930_set_output_rate,
1551 amd7930_get_output_rate,
1552 amd7930_set_input_rate,
1553 amd7930_get_input_rate,
1554 amd7930_sunaudio_getdev_sunos,
1555 amd7930_get_output_ports,
1556 amd7930_get_input_ports,
1557 NULL, /* amd7930_set_output_muted */
1558 amd7930_get_output_muted,
1559 NULL, /* amd7930_set_output_pause */
1560 NULL, /* amd7930_get_output_pause */
1561 NULL, /* amd7930_set_input_pause */
1562 NULL, /* amd7930_get_input_pause */
1563 NULL, /* amd7930_set_output_samples */
1564 NULL, /* amd7930_get_output_samples */
1565 NULL, /* amd7930_set_input_samples */
1566 NULL, /* amd7930_get_input_samples */
1567 NULL, /* amd7930_set_output_error */
1568 NULL, /* amd7930_get_output_error */
1569 NULL, /* amd7930_set_input_error */
1570 NULL, /* amd7930_get_input_error */
1571 amd7930_get_formats,
1574 /* Attach to an amd7930 chip given its PROM node. */
1575 static int amd7930_attach(struct sparcaudio_driver *drv, int node,
1576 struct linux_sbus *sbus, struct linux_sbus_device *sdev)
1578 struct linux_prom_registers regs;
1579 struct linux_prom_irqs irq;
1580 struct amd7930_info *info;
1581 int err;
1583 /* Allocate our private information structure. */
1584 drv->private = kmalloc(sizeof(struct amd7930_info), GFP_KERNEL);
1585 if (!drv->private)
1586 return -ENOMEM;
1588 /* Point at the information structure and initialize it. */
1589 drv->ops = &amd7930_ops;
1590 info = (struct amd7930_info *)drv->private;
1591 memset(info, 0, sizeof(*info));
1592 info->ints_on = 1; /* force disable below */
1594 drv->dev = sdev;
1596 /* Map the registers into memory. */
1597 prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
1598 if (sbus && sdev)
1599 prom_apply_sbus_ranges(sbus, &regs, 1, sdev);
1600 info->regs_size = regs.reg_size;
1601 info->regs = sparc_alloc_io(regs.phys_addr, 0, regs.reg_size,
1602 "amd7930", regs.which_io, 0);
1603 if (!info->regs) {
1604 printk(KERN_ERR "amd7930: could not allocate registers\n");
1605 kfree(drv->private);
1606 return -EIO;
1609 /* Put amd7930 in idle mode (interrupts disabled) */
1610 amd7930_idle(info);
1612 /* Enable extended FIFO operation on D-channel */
1613 info->regs->cr = AMR_DLC_EFCR;
1614 info->regs->dr = AMR_DLC_EFCR_EXTEND_FIFO;
1615 info->regs->cr = AMR_DLC_DMR4;
1616 info->regs->dr = /* AMR_DLC_DMR4_RCV_30 | */ AMR_DLC_DMR4_XMT_14;
1618 /* Attach the interrupt handler to the audio interrupt. */
1619 prom_getproperty(node, "intr", (char *)&irq, sizeof(irq));
1620 info->irq = irq.pri;
1621 request_irq(info->irq, amd7930_interrupt,
1622 SA_INTERRUPT, "amd7930", drv);
1623 enable_irq(info->irq);
1624 amd7930_enable_ints(info);
1626 /* Initalize the local copy of the MAP registers. */
1627 memset(&info->map, 0, sizeof(info->map));
1628 info->map.mmr1 = AM_MAP_MMR1_GX | AM_MAP_MMR1_GER
1629 | AM_MAP_MMR1_GR | AM_MAP_MMR1_STG;
1630 /* Start out with speaker, microphone */
1631 info->map.mmr2 |= (AM_MAP_MMR2_LS | AM_MAP_MMR2_AINB);
1633 /* Set the default audio parameters. */
1634 info->rgain = 128;
1635 info->pgain = 200;
1636 info->mgain = 0;
1637 info->format_type = AUDIO_ENCODING_ULAW;
1638 info->Bb.input_format = AUDIO_ENCODING_ULAW;
1639 info->Bb.output_format = AUDIO_ENCODING_ULAW;
1640 info->Bc.input_format = AUDIO_ENCODING_ULAW;
1641 info->Bc.output_format = AUDIO_ENCODING_ULAW;
1642 amd7930_update_map(drv);
1644 /* Register the amd7930 with the midlevel audio driver. */
1645 err = register_sparcaudio_driver(drv, 1);
1646 if (err < 0) {
1647 printk(KERN_ERR "amd7930: unable to register\n");
1648 disable_irq(info->irq);
1649 free_irq(info->irq, drv);
1650 sparc_free_io(info->regs, info->regs_size);
1651 kfree(drv->private);
1652 return -EIO;
1655 /* Announce the hardware to the user. */
1656 printk(KERN_INFO "amd7930 at 0x%lx irq %d\n",
1657 (unsigned long)info->regs, info->irq);
1659 /* Success! */
1660 return 0;
1663 #ifdef MODULE
1664 /* Detach from an amd7930 chip given the device structure. */
1665 static void amd7930_detach(struct sparcaudio_driver *drv)
1667 struct amd7930_info *info = (struct amd7930_info *)drv->private;
1669 unregister_sparcaudio_driver(drv, 1);
1670 amd7930_idle(info);
1671 disable_irq(info->irq);
1672 free_irq(info->irq, drv);
1673 sparc_free_io(info->regs, info->regs_size);
1674 kfree(drv->private);
1676 #endif
1678 /* Probe for the amd7930 chip and then attach the driver. */
1679 #ifdef MODULE
1680 int init_module(void)
1681 #else
1682 int __init amd7930_init(void)
1683 #endif
1685 struct linux_sbus *bus;
1686 struct linux_sbus_device *sdev;
1687 int node;
1689 /* Try to find the sun4c "audio" node first. */
1690 node = prom_getchild(prom_root_node);
1691 node = prom_searchsiblings(node, "audio");
1692 if (node && amd7930_attach(&drivers[0], node, NULL, NULL) == 0)
1693 num_drivers = 1;
1694 else
1695 num_drivers = 0;
1697 /* Probe each SBUS for amd7930 chips. */
1698 for_all_sbusdev(sdev,bus) {
1699 if (!strcmp(sdev->prom_name, "audio")) {
1700 /* Don't go over the max number of drivers. */
1701 if (num_drivers >= MAX_DRIVERS)
1702 continue;
1704 if (amd7930_attach(&drivers[num_drivers],
1705 sdev->prom_node, sdev->my_bus, sdev) == 0)
1706 num_drivers++;
1710 /* Only return success if we found some amd7930 chips. */
1711 return (num_drivers > 0) ? 0 : -EIO;
1714 #ifdef MODULE
1715 void cleanup_module(void)
1717 register int i;
1719 for (i = 0; i < num_drivers; i++) {
1720 amd7930_detach(&drivers[i]);
1721 num_drivers--;
1724 #endif
1727 /*************************************************************/
1728 /* Audio format conversion */
1729 /*************************************************************/
1731 /* Translation tables */
1733 static unsigned char ulaw[] = {
1734 3, 7, 11, 15, 19, 23, 27, 31,
1735 35, 39, 43, 47, 51, 55, 59, 63,
1736 66, 68, 70, 72, 74, 76, 78, 80,
1737 82, 84, 86, 88, 90, 92, 94, 96,
1738 98, 99, 100, 101, 102, 103, 104, 105,
1739 106, 107, 108, 109, 110, 111, 112, 113,
1740 113, 114, 114, 115, 115, 116, 116, 117,
1741 117, 118, 118, 119, 119, 120, 120, 121,
1742 121, 121, 122, 122, 122, 122, 123, 123,
1743 123, 123, 124, 124, 124, 124, 125, 125,
1744 125, 125, 125, 125, 126, 126, 126, 126,
1745 126, 126, 126, 126, 127, 127, 127, 127,
1746 127, 127, 127, 127, 127, 127, 127, 127,
1747 128, 128, 128, 128, 128, 128, 128, 128,
1748 128, 128, 128, 128, 128, 128, 128, 128,
1749 128, 128, 128, 128, 128, 128, 128, 128,
1750 253, 249, 245, 241, 237, 233, 229, 225,
1751 221, 217, 213, 209, 205, 201, 197, 193,
1752 190, 188, 186, 184, 182, 180, 178, 176,
1753 174, 172, 170, 168, 166, 164, 162, 160,
1754 158, 157, 156, 155, 154, 153, 152, 151,
1755 150, 149, 148, 147, 146, 145, 144, 143,
1756 143, 142, 142, 141, 141, 140, 140, 139,
1757 139, 138, 138, 137, 137, 136, 136, 135,
1758 135, 135, 134, 134, 134, 134, 133, 133,
1759 133, 133, 132, 132, 132, 132, 131, 131,
1760 131, 131, 131, 131, 130, 130, 130, 130,
1761 130, 130, 130, 130, 129, 129, 129, 129,
1762 129, 129, 129, 129, 129, 129, 129, 129,
1763 128, 128, 128, 128, 128, 128, 128, 128,
1764 128, 128, 128, 128, 128, 128, 128, 128,
1765 128, 128, 128, 128, 128, 128, 128, 128
1768 static __u8 mulaw2bilinear(__u8 data)
1770 return ulaw[data];
1774 static unsigned char linear[] = {
1775 0, 0, 0, 0, 0, 0, 0, 1,
1776 0, 0, 0, 2, 0, 0, 0, 3,
1777 0, 0, 0, 4, 0, 0, 0, 5,
1778 0, 0, 0, 6, 0, 0, 0, 7,
1779 0, 0, 0, 8, 0, 0, 0, 9,
1780 0, 0, 0, 10, 0, 0, 0, 11,
1781 0, 0, 0, 12, 0, 0, 0, 13,
1782 0, 0, 0, 14, 0, 0, 0, 15,
1783 0, 0, 16, 0, 17, 0, 18, 0,
1784 19, 0, 20, 0, 21, 0, 22, 0,
1785 23, 0, 24, 0, 25, 0, 26, 0,
1786 27, 0, 28, 0, 29, 0, 30, 0,
1787 31, 0, 32, 33, 34, 35, 36, 37,
1788 38, 39, 40, 41, 42, 43, 44, 45,
1789 46, 48, 50, 52, 54, 56, 58, 60,
1790 62, 65, 69, 73, 77, 83, 91, 103,
1791 255, 231, 219, 211, 205, 201, 197, 193,
1792 190, 188, 186, 184, 182, 180, 178, 176,
1793 174, 173, 172, 171, 170, 169, 168, 167,
1794 166, 165, 164, 163, 162, 161, 160, 0,
1795 159, 0, 158, 0, 157, 0, 156, 0,
1796 155, 0, 154, 0, 153, 0, 152, 0,
1797 151, 0, 150, 0, 149, 0, 148, 0,
1798 147, 0, 146, 0, 145, 0, 144, 0,
1799 0, 143, 0, 0, 0, 142, 0, 0,
1800 0, 141, 0, 0, 0, 140, 0, 0,
1801 0, 139, 0, 0, 0, 138, 0, 0,
1802 0, 137, 0, 0, 0, 136, 0, 0,
1803 0, 135, 0, 0, 0, 134, 0, 0,
1804 0, 133, 0, 0, 0, 132, 0, 0,
1805 0, 131, 0, 0, 0, 130, 0, 0,
1806 0, 129, 0, 0, 0, 128, 0, 0
1809 static __u8 bilinear2mulaw(__u8 data)
1811 return linear[data];
1814 static int exp_lut[256] = {
1815 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
1816 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
1817 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1818 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1819 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1820 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1821 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1822 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
1825 #define BIAS 0x84
1826 #define CLIP 32635
1828 #define SWAP_ENDIAN(x) ((x >> 8) | ((x & 0xff) << 8))
1830 static __u8 linear2mulaw(__u16 data)
1832 static int sign, exponent, mantissa;
1834 /* not really sure, if swapping is ok - comment next line to disable it */
1835 data = SWAP_ENDIAN(data);
1837 sign = (data >> 8) & 0x80;
1838 if (sign != 0) data = -data;
1840 if (data > CLIP) data = CLIP;
1841 data += BIAS;
1842 exponent = exp_lut[(data >> 7) & 0xFF];
1843 mantissa = (data >> (exponent + 3)) & 0x0F;
1845 return (~(sign | (exponent << 4) | mantissa));
1848 static __u16 mulaw2linear(__u8 data)
1850 /* this conversion is not working */
1851 return data;
1854 #if 0
1855 #define INOUT(x,y) (((x) << 16) | (y))
1856 static int convert_audio(int in_format, int out_format, __u8* buffer, int count)
1858 static int i,sign,exponent;
1859 static __u16 data;
1861 if (in_format == out_format) return count;
1863 switch(INOUT(in_format, out_format)) {
1864 case INOUT(AUDIO_ENCODING_ULAW, AUDIO_ENCODING_LINEAR8):
1865 for (i = 0;i < count; i++) {
1866 buffer[i] = ulaw[buffer[i]];
1868 break;
1869 case INOUT(AUDIO_ENCODING_ULAW, AUDIO_ENCODING_LINEAR):
1870 break;
1871 case INOUT(AUDIO_ENCODING_LINEAR, AUDIO_ENCODING_ULAW):
1872 /* buffer is two-byte => convert to first */
1873 for (i = 0; i < count/2; i++) {
1874 data = ((__u16*)buffer)[i];
1875 sign = (data >> 8) & 0x80;
1876 if (data > CLIP) data = CLIP;
1877 data += BIAS;
1878 exponent = exp_lut[(data >> 7) & 0xFF];
1879 buffer[i] = ~(sign | (exponent << 4) |
1880 ((data >> (exponent + 3)) & 0x0F));
1882 break;
1883 case INOUT(AUDIO_ENCODING_LINEAR8, AUDIO_ENCODING_ULAW):
1884 for (i = 0; i < count; i++) {
1885 buffer[i] = linear[buffer[i]];
1887 break;
1888 default:
1889 return 0;
1892 return count;
1894 #undef INOUT
1895 #endif
1897 #undef BIAS
1898 #undef CLIP
1899 #undef SWAP_ENDIAN