OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [sbus/] [audio/] [amd7930.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* $Id: amd7930.c,v 1.1.1.1 2004-04-15 02:07:29 phoenix Exp $
2
 * drivers/sbus/audio/amd7930.c
3
 *
4
 * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu)
5
 *
6
 * This is the lowlevel driver for the AMD7930 audio chip found on all
7
 * sun4c machines and some sun4m machines.
8
 *
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.
13
 *
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.
16
 *
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.
26
 *
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.
34
 *
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.
39
 *
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.
50
 *
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
55
 *
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.
61
 *
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.
70
 *
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.
84
 */
85
 
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/slab.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>
101
 
102
#include <asm/audioio.h>
103
#include "amd7930.h"
104
 
105
static __u8  bilinear2mulaw(__u8 data);
106
static __u8  mulaw2bilinear(__u8 data);
107
static __u8  linear2mulaw(__u16 data);
108
static __u16 mulaw2linear(__u8 data);
109
 
110
#if defined (AMD79C30_ISDN)
111
#include "../../isdn/hisax/hisax.h"
112
#include "../../isdn/hisax/isdnl1.h"
113
#include "../../isdn/hisax/foreign.h"
114
#endif
115
 
116
#define MAX_DRIVERS 1
117
 
118
static struct sparcaudio_driver drivers[MAX_DRIVERS];
119
static int num_drivers;
120
 
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.
124
 */
125
 
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
132
 
133
struct amd7930_channel {
134
        /* Channel status */
135
        u8 channel_status;
136
 
137
        /* Current buffer that the driver is playing on channel */
138
        volatile __u8 * output_ptr;
139
        volatile u32 output_count;
140
        u8 xmit_idle_char;
141
 
142
        /* Callback routine (and argument) when output is done on */
143
        void (*output_callback)(void *, unsigned char);
144
        void * output_callback_arg;
145
 
146
        /* Current buffer that the driver is recording on channel */
147
        volatile __u8 * input_ptr;
148
        volatile u32 input_count;
149
        volatile u32 input_limit;
150
 
151
        /* Callback routine (and argument) when input is done on */
152
        void (*input_callback)(void *, unsigned char, unsigned long);
153
        void * input_callback_arg;
154
 
155
        int input_format;
156
        int output_format;
157
};
158
 
159
/* Private information we store for each amd7930 chip. */
160
struct amd7930_info {
161
        struct amd7930_channel D;
162
        struct amd7930_channel Bb;
163
        struct amd7930_channel Bc;
164
 
165
        /* Pointers to which B channels are being used for what
166
         * These three fields (Baudio, Bisdn[0], and Bisdn[1]) will either
167
         * be NULL or point to one of the Bb/Bc structures above.
168
         */
169
        struct amd7930_channel *Baudio;
170
        struct amd7930_channel *Bisdn[2];
171
 
172
        /* Device registers information. */
173
        unsigned long regs;
174
        unsigned long regs_size;
175
        struct amd7930_map map;
176
 
177
        /* Volume information. */
178
        int pgain, rgain, mgain;
179
 
180
        /* Device interrupt information. */
181
        int irq;
182
        volatile int ints_on;
183
 
184
        /* Format type */
185
        int format_type;
186
 
187
        /* Someone to signal when the ISDN LIU state changes */
188
        int liu_state;
189
        void (*liu_callback)(void *);
190
        void *liu_callback_arg;
191
};
192
 
193
/* Output a 16-bit quantity in the order that the amd7930 expects. */
194
static __inline__ void amd7930_out16(unsigned long regs, u16 val)
195
{
196
        sbus_writeb(val & 0xff, regs + DR);
197
        sbus_writeb(val >> 8, regs + DR);
198
}
199
 
200
/* gx, gr & stg gains.  this table must contain 256 elements with
201
 * the 0th being "infinity" (the magic value 9008).  The remaining
202
 * elements match sun's gain curve (but with higher resolution):
203
 * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
204
 */
205
static __const__ __u16 gx_coeff[256] = {
206
        0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33,
207
        0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
208
        0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
209
        0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
210
        0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
211
        0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
212
        0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
213
        0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
214
        0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
215
        0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
216
        0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
217
        0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
218
        0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
219
        0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
220
        0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
221
        0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
222
        0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
223
        0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
224
        0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
225
        0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
226
        0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
227
        0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
228
        0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
229
        0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
230
        0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
231
        0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
232
        0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
233
        0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
234
        0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
235
        0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
236
        0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
237
        0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
238
};
239
 
240
static __const__ __u16 ger_coeff[] = {
241
        0x431f, /* 5. dB */
242
        0x331f, /* 5.5 dB */
243
        0x40dd, /* 6. dB */
244
        0x11dd, /* 6.5 dB */
245
        0x440f, /* 7. dB */
246
        0x411f, /* 7.5 dB */
247
        0x311f, /* 8. dB */
248
        0x5520, /* 8.5 dB */
249
        0x10dd, /* 9. dB */
250
        0x4211, /* 9.5 dB */
251
        0x410f, /* 10. dB */
252
        0x111f, /* 10.5 dB */
253
        0x600b, /* 11. dB */
254
        0x00dd, /* 11.5 dB */
255
        0x4210, /* 12. dB */
256
        0x110f, /* 13. dB */
257
        0x7200, /* 14. dB */
258
        0x2110, /* 15. dB */
259
        0x2200, /* 15.9 dB */
260
        0x000b, /* 16.9 dB */
261
        0x000f  /* 18. dB */
262
};
263
#define NR_GER_COEFFS (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
264
 
265
/* Enable amd7930 interrupts atomically. */
266
static void amd7930_enable_ints(struct amd7930_info *info)
267
{
268
        unsigned long flags;
269
 
270
        save_and_cli(flags);
271
        if (!info->ints_on) {
272
                sbus_writeb(AMR_INIT, info->regs + CR);
273
                sbus_writeb(AM_INIT_ACTIVE, info->regs + DR);
274
                info->ints_on = 1;
275
        }
276
        restore_flags(flags);
277
}
278
 
279
/* Disable amd7930 interrupts atomically. */
280
static __inline__ void amd7930_disable_ints(struct amd7930_info *info)
281
{
282
        unsigned long flags;
283
 
284
        save_and_cli(flags);
285
        if (info->ints_on) {
286
                sbus_writeb(AMR_INIT, info->regs + CR);
287
                sbus_writeb(AM_INIT_ACTIVE | AM_INIT_DISABLE_INTS,
288
                            info->regs + DR);
289
                info->ints_on = 0;
290
        }
291
        restore_flags(flags);
292
 
293
}
294
 
295
/* Idle amd7930 (no interrupts, no audio, no data) */
296
static __inline__ void amd7930_idle(struct amd7930_info *info)
297
{
298
        unsigned long flags;
299
 
300
        save_and_cli(flags);
301
        if (info->ints_on) {
302
                sbus_writeb(AMR_INIT, info->regs + CR);
303
                sbus_writeb(0, info->regs + DR);
304
                info->ints_on = 0;
305
        }
306
        restore_flags(flags);
307
}
308
 
309
/* Commit the local copy of the MAP registers to the amd7930. */
310
static void amd7930_write_map(struct sparcaudio_driver *drv)
311
{
312
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
313
        unsigned long        regs = info->regs;
314
        struct amd7930_map  *map  = &info->map;
315
        unsigned long flags;
316
 
317
        save_and_cli(flags);
318
 
319
        sbus_writeb(AMR_MAP_GX, regs + CR);
320
        amd7930_out16(regs, map->gx);
321
 
322
        sbus_writeb(AMR_MAP_GR, regs + CR);
323
        amd7930_out16(regs, map->gr);
324
 
325
        sbus_writeb(AMR_MAP_STGR, regs + CR);
326
        amd7930_out16(regs, map->stgr);
327
 
328
        sbus_writeb(AMR_MAP_GER, regs + CR);
329
        amd7930_out16(regs, map->ger);
330
 
331
        sbus_writeb(AMR_MAP_MMR1, regs + CR);
332
        sbus_writeb(map->mmr1, regs + DR);
333
 
334
        sbus_writeb(AMR_MAP_MMR2, regs + CR);
335
        sbus_writeb(map->mmr2, regs + DR);
336
 
337
        restore_flags(flags);
338
}
339
 
340
/* Update the MAP registers with new settings. */
341
static void amd7930_update_map(struct sparcaudio_driver *drv)
342
{
343
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
344
        struct amd7930_map  *map  = &info->map;
345
        int level;
346
 
347
        map->gx = gx_coeff[info->rgain];
348
        map->stgr = gx_coeff[info->mgain];
349
 
350
        level = (info->pgain * (256 + NR_GER_COEFFS)) >> 8;
351
        if (level >= 256) {
352
                map->ger = ger_coeff[level - 256];
353
                map->gr = gx_coeff[255];
354
        } else {
355
                map->ger = ger_coeff[0];
356
                map->gr = gx_coeff[level];
357
        }
358
 
359
        amd7930_write_map(drv);
360
}
361
 
362
/* Bit of a hack here - if the HISAX ISDN driver has got INTSTAT debugging
363
 * turned on, we send debugging characters to the ISDN driver:
364
 *
365
 *   i# - Interrupt received - number from 0 to 7 is low three bits of IR
366
 *   >  - Loaded a single char into the Dchan xmit FIFO
367
 *   +  - Finished loading an xmit packet into the Dchan xmit FIFO
368
 *   <  - Read a single char from the Dchan recv FIFO
369
 *   !  - Finished reading a packet from the Dchan recv FIFO
370
 *
371
 * This code needs to be removed if anything other than HISAX uses the ISDN
372
 * driver, since D.output_callback_arg is assumed to be a certain struct ptr
373
 */
374
 
375
#ifdef L2FRAME_DEBUG
376
 
377
inline void debug_info(struct amd7930_info *info, char c)
378
{
379
        struct IsdnCardState *cs;
380
 
381
        if (!info || !info->D.output_callback_arg)
382
                return;
383
 
384
        cs = (struct IsdnCardState *) info->D.output_callback_arg;
385
 
386
        if (!cs || !cs->status_write)
387
                return;
388
 
389
        if (cs->debug & L1_DEB_INTSTAT) {
390
                *(cs->status_write++) = c;
391
                if (cs->status_write > cs->status_end)
392
                        cs->status_write = cs->status_buf;
393
        }
394
}
395
 
396
#else
397
 
398
#define debug_info(info,c)
399
 
400
#endif
401
 
402
static void fill_D_xmit_fifo(struct amd7930_info *info)
403
{
404
        /* Send next byte(s) of outgoing data. */
405
        while (info->D.output_ptr && info->D.output_count > 0 &&
406
               (sbus_readb(info->regs + DSR2) & AMR_DSR2_TBE)) {
407
                u8 byte = *(info->D.output_ptr);
408
 
409
                /* Send the next byte and advance buffer pointer. */
410
                sbus_writeb(byte, info->regs + DCTB);
411
                info->D.output_ptr++;
412
                info->D.output_count--;
413
 
414
                debug_info(info, '>');
415
        }
416
}
417
 
418
static void transceive_Dchannel(struct amd7930_info *info)
419
{
420
        __u8 dummy;
421
 
422
#define D_XMIT_ERRORS (AMR_DER_COLLISION | AMR_DER_UNRN)
423
#define D_RECV_ERRORS (AMR_DER_RABRT | AMR_DER_RFRAME | AMR_DER_FCS | \
424
                        AMR_DER_OVFL | AMR_DER_UNFL | AMR_DER_OVRN)
425
 
426
        /* Transmit if we can */
427
        fill_D_xmit_fifo(info);
428
 
429
        /* Done with the xmit buffer? Notify the midlevel driver. */
430
        if (info->D.output_ptr != NULL && info->D.output_count == 0) {
431
                info->D.output_ptr = NULL;
432
                info->D.output_count = 0;
433
                debug_info(info, '+');
434
                if (info->D.output_callback)
435
                        (*info->D.output_callback)
436
                                (info->D.output_callback_arg,
437
                                 sbus_readb(info->regs + DER));
438
                                 /* sbus_readb(info->regs + DER) & D_XMIT_ERRORS); */
439
        }
440
 
441
        /* Read the next byte(s) of incoming data. */
442
 
443
        while (sbus_readb(info->regs + DSR2) & AMR_DSR2_RBA) {
444
                if (info->D.input_ptr &&
445
                    (info->D.input_count < info->D.input_limit)) {
446
                        /* Get the next byte and advance buffer pointer. */
447
                        *(info->D.input_ptr) = sbus_readb(info->regs + DCRB);
448
                        info->D.input_ptr++;
449
                        info->D.input_count++;
450
                } else {
451
                        /* Overflow - should be detected by chip via RBLR
452
                         * so we'll just consume data until we see LBRP
453
                         */
454
                        dummy = sbus_readb(info->regs + DCRB);
455
                }
456
 
457
                debug_info(info, '<');
458
 
459
                if (sbus_readb(info->regs + DSR2) & AMR_DSR2_LBRP) {
460
                        __u8 der;
461
 
462
                        /* End of recv packet? Notify the midlevel driver. */
463
                        debug_info(info, '!');
464
                        info->D.input_ptr = NULL;
465
                        der = sbus_readb(info->regs + DER) & D_RECV_ERRORS;
466
 
467
                        /* Read receive byte count - advances FIFOs */
468
                        sbus_writeb(AMR_DLC_DRCR, info->regs + CR);
469
                        dummy = sbus_readb(info->regs + DR);
470
                        dummy = sbus_readb(info->regs + DR);
471
 
472
                        if (info->D.input_callback)
473
                                (*info->D.input_callback)
474
                                        (info->D.input_callback_arg, der,
475
                                         info->D.input_count);
476
                }
477
 
478
        }
479
}
480
 
481
long amd7930_xmit_idles = 0;
482
 
483
static void transceive_Bchannel(struct amd7930_channel *channel,
484
                                unsigned long reg)
485
{
486
        /* Send the next byte of outgoing data. */
487
        if (channel->output_ptr && channel->output_count > 0) {
488
                u8 byte;
489
 
490
                /* Send the next byte and advance buffer pointer. */
491
                switch(channel->output_format) {
492
                case AUDIO_ENCODING_ULAW:
493
                case AUDIO_ENCODING_ALAW:
494
                        byte = *(channel->output_ptr);
495
                        sbus_writeb(byte, reg);
496
                        break;
497
                case AUDIO_ENCODING_LINEAR8:
498
                        byte = bilinear2mulaw(*(channel->output_ptr));
499
                        sbus_writeb(byte, reg);
500
                        break;
501
                case AUDIO_ENCODING_LINEAR:
502
                        if (channel->output_count >= 2) {
503
                                u16 val = channel->output_ptr[0] << 8;
504
 
505
                                val |= channel->output_ptr[1];
506
                                byte = linear2mulaw(val);
507
                                sbus_writeb(byte, reg);
508
                                channel->output_ptr++;
509
                                channel->output_count--;
510
                        };
511
                };
512
                channel->output_ptr++;
513
                channel->output_count--;
514
 
515
 
516
                /* Done with the buffer? Notify the midlevel driver. */
517
                if (channel->output_count == 0) {
518
                        channel->output_ptr = NULL;
519
                        channel->output_count = 0;
520
                        if (channel->output_callback)
521
                                (*channel->output_callback)
522
                                        (channel->output_callback_arg,1);
523
                }
524
        } else {
525
                sbus_writeb(channel->xmit_idle_char, reg);
526
                amd7930_xmit_idles++;
527
        }
528
 
529
        /* Read the next byte of incoming data. */
530
        if (channel->input_ptr && channel->input_count > 0) {
531
                /* Get the next byte and advance buffer pointer. */
532
                switch(channel->input_format) {
533
                case AUDIO_ENCODING_ULAW:
534
                case AUDIO_ENCODING_ALAW:
535
                        *(channel->input_ptr) = sbus_readb(reg);
536
                        break;
537
                case AUDIO_ENCODING_LINEAR8:
538
                        *(channel->input_ptr) = mulaw2bilinear(sbus_readb(reg));
539
                        break;
540
                case AUDIO_ENCODING_LINEAR:
541
                        if (channel->input_count >= 2) {
542
                                u16 val = mulaw2linear(sbus_readb(reg));
543
                                channel->input_ptr[0] = val >> 8;
544
                                channel->input_ptr[1] = val & 0xff;
545
                                channel->input_ptr++;
546
                                channel->input_count--;
547
                        } else {
548
                                *(channel->input_ptr) = 0;
549
                        }
550
                };
551
                channel->input_ptr++;
552
                channel->input_count--;
553
 
554
                /* Done with the buffer? Notify the midlevel driver. */
555
                if (channel->input_count == 0) {
556
                        channel->input_ptr = NULL;
557
                        channel->input_count = 0;
558
                        if (channel->input_callback)
559
                                (*channel->input_callback)
560
                                        (channel->input_callback_arg, 1, 0);
561
                }
562
        }
563
}
564
 
565
/* Interrupt handler (The chip takes only one byte per interrupt. Grrr!) */
566
static void amd7930_interrupt(int irq, void *dev_id, struct pt_regs *intr_regs)
567
{
568
        struct sparcaudio_driver *drv = (struct sparcaudio_driver *) dev_id;
569
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
570
        unsigned long regs = info->regs;
571
        __u8 ir;
572
 
573
        /* Clear the interrupt. */
574
        ir = sbus_readb(regs + IR);
575
 
576
        if (ir & AMR_IR_BBUF) {
577
                if (info->Bb.channel_status == CHANNEL_INUSE)
578
                        transceive_Bchannel(&info->Bb, info->regs + BBTB);
579
                if (info->Bc.channel_status == CHANNEL_INUSE)
580
                        transceive_Bchannel(&info->Bc, info->regs + BCTB);
581
        }
582
 
583
        if (ir & (AMR_IR_DRTHRSH | AMR_IR_DTTHRSH | AMR_IR_DSRI)) {
584
                debug_info(info, 'i');
585
                debug_info(info, '0' + (ir&7));
586
                transceive_Dchannel(info);
587
        }
588
 
589
        if (ir & AMR_IR_LSRI) {
590
                __u8 lsr;
591
 
592
                sbus_writeb(AMR_LIU_LSR, regs + CR);
593
                lsr = sbus_readb(regs + DR);
594
 
595
                info->liu_state = (lsr & 0x7) + 2;
596
 
597
                if (info->liu_callback)
598
                        (*info->liu_callback)(info->liu_callback_arg);
599
        }
600
}
601
 
602
static int amd7930_open(struct inode * inode, struct file * file,
603
                        struct sparcaudio_driver *drv)
604
{
605
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
606
 
607
        switch(MINOR(inode->i_rdev) & 0xf) {
608
        case SPARCAUDIO_AUDIO_MINOR:
609
                info->format_type = AUDIO_ENCODING_ULAW;
610
                break;
611
        case SPARCAUDIO_DSP_MINOR:
612
                info->format_type = AUDIO_ENCODING_LINEAR8;
613
                break;
614
        case SPARCAUDIO_DSP16_MINOR:
615
                info->format_type = AUDIO_ENCODING_LINEAR;
616
                break;
617
        };
618
 
619
        MOD_INC_USE_COUNT;
620
        return 0;
621
}
622
 
623
static void amd7930_release(struct inode * inode, struct file * file,
624
                            struct sparcaudio_driver *drv)
625
{
626
        /* amd7930_disable_ints(drv->private); */
627
        MOD_DEC_USE_COUNT;
628
}
629
 
630
static void request_Baudio(struct amd7930_info *info)
631
{
632
        if (info->Bb.channel_status == CHANNEL_AVAILABLE) {
633
                info->Bb.channel_status = CHANNEL_INUSE;
634
                info->Baudio = &info->Bb;
635
 
636
                /* Multiplexor map - audio (Ba) to Bb */
637
                sbus_writeb(AMR_MUX_MCR1, info->regs + CR);
638
                sbus_writeb(AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bb << 4),
639
                            info->regs + DR);
640
 
641
                /* Enable B channel interrupts */
642
                sbus_writeb(AMR_MUX_MCR4, info->regs + CR);
643
                sbus_writeb(AM_MUX_MCR4_ENABLE_INTS, info->regs + DR);
644
        } else if (info->Bc.channel_status == CHANNEL_AVAILABLE) {
645
                info->Bc.channel_status = CHANNEL_INUSE;
646
                info->Baudio = &info->Bc;
647
 
648
                /* Multiplexor map - audio (Ba) to Bc */
649
                sbus_writeb(AMR_MUX_MCR1, info->regs + CR);
650
                sbus_writeb(AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bc << 4),
651
                            info->regs + DR);
652
 
653
                /* Enable B channel interrupts */
654
                sbus_writeb(AMR_MUX_MCR4, info->regs + CR);
655
                sbus_writeb(AM_MUX_MCR4_ENABLE_INTS, info->regs + DR);
656
        }
657
}
658
 
659
static void release_Baudio(struct amd7930_info *info)
660
{
661
        if (info->Baudio) {
662
                info->Baudio->channel_status = CHANNEL_AVAILABLE;
663
                sbus_writeb(AMR_MUX_MCR1, info->regs + CR);
664
                sbus_writeb(0, info->regs + DR);
665
                info->Baudio = NULL;
666
 
667
                if (info->Bb.channel_status == CHANNEL_AVAILABLE &&
668
                    info->Bc.channel_status == CHANNEL_AVAILABLE) {
669
                        /* Disable B channel interrupts */
670
                        sbus_writeb(AMR_MUX_MCR4, info->regs + CR);
671
                        sbus_writeb(0, info->regs + DR);
672
                }
673
        }
674
}
675
 
676
static void amd7930_start_output(struct sparcaudio_driver *drv,
677
                                 __u8 * buffer, unsigned long count)
678
{
679
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
680
 
681
        if (! info->Baudio)
682
                request_Baudio(info);
683
 
684
        if (info->Baudio) {
685
                info->Baudio->output_ptr = buffer;
686
                info->Baudio->output_count = count;
687
                info->Baudio->output_format = info->format_type;
688
                info->Baudio->output_callback = (void *) &sparcaudio_output_done;
689
                info->Baudio->output_callback_arg = (void *) drv;
690
                info->Baudio->xmit_idle_char = 0;
691
        }
692
}
693
 
694
static void amd7930_stop_output(struct sparcaudio_driver *drv)
695
{
696
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
697
 
698
        if (info->Baudio) {
699
                info->Baudio->output_ptr = NULL;
700
                info->Baudio->output_count = 0;
701
                if (! info->Baudio->input_ptr)
702
                        release_Baudio(info);
703
        }
704
}
705
 
706
static void amd7930_start_input(struct sparcaudio_driver *drv,
707
                                __u8 * buffer, unsigned long count)
708
{
709
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
710
 
711
        if (! info->Baudio)
712
                request_Baudio(info);
713
 
714
        if (info->Baudio) {
715
                info->Baudio->input_ptr = buffer;
716
                info->Baudio->input_count = count;
717
                info->Baudio->input_format = info->format_type;
718
                info->Baudio->input_callback = (void *) &sparcaudio_input_done;
719
                info->Baudio->input_callback_arg = (void *) drv;
720
        }
721
}
722
 
723
static void amd7930_stop_input(struct sparcaudio_driver *drv)
724
{
725
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
726
 
727
        if (info->Baudio) {
728
                info->Baudio->input_ptr = NULL;
729
                info->Baudio->input_count = 0;
730
                if (! info->Baudio->output_ptr)
731
                        release_Baudio(info);
732
        }
733
 
734
}
735
 
736
static void amd7930_sunaudio_getdev(struct sparcaudio_driver *drv,
737
                                 audio_device_t * audinfo)
738
{
739
        strncpy(audinfo->name, "SUNW,am79c30", sizeof(audinfo->name) - 1);
740
        strncpy(audinfo->version, "a", sizeof(audinfo->version) - 1);
741
        strncpy(audinfo->config, "onboard1", sizeof(audinfo->config) - 1);
742
}
743
 
744
static int amd7930_sunaudio_getdev_sunos(struct sparcaudio_driver *drv)
745
{
746
        return AUDIO_DEV_AMD;
747
}
748
 
749
static int amd7930_get_formats(struct sparcaudio_driver *drv)
750
{
751
      return (AFMT_MU_LAW | AFMT_A_LAW | AFMT_U8 | AFMT_S16_BE);
752
}
753
 
754
static int amd7930_get_output_ports(struct sparcaudio_driver *drv)
755
{
756
      return (AUDIO_SPEAKER | AUDIO_HEADPHONE);
757
}
758
 
759
static int amd7930_get_input_ports(struct sparcaudio_driver *drv)
760
{
761
      return (AUDIO_MICROPHONE);
762
}
763
 
764
static int amd7930_set_output_volume(struct sparcaudio_driver *drv, int vol)
765
{
766
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
767
 
768
        info->pgain = vol;
769
        amd7930_update_map(drv);
770
        return 0;
771
}
772
 
773
static int amd7930_get_output_volume(struct sparcaudio_driver *drv)
774
{
775
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
776
 
777
        return info->pgain;
778
}
779
 
780
static int amd7930_set_input_volume(struct sparcaudio_driver *drv, int vol)
781
{
782
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
783
 
784
        info->rgain = vol;
785
        amd7930_update_map(drv);
786
        return 0;
787
}
788
 
789
static int amd7930_get_input_volume(struct sparcaudio_driver *drv)
790
{
791
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
792
 
793
        return info->rgain;
794
}
795
 
796
static int amd7930_set_monitor_volume(struct sparcaudio_driver *drv, int vol)
797
{
798
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
799
 
800
        info->mgain = vol;
801
        amd7930_update_map(drv);
802
        return 0;
803
}
804
 
805
static int amd7930_get_monitor_volume(struct sparcaudio_driver *drv)
806
{
807
      struct amd7930_info *info = (struct amd7930_info *) drv->private;
808
 
809
      return info->mgain;
810
}
811
 
812
/* Cheats. The amd has the minimum capabilities we support */
813
static int amd7930_get_output_balance(struct sparcaudio_driver *drv)
814
{
815
        return AUDIO_MID_BALANCE;
816
}
817
 
818
static int amd7930_get_input_balance(struct sparcaudio_driver *drv)
819
{
820
        return AUDIO_MID_BALANCE;
821
}
822
 
823
static int amd7930_get_output_channels(struct sparcaudio_driver *drv)
824
{
825
        return AUDIO_MIN_PLAY_CHANNELS;
826
}
827
 
828
static int amd7930_set_output_channels(struct sparcaudio_driver *drv,
829
                                       int value)
830
{
831
  return (value == AUDIO_MIN_PLAY_CHANNELS) ? 0 : -EINVAL;
832
}
833
 
834
static int amd7930_get_input_channels(struct sparcaudio_driver *drv)
835
{
836
        return AUDIO_MIN_REC_CHANNELS;
837
}
838
 
839
static int
840
amd7930_set_input_channels(struct sparcaudio_driver *drv, int value)
841
{
842
        return (value == AUDIO_MIN_REC_CHANNELS) ? 0 : -EINVAL;
843
}
844
 
845
static int amd7930_get_output_precision(struct sparcaudio_driver *drv)
846
{
847
        return AUDIO_MIN_PLAY_PRECISION;
848
}
849
 
850
static int
851
amd7930_set_output_precision(struct sparcaudio_driver *drv, int value)
852
{
853
        return (value == AUDIO_MIN_PLAY_PRECISION) ? 0 : -EINVAL;
854
}
855
 
856
static int amd7930_get_input_precision(struct sparcaudio_driver *drv)
857
{
858
        return AUDIO_MIN_REC_PRECISION;
859
}
860
 
861
static int
862
amd7930_set_input_precision(struct sparcaudio_driver *drv, int value)
863
{
864
        return (value == AUDIO_MIN_REC_PRECISION) ? 0 : -EINVAL;
865
}
866
 
867
static int amd7930_get_output_port(struct sparcaudio_driver *drv)
868
{
869
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
870
 
871
        if (info->map.mmr2 & AM_MAP_MMR2_LS)
872
                return AUDIO_SPEAKER;
873
 
874
        return AUDIO_HEADPHONE;
875
}
876
 
877
static int amd7930_set_output_port(struct sparcaudio_driver *drv, int value)
878
{
879
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
880
 
881
        switch (value) {
882
        case AUDIO_HEADPHONE:
883
                info->map.mmr2 &= ~AM_MAP_MMR2_LS;
884
                break;
885
        case AUDIO_SPEAKER:
886
                info->map.mmr2 |= AM_MAP_MMR2_LS;
887
                break;
888
        default:
889
                return -EINVAL;
890
        };
891
 
892
        amd7930_update_map(drv);
893
        return 0;
894
}
895
 
896
/* Only a microphone here, so no troubles */
897
static int amd7930_get_input_port(struct sparcaudio_driver *drv)
898
{
899
        return AUDIO_MICROPHONE;
900
}
901
 
902
static int amd7930_get_encoding(struct sparcaudio_driver *drv)
903
{
904
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
905
 
906
        if ((info->map.mmr1 & AM_MAP_MMR1_ALAW) &&
907
            (info->format_type == AUDIO_ENCODING_ALAW))
908
                return AUDIO_ENCODING_ALAW;
909
 
910
        return info->format_type;
911
}
912
 
913
static int
914
amd7930_set_encoding(struct sparcaudio_driver *drv, int value)
915
{
916
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
917
 
918
        switch (value) {
919
        case AUDIO_ENCODING_ALAW:
920
                info->map.mmr1 |= AM_MAP_MMR1_ALAW;
921
                break;
922
        case AUDIO_ENCODING_LINEAR8:
923
        case AUDIO_ENCODING_LINEAR:
924
        case AUDIO_ENCODING_ULAW:
925
                info->map.mmr1 &= ~AM_MAP_MMR1_ALAW;
926
                break;
927
        default:
928
                return -EINVAL;
929
        };
930
 
931
        info->format_type = value;
932
 
933
        amd7930_update_map(drv);
934
        return 0;
935
}
936
 
937
/* This is what you get. Take it or leave it */
938
static int amd7930_get_output_rate(struct sparcaudio_driver *drv)
939
{
940
        return AMD7930_RATE;
941
}
942
 
943
static int
944
amd7930_set_output_rate(struct sparcaudio_driver *drv, int value)
945
{
946
        return (value == AMD7930_RATE) ? 0 : -EINVAL;
947
}
948
 
949
static int amd7930_get_input_rate(struct sparcaudio_driver *drv)
950
{
951
        return AMD7930_RATE;
952
}
953
 
954
static int
955
amd7930_set_input_rate(struct sparcaudio_driver *drv, int value)
956
{
957
        return (value == AMD7930_RATE) ? 0 : -EINVAL;
958
}
959
 
960
static int amd7930_get_output_muted(struct sparcaudio_driver *drv)
961
{
962
      return 0;
963
}
964
 
965
static void amd7930_loopback(struct sparcaudio_driver *drv, unsigned int value)
966
{
967
        struct amd7930_info *info = (struct amd7930_info *) drv->private;
968
 
969
        if (value)
970
                info->map.mmr1 |= AM_MAP_MMR1_LOOPBACK;
971
        else
972
                info->map.mmr1 &= ~AM_MAP_MMR1_LOOPBACK;
973
        amd7930_update_map(drv);
974
}
975
 
976
static int amd7930_ioctl(struct inode * inode, struct file * file,
977
                         unsigned int cmd, unsigned long arg,
978
                         struct sparcaudio_driver *drv)
979
{
980
        int retval = 0;
981
 
982
        switch (cmd) {
983
        case AUDIO_DIAG_LOOPBACK:
984
                amd7930_loopback(drv, (unsigned int)arg);
985
                break;
986
        default:
987
                retval = -EINVAL;
988
        };
989
 
990
        return retval;
991
}
992
 
993
 
994
/*
995
 *       ISDN operations
996
 *
997
 * Many of these routines take an "int dev" argument, which is simply
998
 * an index into the drivers[] array.  Currently, we only support a
999
 * single AMD 7930 chip, so the value should always be 0.  B channel
1000
 * operations require an "int chan", which should be 0 for channel B1
1001
 * and 1 for channel B2
1002
 *
1003
 * int amd7930_get_irqnum(int dev)
1004
 *
1005
 *   returns the interrupt number being used by the chip.  ISDN4linux
1006
 *   uses this number to watch the interrupt during initialization and
1007
 *   make sure something is happening.
1008
 *
1009
 * int amd7930_get_liu_state(int dev)
1010
 *
1011
 *   returns the current state of the ISDN Line Interface Unit (LIU)
1012
 *   as a number between 2 (state F2) and 7 (state F7).  0 may also be
1013
 *   returned if the chip doesn't exist or the LIU hasn't been
1014
 *   activated.  The meanings of the states are defined in I.430, ISDN
1015
 *   BRI Physical Layer Interface.  The most important two states are
1016
 *   F3 (shutdown) and F7 (syncronized).
1017
 *
1018
 * void amd7930_liu_init(int dev, void (*callback)(), void *callback_arg)
1019
 *
1020
 *   initializes the LIU and optionally registers a callback to be
1021
 *   signaled upon a change of LIU state.  The callback will be called
1022
 *   with a single opaque callback_arg Once the callback has been
1023
 *   triggered, amd7930_get_liu_state can be used to determine the LIU
1024
 *   current state.
1025
 *
1026
 * void amd7930_liu_activate(int dev, int priority)
1027
 *
1028
 *   requests LIU activation at a given D-channel priority.
1029
 *   Successful activatation is achieved upon entering state F7, which
1030
 *   will trigger any callback previously registered with
1031
 *   amd7930_liu_init.
1032
 *
1033
 * void amd7930_liu_deactivate(int dev)
1034
 *
1035
 *   deactivates LIU.  Outstanding D and B channel transactions are
1036
 *   terminated rudely and without callback notification.  LIU change
1037
 *   of state callback will be triggered, however.
1038
 *
1039
 * void amd7930_dxmit(int dev, __u8 *buffer, unsigned int count,
1040
 *               void (*callback)(void *, int), void *callback_arg)
1041
 *
1042
 *   transmits a packet - specified with buffer, count - over the D-channel
1043
 *   interface.  Buffer should begin with the LAPD address field and
1044
 *   end with the information field.  FCS and flag sequences should not
1045
 *   be included, nor is bit-stuffing required - all these functions are
1046
 *   performed by the chip.  The callback function will be called
1047
 *   DURING THE TOP HALF OF AN INTERRUPT HANDLER and will be passed
1048
 *   both the arbitrary callback_arg and an integer error indication:
1049
 *
1050
 *       0 - successful transmission; ready for next packet
1051
 *   non-0 - error value from chip's DER (D-Channel Error Register):
1052
 *       4 - collision detect
1053
 *     128 - underrun; irq routine didn't service chip fast enough
1054
 *
1055
 *   The callback routine should defer any time-consuming operations
1056
 *   to a bottom-half handler; however, amd7930_dxmit may be called
1057
 *   from within the callback to request back-to-back transmission of
1058
 *   a second packet (without repeating the priority/collision mechanism)
1059
 *
1060
 *   A comment about the "collision detect" error, which is signalled
1061
 *   whenever the echoed D-channel data didn't match the transmitted
1062
 *   data.  This is part of ISDN's normal multi-drop T-interface
1063
 *   operation, indicating that another device has attempted simultaneous
1064
 *   transmission, but can also result from line noise.  An immediate
1065
 *   requeue via amd7930_dxmit is suggested, but repeated collision
1066
 *   errors may indicate a more serious problem.
1067
 *
1068
 * void amd7930_drecv(int dev, __u8 *buffer, unsigned int size,
1069
 *               void (*callback)(void *, int, unsigned int),
1070
 *               void *callback_arg)
1071
 *
1072
 *   register a buffer - buffer, size - into which a D-channel packet
1073
 *   can be received.  The callback function will be called DURING
1074
 *   THE TOP HALF OF AN INTERRUPT HANDLER and will be passed an
1075
 *   arbitrary callback_arg, an integer error indication and the length
1076
 *   of the received packet, which will start with the address field,
1077
 *   end with the information field, and not contain flag or FCS
1078
 *   bytes.  Bit-stuffing will already have been corrected for.
1079
 *   Possible values of second callback argument "error":
1080
 *
1081
 *       0 - successful reception
1082
 *   non-0 - error value from chip's DER (D-Channel Error Register):
1083
 *       1 - received packet abort
1084
 *       2 - framing error; non-integer number of bytes received
1085
 *       8 - FCS error; CRC sequence indicated corrupted data
1086
 *      16 - overflow error; packet exceeded size of buffer
1087
 *      32 - underflow error; packet smaller than required five bytes
1088
 *      64 - overrun error; irq routine didn't service chip fast enough
1089
 *
1090
 * int amd7930_bopen(int dev, int chan, u_char xmit_idle_char)
1091
 *
1092
 *   This function should be called before any other operations on a B
1093
 *   channel.  In addition to arranging for interrupt handling and
1094
 *   channel multiplexing, it sets the xmit_idle_char which is
1095
 *   transmitted on the interface when no data buffer is available.
1096
 *   Suggested values are: 0 for ISDN audio; FF for HDLC mark idle; 7E
1097
 *   for HDLC flag idle.  Returns 0 on a successful open; -1 on error,
1098
 *   which is quite possible if audio and the other ISDN channel are
1099
 *   already in use, since the Am7930 can only send two of the three
1100
 *   channels to the processor
1101
 *
1102
 * void amd7930_bclose(int dev, int chan)
1103
 *
1104
 *   Shuts down a B channel when no longer in use.
1105
 *
1106
 * void amd7930_bxmit(int dev, int chan, __u8 *buffer, unsigned int count,
1107
 *               void (*callback)(void *), void *callback_arg)
1108
 *
1109
 *   transmits a raw data block - specified with buffer, count - over
1110
 *   the B channel interface specified by dev/chan.  The callback
1111
 *   function will be called DURING THE TOP HALF OF AN INTERRUPT
1112
 *   HANDLER and will be passed the arbitrary callback_arg
1113
 *
1114
 *   The callback routine should defer any time-consuming operations
1115
 *   to a bottom-half handler; however, amd7930_bxmit may be called
1116
 *   from within the callback to request back-to-back transmission of
1117
 *   another data block
1118
 *
1119
 * void amd7930_brecv(int dev, int chan, __u8 *buffer, unsigned int size,
1120
 *               void (*callback)(void *), void *callback_arg)
1121
 *
1122
 *   receive a raw data block - specified with buffer, size - over the
1123
 *   B channel interface specified by dev/chan.  The callback function
1124
 *   will be called DURING THE TOP HALF OF AN INTERRUPT HANDLER and
1125
 *   will be passed the arbitrary callback_arg
1126
 *
1127
 *   The callback routine should defer any time-consuming operations
1128
 *   to a bottom-half handler; however, amd7930_brecv may be called
1129
 *   from within the callback to register another buffer and ensure
1130
 *   continuous B channel reception without loss of data
1131
 *
1132
 */
1133
 
1134
#if defined (AMD79C30_ISDN)
1135
static int amd7930_get_irqnum(int dev)
1136
{
1137
        struct amd7930_info *info;
1138
 
1139
        if (dev > num_drivers)
1140
                return(0);
1141
 
1142
        info = (struct amd7930_info *) drivers[dev].private;
1143
 
1144
        return info->irq;
1145
}
1146
 
1147
static int amd7930_get_liu_state(int dev)
1148
{
1149
        struct amd7930_info *info;
1150
 
1151
        if (dev > num_drivers)
1152
                return(0);
1153
 
1154
        info = (struct amd7930_info *) drivers[dev].private;
1155
 
1156
        return info->liu_state;
1157
}
1158
 
1159
static void amd7930_liu_init(int dev, void (*callback)(), void *callback_arg)
1160
{
1161
        struct amd7930_info *info;
1162
        unsigned long flags;
1163
 
1164
        if (dev > num_drivers)
1165
                return;
1166
 
1167
        info = (struct amd7930_info *) drivers[dev].private;
1168
 
1169
        save_and_cli(flags);
1170
 
1171
        /* Set callback for LIU state change */
1172
        info->liu_callback = callback;
1173
        info->liu_callback_arg = callback_arg;
1174
 
1175
        /* De-activate the ISDN Line Interface Unit (LIU) */
1176
        sbus_writeb(AMR_LIU_LMR1, info->regs + CR);
1177
        sbus_writeb(0, info->regs + DR);
1178
 
1179
        /* Request interrupt when LIU changes state from/to F3/F7/F8 */
1180
        sbus_writeb(AMR_LIU_LMR2, info->regs + CR);
1181
        sbus_writeb(AM_LIU_LMR2_EN_F3_INT |
1182
                    AM_LIU_LMR2_EN_F7_INT |
1183
                    AM_LIU_LMR2_EN_F8_INT,
1184
                    info->regs + DR);
1185
 
1186
        /* amd7930_enable_ints(info); */
1187
 
1188
        /* Activate the ISDN Line Interface Unit (LIU) */
1189
        sbus_writeb(AMR_LIU_LMR1, info->regs + CR);
1190
        sbus_writeb(AM_LIU_LMR1_LIU_ENABL, info->regs + DR);
1191
 
1192
        restore_flags(flags);
1193
}
1194
 
1195
static void amd7930_liu_activate(int dev, int priority)
1196
{
1197
        struct amd7930_info *info;
1198
        unsigned long flags;
1199
 
1200
        if (dev > num_drivers)
1201
                return;
1202
 
1203
        info = (struct amd7930_info *) drivers[dev].private;
1204
 
1205
        save_and_cli(flags);
1206
 
1207
        /* Set D-channel access priority
1208
         *
1209
         * I.430 defines a priority mechanism based on counting 1s
1210
         * in the echo channel before transmitting
1211
         *
1212
         * Priority 0 is eight 1s; priority 1 is ten 1s; etc
1213
         */
1214
        sbus_writeb(AMR_LIU_LPR, info->regs + CR);
1215
        sbus_writeb(priority & 0x0f, info->regs + DR);
1216
 
1217
        /* request LIU activation */
1218
        sbus_writeb(AMR_LIU_LMR1, info->regs + CR);
1219
        sbus_writeb(AM_LIU_LMR1_LIU_ENABL | AM_LIU_LMR1_REQ_ACTIV,
1220
                    info->regs + DR);
1221
 
1222
        restore_flags(flags);
1223
}
1224
 
1225
static void amd7930_liu_deactivate(int dev)
1226
{
1227
        struct amd7930_info *info;
1228
        unsigned long flags;
1229
 
1230
        if (dev > num_drivers)
1231
                return;
1232
 
1233
        info = (struct amd7930_info *) drivers[dev].private;
1234
 
1235
        save_and_cli(flags);
1236
 
1237
        /* deactivate LIU */
1238
        sbus_writeb(AMR_LIU_LMR1, info->regs + CR);
1239
        sbus_writeb(0, info->regs + DR);
1240
 
1241
        restore_flags(flags);
1242
}
1243
 
1244
static void amd7930_dxmit(int dev, __u8 *buffer, unsigned int count,
1245
                          void (*callback)(void *, int), void *callback_arg)
1246
{
1247
        struct amd7930_info *info;
1248
        unsigned long flags;
1249
        __u8 dmr1;
1250
 
1251
        if (dev > num_drivers)
1252
                return;
1253
 
1254
        info = (struct amd7930_info *) drivers[dev].private;
1255
 
1256
        save_and_cli(flags);
1257
 
1258
        if (info->D.output_ptr) {
1259
                restore_flags(flags);
1260
                printk("amd7930_dxmit: transmitter in use\n");
1261
                return;
1262
        }
1263
 
1264
        info->D.output_ptr = buffer;
1265
        info->D.output_count = count;
1266
        info->D.output_callback = callback;
1267
        info->D.output_callback_arg = callback_arg;
1268
 
1269
        /* Enable D-channel Transmit Threshold interrupt; disable addressing */
1270
        sbus_writeb(AMR_DLC_DMR1, info->regs + CR);
1271
        dmr1 = sbus_readb(info->regs + DR);
1272
        dmr1 |= AMR_DLC_DMR1_DTTHRSH_INT;
1273
        dmr1 &= ~AMR_DLC_DMR1_EN_ADDRS;
1274
        sbus_writeb(dmr1, info->regs + DR);
1275
 
1276
        /* Begin xmit by setting D-channel Transmit Byte Count Reg (DTCR) */
1277
        sbus_writeb(AMR_DLC_DTCR, info->regs + CR);
1278
        sbus_writeb(count & 0xff, info->regs + DR);
1279
        sbus_writeb((count >> 8) & 0xff, info->regs + DR);
1280
 
1281
        /* Prime xmit FIFO */
1282
        /* fill_D_xmit_fifo(info); */
1283
        transceive_Dchannel(info);
1284
 
1285
        restore_flags(flags);
1286
}
1287
 
1288
static void amd7930_drecv(int dev, __u8 *buffer, unsigned int size,
1289
                          void (*callback)(void *, int, unsigned int),
1290
                          void *callback_arg)
1291
{
1292
        struct amd7930_info *info;
1293
        unsigned long flags;
1294
        __u8 dmr1;
1295
 
1296
        if (dev > num_drivers)
1297
                return;
1298
 
1299
        info = (struct amd7930_info *) drivers[dev].private;
1300
 
1301
        save_and_cli(flags);
1302
 
1303
        if (info->D.input_ptr) {
1304
                restore_flags(flags);
1305
                printk("amd7930_drecv: receiver already has buffer!\n");
1306
                return;
1307
        }
1308
 
1309
        info->D.input_ptr = buffer;
1310
        info->D.input_count = 0;
1311
        info->D.input_limit = size;
1312
        info->D.input_callback = callback;
1313
        info->D.input_callback_arg = callback_arg;
1314
 
1315
        /* Enable D-channel Receive Threshold interrupt;
1316
         * Enable D-channel End of Receive Packet interrupt;
1317
         * Disable address recognition
1318
         */
1319
        sbus_writeb(AMR_DLC_DMR1, info->regs + CR);
1320
        dmr1 = sbus_readb(info->regs + DR);
1321
        dmr1 |= AMR_DLC_DMR1_DRTHRSH_INT | AMR_DLC_DMR1_EORP_INT;
1322
        dmr1 &= ~AMR_DLC_DMR1_EN_ADDRS;
1323
        sbus_writeb(dmr1, info->regs + DR);
1324
 
1325
        /* Set D-channel Receive Byte Count Limit Register */
1326
        sbus_writeb(AMR_DLC_DRCR, info->regs + CR);
1327
        sbus_writeb(size & 0xff, info->regs + DR);
1328
        sbus_writeb((size >> 8) & 0xff, info->regs + DR);
1329
 
1330
        restore_flags(flags);
1331
}
1332
 
1333
static int amd7930_bopen(int dev, unsigned int chan,
1334
                         int mode, u_char xmit_idle_char)
1335
{
1336
        struct amd7930_info *info;
1337
        unsigned long flags;
1338
        u8 tmp;
1339
 
1340
        if (dev > num_drivers || chan<0 || chan>1)
1341
                return -1;
1342
 
1343
        if (mode == L1_MODE_HDLC)
1344
                return -1;
1345
 
1346
        info = (struct amd7930_info *) drivers[dev].private;
1347
 
1348
        save_and_cli(flags);
1349
 
1350
        if (info->Bb.channel_status == CHANNEL_AVAILABLE) {
1351
                info->Bb.channel_status = CHANNEL_INUSE;
1352
                info->Bb.xmit_idle_char = xmit_idle_char;
1353
                info->Bisdn[chan] = &info->Bb;
1354
 
1355
                /* Multiplexor map - isdn (B1/2) to Bb */
1356
                sbus_writeb(AMR_MUX_MCR2 + chan, info->regs + CR);
1357
                sbus_writeb((AM_MUX_CHANNEL_B1 + chan) |
1358
                            (AM_MUX_CHANNEL_Bb << 4),
1359
                            info->regs + DR);
1360
        } else if (info->Bc.channel_status == CHANNEL_AVAILABLE) {
1361
                info->Bc.channel_status = CHANNEL_INUSE;
1362
                info->Bc.xmit_idle_char = xmit_idle_char;
1363
                info->Bisdn[chan] = &info->Bc;
1364
 
1365
                /* Multiplexor map - isdn (B1/2) to Bc */
1366
                sbus_writeb(AMR_MUX_MCR2 + chan, info->regs + CR);
1367
                sbus_writeb((AM_MUX_CHANNEL_B1 + chan) |
1368
                            (AM_MUX_CHANNEL_Bc << 4),
1369
                            info->regs + DR);
1370
        } else {
1371
                restore_flags(flags);
1372
                return (-1);
1373
        }
1374
 
1375
        /* Enable B channel transmit */
1376
        sbus_writeb(AMR_LIU_LMR1, info->regs + CR);
1377
        tmp = sbus_readb(info->regs + DR);
1378
        tmp |= AM_LIU_LMR1_B1_ENABL + chan;
1379
        sbus_writeb(tmp, info->regs + DR);
1380
 
1381
        /* Enable B channel interrupts */
1382
        sbus_writeb(AMR_MUX_MCR4, info->regs + CR);
1383
        sbus_writeb(AM_MUX_MCR4_ENABLE_INTS |
1384
                    AM_MUX_MCR4_REVERSE_Bb |
1385
                    AM_MUX_MCR4_REVERSE_Bc,
1386
                    info->regs + DR);
1387
 
1388
        restore_flags(flags);
1389
        return 0;
1390
}
1391
 
1392
static void amd7930_bclose(int dev, unsigned int chan)
1393
{
1394
        struct amd7930_info *info;
1395
        unsigned long flags;
1396
 
1397
        if (dev > num_drivers || chan<0 || chan>1)
1398
                return;
1399
 
1400
        info = (struct amd7930_info *) drivers[dev].private;
1401
 
1402
        save_and_cli(flags);
1403
 
1404
        if (info->Bisdn[chan]) {
1405
                u8 tmp;
1406
 
1407
                info->Bisdn[chan]->channel_status = CHANNEL_AVAILABLE;
1408
 
1409
                sbus_writeb(AMR_MUX_MCR2 + chan, info->regs + CR);
1410
                sbus_writeb(0, info->regs + DR);
1411
 
1412
                info->Bisdn[chan] = NULL;
1413
 
1414
                /* Disable B channel transmit */
1415
                sbus_writeb(AMR_LIU_LMR1, info->regs + CR);
1416
                tmp = sbus_readb(info->regs + DR);
1417
                tmp &= ~(AM_LIU_LMR1_B1_ENABL + chan);
1418
                sbus_writeb(tmp, info->regs + DR);
1419
 
1420
                if (info->Bb.channel_status == CHANNEL_AVAILABLE &&
1421
                    info->Bc.channel_status == CHANNEL_AVAILABLE) {
1422
                        /* Disable B channel interrupts */
1423
                        sbus_writeb(AMR_MUX_MCR4, info->regs + CR);
1424
                        sbus_writeb(0, info->regs + DR);
1425
                }
1426
        }
1427
 
1428
        restore_flags(flags);
1429
}
1430
 
1431
static void amd7930_bxmit(int dev, unsigned int chan,
1432
                          __u8 * buffer, unsigned long count,
1433
                          void (*callback)(void *, int), void *callback_arg)
1434
{
1435
        struct amd7930_info *info;
1436
        struct amd7930_channel *Bchan;
1437
        unsigned long flags;
1438
 
1439
        if (dev > num_drivers)
1440
                return;
1441
 
1442
        info = (struct amd7930_info *) drivers[dev].private;
1443
        Bchan = info->Bisdn[chan];
1444
 
1445
        if (Bchan) {
1446
                save_and_cli(flags);
1447
 
1448
                Bchan->output_ptr = buffer;
1449
                Bchan->output_count = count;
1450
                Bchan->output_format = AUDIO_ENCODING_ULAW;
1451
                Bchan->output_callback = (void *) callback;
1452
                Bchan->output_callback_arg = callback_arg;
1453
 
1454
                restore_flags(flags);
1455
        }
1456
}
1457
 
1458
static void amd7930_brecv(int dev, unsigned int chan,
1459
                          __u8 * buffer, unsigned long size,
1460
                          void (*callback)(void *, int, unsigned int),
1461
                          void *callback_arg)
1462
{
1463
        struct amd7930_info *info;
1464
        struct amd7930_channel *Bchan;
1465
        unsigned long flags;
1466
 
1467
        if (dev > num_drivers)
1468
                return;
1469
 
1470
        info = (struct amd7930_info *) drivers[dev].private;
1471
        Bchan = info->Bisdn[chan];
1472
 
1473
        if (Bchan) {
1474
                save_and_cli(flags);
1475
 
1476
                Bchan->input_ptr = buffer;
1477
                Bchan->input_count = size;
1478
                Bchan->input_format = AUDIO_ENCODING_ULAW;
1479
                Bchan->input_callback = (void *) callback;
1480
                Bchan->input_callback_arg = callback_arg;
1481
 
1482
                restore_flags(flags);
1483
        }
1484
}
1485
 
1486
struct foreign_interface amd7930_foreign_interface = {
1487
        amd7930_get_irqnum,
1488
        amd7930_get_liu_state,
1489
        amd7930_liu_init,
1490
        amd7930_liu_activate,
1491
        amd7930_liu_deactivate,
1492
        amd7930_dxmit,
1493
        amd7930_drecv,
1494
        amd7930_bopen,
1495
        amd7930_bclose,
1496
        amd7930_bxmit,
1497
        amd7930_brecv
1498
};
1499
EXPORT_SYMBOL(amd7930_foreign_interface);
1500
#endif
1501
 
1502
 
1503
/*
1504
 *      Device detection and initialization.
1505
 */
1506
 
1507
static struct sparcaudio_operations amd7930_ops = {
1508
        amd7930_open,
1509
        amd7930_release,
1510
        amd7930_ioctl,
1511
        amd7930_start_output,
1512
        amd7930_stop_output,
1513
        amd7930_start_input,
1514
        amd7930_stop_input,
1515
        amd7930_sunaudio_getdev,
1516
        amd7930_set_output_volume,
1517
        amd7930_get_output_volume,
1518
        amd7930_set_input_volume,
1519
        amd7930_get_input_volume,
1520
        amd7930_set_monitor_volume,
1521
        amd7930_get_monitor_volume,
1522
        NULL,                   /* amd7930_set_output_balance */
1523
        amd7930_get_output_balance,
1524
        NULL,                   /* amd7930_set_input_balance */
1525
        amd7930_get_input_balance,
1526
        amd7930_set_output_channels,
1527
        amd7930_get_output_channels,
1528
        amd7930_set_input_channels,
1529
        amd7930_get_input_channels,
1530
        amd7930_set_output_precision,
1531
        amd7930_get_output_precision,
1532
        amd7930_set_input_precision,
1533
        amd7930_get_input_precision,
1534
        amd7930_set_output_port,
1535
        amd7930_get_output_port,
1536
        NULL,                   /* amd7930_set_input_port */
1537
        amd7930_get_input_port,
1538
        amd7930_set_encoding,
1539
        amd7930_get_encoding,
1540
        amd7930_set_encoding,
1541
        amd7930_get_encoding,
1542
        amd7930_set_output_rate,
1543
        amd7930_get_output_rate,
1544
        amd7930_set_input_rate,
1545
        amd7930_get_input_rate,
1546
        amd7930_sunaudio_getdev_sunos,
1547
        amd7930_get_output_ports,
1548
        amd7930_get_input_ports,
1549
        NULL,                    /* amd7930_set_output_muted */
1550
        amd7930_get_output_muted,
1551
        NULL,                   /* amd7930_set_output_pause */
1552
        NULL,                   /* amd7930_get_output_pause */
1553
        NULL,                   /* amd7930_set_input_pause */
1554
        NULL,                   /* amd7930_get_input_pause */
1555
        NULL,                   /* amd7930_set_output_samples */
1556
        NULL,                   /* amd7930_get_output_samples */
1557
        NULL,                   /* amd7930_set_input_samples */
1558
        NULL,                   /* amd7930_get_input_samples */
1559
        NULL,                   /* amd7930_set_output_error */
1560
        NULL,                   /* amd7930_get_output_error */
1561
        NULL,                   /* amd7930_set_input_error */
1562
        NULL,                   /* amd7930_get_input_error */
1563
        amd7930_get_formats,
1564
};
1565
 
1566
/* Attach to an amd7930 chip given its PROM node. */
1567
static int amd7930_attach(struct sparcaudio_driver *drv, int node,
1568
                          struct sbus_bus *sbus, struct sbus_dev *sdev)
1569
{
1570
        struct linux_prom_registers regs;
1571
        struct linux_prom_irqs irq;
1572
        struct resource res, *resp;
1573
        struct amd7930_info *info;
1574
        int err;
1575
 
1576
        /* Allocate our private information structure. */
1577
        drv->private = kmalloc(sizeof(struct amd7930_info), GFP_KERNEL);
1578
        if (drv->private == NULL)
1579
                return -ENOMEM;
1580
 
1581
        /* Point at the information structure and initialize it. */
1582
        drv->ops = &amd7930_ops;
1583
        info = (struct amd7930_info *)drv->private;
1584
        memset(info, 0, sizeof(*info));
1585
        info->ints_on = 1; /* force disable below */
1586
 
1587
        drv->dev = sdev;
1588
 
1589
        /* Map the registers into memory. */
1590
        prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
1591
        if (sbus && sdev) {
1592
                resp = &sdev->resource[0];
1593
        } else {
1594
                resp = &res;
1595
                res.start = regs.phys_addr;
1596
                res.end = res.start + regs.reg_size - 1;
1597
                res.flags = IORESOURCE_IO | (regs.which_io & 0xff);
1598
        }
1599
        info->regs_size = regs.reg_size;
1600
        info->regs = sbus_ioremap(resp, 0, regs.reg_size, "amd7930");
1601
        if (!info->regs) {
1602
                printk(KERN_ERR "amd7930: could not remap registers\n");
1603
                kfree(drv->private);
1604
                return -EIO;
1605
        }
1606
 
1607
        /* Put amd7930 in idle mode (interrupts disabled) */
1608
        amd7930_idle(info);
1609
 
1610
        /* Enable extended FIFO operation on D-channel */
1611
        sbus_writeb(AMR_DLC_EFCR, info->regs + CR);
1612
        sbus_writeb(AMR_DLC_EFCR_EXTEND_FIFO, info->regs + DR);
1613
        sbus_writeb(AMR_DLC_DMR4, info->regs + CR);
1614
        sbus_writeb(/* AMR_DLC_DMR4_RCV_30 | */ AMR_DLC_DMR4_XMT_14,
1615
                    info->regs + DR);
1616
 
1617
        /* Attach the interrupt handler to the audio interrupt. */
1618
        prom_getproperty(node, "intr", (char *)&irq, sizeof(irq));
1619
        info->irq = irq.pri;
1620
        request_irq(info->irq, amd7930_interrupt,
1621
                    SA_INTERRUPT, "amd7930", drv);
1622
        amd7930_enable_ints(info);
1623
 
1624
        /* Initalize the local copy of the MAP registers. */
1625
        memset(&info->map, 0, sizeof(info->map));
1626
        info->map.mmr1 = AM_MAP_MMR1_GX | AM_MAP_MMR1_GER |
1627
                         AM_MAP_MMR1_GR | AM_MAP_MMR1_STG;
1628
        /* Start out with speaker, microphone */
1629
        info->map.mmr2 |= (AM_MAP_MMR2_LS | AM_MAP_MMR2_AINB);
1630
 
1631
        /* Set the default audio parameters. */
1632
        info->rgain = 128;
1633
        info->pgain = 200;
1634
        info->mgain = 0;
1635
        info->format_type = AUDIO_ENCODING_ULAW;
1636
        info->Bb.input_format = AUDIO_ENCODING_ULAW;
1637
        info->Bb.output_format = AUDIO_ENCODING_ULAW;
1638
        info->Bc.input_format = AUDIO_ENCODING_ULAW;
1639
        info->Bc.output_format = AUDIO_ENCODING_ULAW;
1640
        amd7930_update_map(drv);
1641
 
1642
        /* Register the amd7930 with the midlevel audio driver. */
1643
        err = register_sparcaudio_driver(drv, 1);
1644
        if (err < 0) {
1645
                printk(KERN_ERR "amd7930: unable to register\n");
1646
                free_irq(info->irq, drv);
1647
                sbus_iounmap(info->regs, info->regs_size);
1648
                kfree(drv->private);
1649
                return -EIO;
1650
        }
1651
 
1652
        /* Announce the hardware to the user. */
1653
        printk(KERN_INFO "amd7930 at %lx irq %d\n",
1654
               info->regs, info->irq);
1655
 
1656
        /* Success! */
1657
        return 0;
1658
}
1659
 
1660
/* Detach from an amd7930 chip given the device structure. */
1661
static void __exit amd7930_detach(struct sparcaudio_driver *drv)
1662
{
1663
        struct amd7930_info *info = (struct amd7930_info *)drv->private;
1664
 
1665
        unregister_sparcaudio_driver(drv, 1);
1666
        amd7930_idle(info);
1667
        free_irq(info->irq, drv);
1668
        sbus_iounmap(info->regs, info->regs_size);
1669
        kfree(drv->private);
1670
}
1671
 
1672
/* Probe for the amd7930 chip and then attach the driver. */
1673
static int __init amd7930_init(void)
1674
{
1675
        struct sbus_bus *sbus;
1676
        struct sbus_dev *sdev;
1677
        int node;
1678
 
1679
        /* Try to find the sun4c "audio" node first. */
1680
        node = prom_getchild(prom_root_node);
1681
        node = prom_searchsiblings(node, "audio");
1682
        if (node && amd7930_attach(&drivers[0], node, NULL, NULL) == 0)
1683
                num_drivers = 1;
1684
        else
1685
                num_drivers = 0;
1686
 
1687
        /* Probe each SBUS for amd7930 chips. */
1688
        for_all_sbusdev(sdev, sbus) {
1689
                if (!strcmp(sdev->prom_name, "audio")) {
1690
                        /* Don't go over the max number of drivers. */
1691
                        if (num_drivers >= MAX_DRIVERS)
1692
                                continue;
1693
 
1694
                        if (amd7930_attach(&drivers[num_drivers],
1695
                                           sdev->prom_node, sdev->bus, sdev) == 0)
1696
                                num_drivers++;
1697
                }
1698
        }
1699
 
1700
        /* Only return success if we found some amd7930 chips. */
1701
        return (num_drivers > 0) ? 0 : -EIO;
1702
}
1703
 
1704
static void __exit amd7930_exit(void)
1705
{
1706
        register int i;
1707
 
1708
        for (i = 0; i < num_drivers; i++) {
1709
                amd7930_detach(&drivers[i]);
1710
                num_drivers--;
1711
        }
1712
}
1713
 
1714
module_init(amd7930_init);
1715
module_exit(amd7930_exit);
1716
MODULE_LICENSE("GPL");
1717
 
1718
/*************************************************************/
1719
/*                 Audio format conversion                   */
1720
/*************************************************************/
1721
 
1722
/* Translation tables */
1723
 
1724
static unsigned char ulaw[] = {
1725
    3,   7,  11,  15,  19,  23,  27,  31,
1726
   35,  39,  43,  47,  51,  55,  59,  63,
1727
   66,  68,  70,  72,  74,  76,  78,  80,
1728
   82,  84,  86,  88,  90,  92,  94,  96,
1729
   98,  99, 100, 101, 102, 103, 104, 105,
1730
  106, 107, 108, 109, 110, 111, 112, 113,
1731
  113, 114, 114, 115, 115, 116, 116, 117,
1732
  117, 118, 118, 119, 119, 120, 120, 121,
1733
  121, 121, 122, 122, 122, 122, 123, 123,
1734
  123, 123, 124, 124, 124, 124, 125, 125,
1735
  125, 125, 125, 125, 126, 126, 126, 126,
1736
  126, 126, 126, 126, 127, 127, 127, 127,
1737
  127, 127, 127, 127, 127, 127, 127, 127,
1738
  128, 128, 128, 128, 128, 128, 128, 128,
1739
  128, 128, 128, 128, 128, 128, 128, 128,
1740
  128, 128, 128, 128, 128, 128, 128, 128,
1741
  253, 249, 245, 241, 237, 233, 229, 225,
1742
  221, 217, 213, 209, 205, 201, 197, 193,
1743
  190, 188, 186, 184, 182, 180, 178, 176,
1744
  174, 172, 170, 168, 166, 164, 162, 160,
1745
  158, 157, 156, 155, 154, 153, 152, 151,
1746
  150, 149, 148, 147, 146, 145, 144, 143,
1747
  143, 142, 142, 141, 141, 140, 140, 139,
1748
  139, 138, 138, 137, 137, 136, 136, 135,
1749
  135, 135, 134, 134, 134, 134, 133, 133,
1750
  133, 133, 132, 132, 132, 132, 131, 131,
1751
  131, 131, 131, 131, 130, 130, 130, 130,
1752
  130, 130, 130, 130, 129, 129, 129, 129,
1753
  129, 129, 129, 129, 129, 129, 129, 129,
1754
  128, 128, 128, 128, 128, 128, 128, 128,
1755
  128, 128, 128, 128, 128, 128, 128, 128,
1756
  128, 128, 128, 128, 128, 128, 128, 128
1757
};
1758
 
1759
static __u8 mulaw2bilinear(__u8 data)
1760
{
1761
        return ulaw[data];
1762
}
1763
 
1764
static unsigned char linear[] = {
1765
     0,    0,    0,    0,    0,    0,    0,    1,
1766
     0,    0,    0,    2,    0,    0,    0,    3,
1767
     0,    0,    0,    4,    0,    0,    0,    5,
1768
     0,    0,    0,    6,    0,    0,    0,    7,
1769
     0,    0,    0,    8,    0,    0,    0,    9,
1770
     0,    0,    0,   10,    0,    0,    0,   11,
1771
     0,    0,    0,   12,    0,    0,    0,   13,
1772
     0,    0,    0,   14,    0,    0,    0,   15,
1773
     0,    0,   16,    0,   17,    0,   18,    0,
1774
    19,    0,   20,    0,   21,    0,   22,    0,
1775
    23,    0,   24,    0,   25,    0,   26,    0,
1776
    27,    0,   28,    0,   29,    0,   30,    0,
1777
    31,    0,   32,   33,   34,   35,   36,   37,
1778
    38,   39,   40,   41,   42,   43,   44,   45,
1779
    46,   48,   50,   52,   54,   56,   58,   60,
1780
    62,   65,   69,   73,   77,   83,   91,  103,
1781
   255,  231,  219,  211,  205,  201,  197,  193,
1782
   190,  188,  186,  184,  182,  180,  178,  176,
1783
   174,  173,  172,  171,  170,  169,  168,  167,
1784
   166,  165,  164,  163,  162,  161,  160,    0,
1785
   159,    0,  158,    0,  157,    0,  156,    0,
1786
   155,    0,  154,    0,  153,    0,  152,    0,
1787
   151,    0,  150,    0,  149,    0,  148,    0,
1788
   147,    0,  146,    0,  145,    0,  144,    0,
1789
     0,  143,    0,    0,    0,  142,    0,    0,
1790
     0,  141,    0,    0,    0,  140,    0,    0,
1791
     0,  139,    0,    0,    0,  138,    0,    0,
1792
     0,  137,    0,    0,    0,  136,    0,    0,
1793
     0,  135,    0,    0,    0,  134,    0,    0,
1794
     0,  133,    0,    0,    0,  132,    0,    0,
1795
     0,  131,    0,    0,    0,  130,    0,    0,
1796
     0,  129,    0,    0,    0,  128,    0,    0
1797
};
1798
 
1799
static __u8 bilinear2mulaw(__u8 data)
1800
{
1801
        return linear[data];
1802
}
1803
 
1804
static int exp_lut[256] = {
1805
        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,
1806
        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,
1807
        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,
1808
        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,
1809
        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,
1810
        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,
1811
        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,
1812
        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
1813
};
1814
 
1815
#define BIAS 0x84
1816
#define CLIP 32635
1817
 
1818
#define SWAP_ENDIAN(x) ((x >> 8) | ((x & 0xff) << 8))
1819
 
1820
static __u8  linear2mulaw(__u16 data)
1821
{
1822
        static int sign, exponent, mantissa;
1823
 
1824
        /* not really sure, if swapping is ok - comment next line to disable it */
1825
        data = SWAP_ENDIAN(data);
1826
 
1827
        sign = (data >> 8) & 0x80;
1828
        if (sign != 0) data = -data;
1829
 
1830
        if (data > CLIP) data = CLIP;
1831
        data += BIAS;
1832
        exponent = exp_lut[(data >> 7) & 0xFF];
1833
        mantissa = (data >> (exponent + 3)) & 0x0F;
1834
 
1835
        return (~(sign | (exponent << 4) | mantissa));
1836
}
1837
 
1838
static __u16 mulaw2linear(__u8 data)
1839
{
1840
        /* this conversion is not working */
1841
        return data;
1842
}
1843
 
1844
#if 0
1845
#define INOUT(x,y) (((x) << 16) | (y))
1846
static int convert_audio(int in_format, int out_format, __u8* buffer, int count)
1847
{
1848
        static int i,sign,exponent;
1849
        static __u16 data;
1850
 
1851
        if (in_format == out_format) return count;
1852
 
1853
        switch(INOUT(in_format, out_format)) {
1854
        case INOUT(AUDIO_ENCODING_ULAW, AUDIO_ENCODING_LINEAR8):
1855
                for (i = 0;i < count; i++) {
1856
                        buffer[i] = ulaw[buffer[i]];
1857
                };
1858
                break;
1859
        case INOUT(AUDIO_ENCODING_ULAW, AUDIO_ENCODING_LINEAR):
1860
                break;
1861
        case INOUT(AUDIO_ENCODING_LINEAR, AUDIO_ENCODING_ULAW):
1862
                /* buffer is two-byte => convert to first */
1863
                for (i = 0; i < count/2; i++) {
1864
                        data = ((__u16*)buffer)[i];
1865
                        sign = (data >> 8) & 0x80;
1866
                        if (data > CLIP) data = CLIP;
1867
                        data += BIAS;
1868
                        exponent = exp_lut[(data >> 7) & 0xFF];
1869
                        buffer[i] = ~(sign | (exponent << 4) |
1870
                                                  ((data >> (exponent + 3)) & 0x0F));
1871
                };
1872
                break;
1873
        case INOUT(AUDIO_ENCODING_LINEAR8, AUDIO_ENCODING_ULAW):
1874
                for (i = 0; i < count; i++) {
1875
                        buffer[i] = linear[buffer[i]];
1876
                };
1877
                break;
1878
        default:
1879
                return 0;
1880
        };
1881
 
1882
        return count;
1883
}
1884
#undef INOUT
1885
#endif
1886
 
1887
#undef BIAS
1888
#undef CLIP
1889
#undef SWAP_ENDIAN

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.