📄 dbri.c
字号:
*/static int mmcodec_setctrl(struct dbri *dbri){ int i, val; u32 tmp; /* XXX - let the CPU do something useful during these delays */ /* Temporarily mute outputs, and wait 1/8000 sec (125 us) * to make sure this takes. This avoids clicking noises. */ mmcodec_setgain(dbri, 1); udelay(125); /* * Enable Control mode: Set DBRI's PIO3 (4215's D/~C) to 0, then wait * 12 cycles <= 12/(5512.5*64) sec = 34.01 usec */ val = D_ENPIO | D_PIO1 | (dbri->mm.onboard ? D_PIO0 : D_PIO2); sbus_writel(val, dbri->regs + REG2); udelay(34); /* In Control mode, the CS4215 is a slave device, so the DBRI must * operate as CHI master, supplying clocking and frame synchronization. * * In Data mode, however, the CS4215 must be CHI master to insure * that its data stream is synchronous with its codec. * * The upshot of all this? We start by putting the DBRI into master * mode, program the CS4215 in Control mode, then switch the CS4215 * into Data mode and put the DBRI into slave mode. Various timing * requirements must be observed along the way. * * Oh, and one more thing, on a SPARCStation 20 (and maybe * others?), the addressing of the CS4215's time slots is * offset by eight bits, so we add eight to all the "cycle" * values in the Define Time Slot (DTS) commands. This is * done in hardware by a TI 248 that delays the DBRI->4215 * frame sync signal by eight clock cycles. Anybody know why? */ tmp = sbus_readl(dbri->regs + REG0); tmp &= ~D_C; /* Disable CHI */ sbus_writel(tmp, dbri->regs + REG0); reset_chi(dbri, CHImaster, 128); /* * Control mode: * Pipe 17: Send timeslots 1-4 (slots 5-8 are readonly) * Pipe 18: Receive timeslot 1 (clb). * Pipe 19: Receive timeslot 7 (version). */ link_time_slot(dbri, 17, PIPEoutput, 16, 32, dbri->mm.offset); link_time_slot(dbri, 18, PIPEinput, 16, 8, dbri->mm.offset); link_time_slot(dbri, 19, PIPEinput, 16, 8, dbri->mm.offset + 48); /* Wait for the chip to echo back CLB (Control Latch Bit) as zero */ dbri->mm.ctrl[0] &= ~CS4215_CLB; xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl); tmp = sbus_readl(dbri->regs + REG0); tmp |= D_C; /* Enable CHI */ sbus_writel(tmp, dbri->regs + REG0); i = 64; while (((dbri->mm.status & 0xe4) != 0x20) && --i) udelay(125); if (i == 0) { dprintk(D_MM, ("DBRI: CS4215 didn't respond to CLB (0x%02x)\n", dbri->mm.status)); return -1; } /* Terminate CS4215 control mode - data sheet says * "Set CLB=1 and send two more frames of valid control info" */ dbri->mm.ctrl[0] |= CS4215_CLB; xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl); /* Two frames of control info @ 8kHz frame rate = 250 us delay */ udelay(250); mmcodec_setgain(dbri, 0); return 0;}static int mmcodec_init(struct sparcaudio_driver *drv){ struct dbri *dbri = (struct dbri *) drv->private; u32 reg2 = sbus_readl(dbri->regs + REG2); /* Look for the cs4215 chips */ if(reg2 & D_PIO2) { dprintk(D_MM, ("DBRI: Onboard CS4215 detected\n")); dbri->mm.onboard = 1; } if(reg2 & D_PIO0) { dprintk(D_MM, ("DBRI: Speakerbox detected\n")); dbri->mm.onboard = 0; } /* Using the Speakerbox, if both are attached. */ if((reg2 & D_PIO2) && (reg2 & D_PIO0)) { printk("DBRI: Using speakerbox / ignoring onboard mmcodec.\n"); sbus_writel(D_ENPIO2, dbri->regs + REG2); dbri->mm.onboard = 0; } if(!(reg2 & (D_PIO0|D_PIO2))) { printk("DBRI: no mmcodec found.\n"); return -EIO; } mmcodec_setup_pipes(dbri); mmcodec_default(&dbri->mm); dbri->mm.version = 0xff; dbri->mm.offset = dbri->mm.onboard ? 0 : 8; if (mmcodec_setctrl(dbri) == -1 || dbri->mm.version == 0xff) { dprintk(D_MM, ("DBRI: CS4215 failed probe at offset %d\n", dbri->mm.offset)); return -EIO; } dprintk(D_MM, ("DBRI: Found CS4215 at offset %d\n", dbri->mm.offset)); dbri->perchip_info.play.channels = 1; dbri->perchip_info.play.precision = 8; dbri->perchip_info.play.gain = (AUDIO_MAX_GAIN * 7 / 10); /* 70% */ dbri->perchip_info.play.balance = AUDIO_MID_BALANCE; dbri->perchip_info.play.port = dbri->perchip_info.play.avail_ports = AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT; dbri->perchip_info.record.port = AUDIO_MICROPHONE; dbri->perchip_info.record.avail_ports = AUDIO_MICROPHONE | AUDIO_LINE_IN; mmcodec_init_data(dbri); return 0;}/************************************************************************************************* Interface with sparcaudio midlevel ************************************************************************************************The sparcaudio midlevel is contained in the file audio.c. It interfacesto the user process and performs buffering, intercepts SunOS-style ioctl's,etc. It interfaces to a abstract audio device via a struct sparcaudio_driver.This code presents such an interface for the DBRI with an attached CS4215.All our routines are defined, and then comes our struct sparcaudio_driver.*//******************* sparcaudio midlevel - audio output *******************/static void dbri_audio_output_callback(void * callback_arg, int status){ struct sparcaudio_driver *drv = callback_arg; if (status != -1) sparcaudio_output_done(drv, 1);}static void dbri_start_output(struct sparcaudio_driver *drv, __u8 * buffer, unsigned long count){ struct dbri *dbri = (struct dbri *) drv->private; dprintk(D_USR, ("DBRI: start audio output buf=%p/%ld\n", buffer, count)); /* Pipe 4 is audio transmit */ xmit_on_pipe(dbri, 4, buffer, count, &dbri_audio_output_callback, drv);#if 0 /* Notify midlevel that we're a DMA-capable driver that * can accept another buffer immediately. We should probably * check that we've got enough resources (i.e, descriptors) * available before doing this, but the default midlevel * settings only buffer 64KB, which we can handle with 16 * of our DBRI_NO_DESCS (64) descriptors. * * This code is #ifdef'ed out because it's caused me more * problems than it solved. It'd be nice to provide the * DBRI with a chain of buffers, but the midlevel code is * so tricky that I really don't want to deal with it. */ sparcaudio_output_done(drv, 2);#endif}static void dbri_stop_output(struct sparcaudio_driver *drv){ struct dbri *dbri = (struct dbri *) drv->private; reset_pipe(dbri, 4);}/******************* sparcaudio midlevel - audio input ********************/static void dbri_audio_input_callback(void * callback_arg, int status, unsigned int len){ struct sparcaudio_driver * drv = (struct sparcaudio_driver *) callback_arg; if (status != -1) sparcaudio_input_done(drv, 3);}static void dbri_start_input(struct sparcaudio_driver *drv, __u8 * buffer, unsigned long len){ struct dbri *dbri = (struct dbri *) drv->private; /* Pipe 6 is audio receive */ recv_on_pipe(dbri, 6, buffer, len, &dbri_audio_input_callback, (void *)drv); dprintk(D_USR, ("DBRI: start audio input buf=%p/%ld\n", buffer, len));}static void dbri_stop_input(struct sparcaudio_driver *drv){ struct dbri *dbri = (struct dbri *) drv->private; reset_pipe(dbri, 6);}/******************* sparcaudio midlevel - volume & balance ***************/static int dbri_set_output_volume(struct sparcaudio_driver *drv, int volume){ struct dbri *dbri = (struct dbri *) drv->private; dbri->perchip_info.play.gain = volume; mmcodec_setgain(dbri, 0); return 0;}static int dbri_get_output_volume(struct sparcaudio_driver *drv){ struct dbri *dbri = (struct dbri *) drv->private; return dbri->perchip_info.play.gain;}static int dbri_set_input_volume(struct sparcaudio_driver *drv, int volume){ return 0;}static int dbri_get_input_volume(struct sparcaudio_driver *drv){ return 0;}static int dbri_set_monitor_volume(struct sparcaudio_driver *drv, int volume){ return 0;}static int dbri_get_monitor_volume(struct sparcaudio_driver *drv){ return 0;}static int dbri_set_output_balance(struct sparcaudio_driver *drv, int balance){ struct dbri *dbri = (struct dbri *) drv->private; dbri->perchip_info.play.balance = balance; mmcodec_setgain(dbri, 0); return 0;}static int dbri_get_output_balance(struct sparcaudio_driver *drv){ struct dbri *dbri = (struct dbri *) drv->private; return dbri->perchip_info.play.balance;}static int dbri_set_input_balance(struct sparcaudio_driver *drv, int balance){ return 0;}static int dbri_get_input_balance(struct sparcaudio_driver *drv){ return 0;}static int dbri_set_output_muted(struct sparcaudio_driver *drv, int mute){ struct dbri *dbri = (struct dbri *) drv->private; dbri->perchip_info.output_muted = mute; return 0;}static int dbri_get_output_muted(struct sparcaudio_driver *drv){ struct dbri *dbri = (struct dbri *) drv->private; return dbri->perchip_info.output_muted;}/******************* sparcaudio midlevel - encoding format ****************/static int dbri_set_output_channels(struct sparcaudio_driver *drv, int chan){ struct dbri *dbri = (struct dbri *) drv->private; switch (chan) { case 0: return 0; case 1: dbri->mm.ctrl[1] &= ~CS4215_DFR_STEREO; break; case 2: dbri->mm.ctrl[1] |= CS4215_DFR_STEREO; break; default: return -1; } dbri->perchip_info.play.channels = chan; mmcodec_setctrl(dbri); mmcodec_init_data(dbri); return 0;}static int dbri_get_output_channels(struct sparcaudio_driver *drv){ struct dbri *dbri = (struct dbri *) drv->private; return dbri->perchip_info.play.channels;}static int dbri_set_input_channels(struct sparcaudio_driver *drv, int chan){ return dbri_set_output_channels(drv, chan);}static int dbri_get_input_channels(struct sparcaudio_driver *drv){ return dbri_get_output_channels(drv);}static int dbri_set_output_precision(struct sparcaudio_driver *drv, int prec){ return 0;}static int dbri_get_output_precision(struct sparcaudio_driver *drv){ struct dbri *dbri = (struct dbri *) drv->private; return dbri->perchip_info.play.precision;}static int dbri_set_input_precision(struct sparcaudio_driver *drv, int prec){ return 0;}static int dbri_get_input_precision(struct sparcaudio_driver *drv){ struct dbri *dbri = (struct dbri *) drv->private; return dbri->perchip_info.play.precision;}static int dbri_set_output_encoding(struct sparcaudio_driver *drv, int enc){ struct dbri *dbri = (struct dbri *) drv->private; /* For ULAW and ALAW, audio.c enforces precision = 8, * for LINEAR, precision must be 16 */ switch (enc) { case AUDIO_ENCODING_NONE: return 0; case AUDIO_ENCODING_ULAW: dbri->mm.ctrl[1] &= ~3; dbri->mm.ctrl[1] |= CS4215_DFR_ULAW; dbri->perchip_info.play.encoding = enc; dbri->perchip_info.play.precision = 8; break; case AUDIO_ENCODING_ALAW: dbri->mm.ctrl[1] &= ~3; dbri->mm.ctrl[1] |= CS4215_DFR_ALAW; dbri->perchip_info.play.encoding = enc; dbri->perchip_info.play.precision = 8; break; case AUDIO_ENCODING_LINEAR: dbri->mm.ctrl[1] &= ~3; dbri->mm.ctrl[1] |= CS4215_DFR_LINEAR16; dbri->perchip_info.play.encoding = enc; dbri->perchip_info.play.precision = 16; break; default: return -1; }; mmcodec_setctrl(dbri); mmcodec_init_data(dbri); return 0;}static int dbri_get_output_encoding(struct sparcaudio_driver *drv){ struct dbri *dbri = (struct dbri *) drv->private; return dbri->perchip_info.play.encoding;}static int dbri_set_input_encoding(struct sparcaudio_driver *drv, int enc){ return dbri_set_output_encoding(drv, enc);}static int dbri_get_input_encoding(struct sparcaudio_driver *drv){ return dbri_get_output_encoding(drv);}static int dbri_set_output_rate(struct sparcaudio_driver *drv, int rate){ struct dbri *dbri = (struct dbri *) drv->private; int i; if (rate == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -