📄 amd7930.c
字号:
if (info->Bb.channel_status == CHANNEL_AVAILABLE && info->Bc.channel_status == CHANNEL_AVAILABLE) { /* Disable B channel interrupts */ sbus_writeb(AMR_MUX_MCR4, info->regs + CR); sbus_writeb(0, info->regs + DR); } } restore_flags(flags);}static void amd7930_bxmit(int dev, unsigned int chan, __u8 * buffer, unsigned long count, void (*callback)(void *, int), void *callback_arg){ struct amd7930_info *info; struct amd7930_channel *Bchan; unsigned long flags; if (dev > num_drivers) return; info = (struct amd7930_info *) drivers[dev].private; Bchan = info->Bisdn[chan]; if (Bchan) { save_and_cli(flags); Bchan->output_ptr = buffer; Bchan->output_count = count; Bchan->output_format = AUDIO_ENCODING_ULAW; Bchan->output_callback = (void *) callback; Bchan->output_callback_arg = callback_arg; restore_flags(flags); }}static void amd7930_brecv(int dev, unsigned int chan, __u8 * buffer, unsigned long size, void (*callback)(void *, int, unsigned int), void *callback_arg){ struct amd7930_info *info; struct amd7930_channel *Bchan; unsigned long flags; if (dev > num_drivers) return; info = (struct amd7930_info *) drivers[dev].private; Bchan = info->Bisdn[chan]; if (Bchan) { save_and_cli(flags); Bchan->input_ptr = buffer; Bchan->input_count = size; Bchan->input_format = AUDIO_ENCODING_ULAW; Bchan->input_callback = (void *) callback; Bchan->input_callback_arg = callback_arg; restore_flags(flags); }}struct foreign_interface amd7930_foreign_interface = { amd7930_get_irqnum, amd7930_get_liu_state, amd7930_liu_init, amd7930_liu_activate, amd7930_liu_deactivate, amd7930_dxmit, amd7930_drecv, amd7930_bopen, amd7930_bclose, amd7930_bxmit, amd7930_brecv};EXPORT_SYMBOL(amd7930_foreign_interface);#endif/* * Device detection and initialization. */static struct sparcaudio_operations amd7930_ops = { amd7930_open, amd7930_release, amd7930_ioctl, amd7930_start_output, amd7930_stop_output, amd7930_start_input, amd7930_stop_input, amd7930_sunaudio_getdev, amd7930_set_output_volume, amd7930_get_output_volume, amd7930_set_input_volume, amd7930_get_input_volume, amd7930_set_monitor_volume, amd7930_get_monitor_volume, NULL, /* amd7930_set_output_balance */ amd7930_get_output_balance, NULL, /* amd7930_set_input_balance */ amd7930_get_input_balance, amd7930_set_output_channels, amd7930_get_output_channels, amd7930_set_input_channels, amd7930_get_input_channels, amd7930_set_output_precision, amd7930_get_output_precision, amd7930_set_input_precision, amd7930_get_input_precision, amd7930_set_output_port, amd7930_get_output_port, NULL, /* amd7930_set_input_port */ amd7930_get_input_port, amd7930_set_encoding, amd7930_get_encoding, amd7930_set_encoding, amd7930_get_encoding, amd7930_set_output_rate, amd7930_get_output_rate, amd7930_set_input_rate, amd7930_get_input_rate, amd7930_sunaudio_getdev_sunos, amd7930_get_output_ports, amd7930_get_input_ports, NULL, /* amd7930_set_output_muted */ amd7930_get_output_muted, NULL, /* amd7930_set_output_pause */ NULL, /* amd7930_get_output_pause */ NULL, /* amd7930_set_input_pause */ NULL, /* amd7930_get_input_pause */ NULL, /* amd7930_set_output_samples */ NULL, /* amd7930_get_output_samples */ NULL, /* amd7930_set_input_samples */ NULL, /* amd7930_get_input_samples */ NULL, /* amd7930_set_output_error */ NULL, /* amd7930_get_output_error */ NULL, /* amd7930_set_input_error */ NULL, /* amd7930_get_input_error */ amd7930_get_formats,};/* Attach to an amd7930 chip given its PROM node. */static int amd7930_attach(struct sparcaudio_driver *drv, int node, struct sbus_bus *sbus, struct sbus_dev *sdev){ struct linux_prom_registers regs; struct linux_prom_irqs irq; struct resource res, *resp; struct amd7930_info *info; int err; /* Allocate our private information structure. */ drv->private = kmalloc(sizeof(struct amd7930_info), GFP_KERNEL); if (drv->private == NULL) return -ENOMEM; /* Point at the information structure and initialize it. */ drv->ops = &amd7930_ops; info = (struct amd7930_info *)drv->private; memset(info, 0, sizeof(*info)); info->ints_on = 1; /* force disable below */ drv->dev = sdev; /* Map the registers into memory. */ prom_getproperty(node, "reg", (char *)®s, sizeof(regs)); if (sbus && sdev) { resp = &sdev->resource[0]; } else { resp = &res; res.start = regs.phys_addr; res.end = res.start + regs.reg_size - 1; res.flags = IORESOURCE_IO | (regs.which_io & 0xff); } info->regs_size = regs.reg_size; info->regs = sbus_ioremap(resp, 0, regs.reg_size, "amd7930"); if (!info->regs) { printk(KERN_ERR "amd7930: could not remap registers\n"); kfree(drv->private); return -EIO; } /* Put amd7930 in idle mode (interrupts disabled) */ amd7930_idle(info); /* Enable extended FIFO operation on D-channel */ sbus_writeb(AMR_DLC_EFCR, info->regs + CR); sbus_writeb(AMR_DLC_EFCR_EXTEND_FIFO, info->regs + DR); sbus_writeb(AMR_DLC_DMR4, info->regs + CR); sbus_writeb(/* AMR_DLC_DMR4_RCV_30 | */ AMR_DLC_DMR4_XMT_14, info->regs + DR); /* Attach the interrupt handler to the audio interrupt. */ prom_getproperty(node, "intr", (char *)&irq, sizeof(irq)); info->irq = irq.pri; request_irq(info->irq, amd7930_interrupt, SA_INTERRUPT, "amd7930", drv); amd7930_enable_ints(info); /* Initalize the local copy of the MAP registers. */ memset(&info->map, 0, sizeof(info->map)); info->map.mmr1 = AM_MAP_MMR1_GX | AM_MAP_MMR1_GER | AM_MAP_MMR1_GR | AM_MAP_MMR1_STG; /* Start out with speaker, microphone */ info->map.mmr2 |= (AM_MAP_MMR2_LS | AM_MAP_MMR2_AINB); /* Set the default audio parameters. */ info->rgain = 128; info->pgain = 200; info->mgain = 0; info->format_type = AUDIO_ENCODING_ULAW; info->Bb.input_format = AUDIO_ENCODING_ULAW; info->Bb.output_format = AUDIO_ENCODING_ULAW; info->Bc.input_format = AUDIO_ENCODING_ULAW; info->Bc.output_format = AUDIO_ENCODING_ULAW; amd7930_update_map(drv); /* Register the amd7930 with the midlevel audio driver. */ err = register_sparcaudio_driver(drv, 1); if (err < 0) { printk(KERN_ERR "amd7930: unable to register\n"); free_irq(info->irq, drv); sbus_iounmap(info->regs, info->regs_size); kfree(drv->private); return -EIO; } /* Announce the hardware to the user. */ printk(KERN_INFO "amd7930 at %lx irq %d\n", info->regs, info->irq); /* Success! */ return 0;}/* Detach from an amd7930 chip given the device structure. */static void __exit amd7930_detach(struct sparcaudio_driver *drv){ struct amd7930_info *info = (struct amd7930_info *)drv->private; unregister_sparcaudio_driver(drv, 1); amd7930_idle(info); free_irq(info->irq, drv); sbus_iounmap(info->regs, info->regs_size); kfree(drv->private);}/* Probe for the amd7930 chip and then attach the driver. */static int __init amd7930_init(void){ struct sbus_bus *sbus; struct sbus_dev *sdev; int node; /* Try to find the sun4c "audio" node first. */ node = prom_getchild(prom_root_node); node = prom_searchsiblings(node, "audio"); if (node && amd7930_attach(&drivers[0], node, NULL, NULL) == 0) num_drivers = 1; else num_drivers = 0; /* Probe each SBUS for amd7930 chips. */ for_all_sbusdev(sdev, sbus) { if (!strcmp(sdev->prom_name, "audio")) { /* Don't go over the max number of drivers. */ if (num_drivers >= MAX_DRIVERS) continue; if (amd7930_attach(&drivers[num_drivers], sdev->prom_node, sdev->bus, sdev) == 0) num_drivers++; } } /* Only return success if we found some amd7930 chips. */ return (num_drivers > 0) ? 0 : -EIO;}static void __exit amd7930_exit(void){ register int i; for (i = 0; i < num_drivers; i++) { amd7930_detach(&drivers[i]); num_drivers--; }}module_init(amd7930_init);module_exit(amd7930_exit);MODULE_LICENSE("GPL");/*************************************************************//* Audio format conversion *//*************************************************************//* Translation tables */static unsigned char ulaw[] = { 3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 121, 122, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 124, 125, 125, 125, 125, 125, 125, 126, 126, 126, 126, 126, 126, 126, 126, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 253, 249, 245, 241, 237, 233, 229, 225, 221, 217, 213, 209, 205, 201, 197, 193, 190, 188, 186, 184, 182, 180, 178, 176, 174, 172, 170, 168, 166, 164, 162, 160, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, 143, 143, 142, 142, 141, 141, 140, 140, 139, 139, 138, 138, 137, 137, 136, 136, 135, 135, 135, 134, 134, 134, 134, 133, 133, 133, 133, 132, 132, 132, 132, 131, 131, 131, 131, 131, 131, 130, 130, 130, 130, 130, 130, 130, 130, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128};static __u8 mulaw2bilinear(__u8 data){ return ulaw[data];}static unsigned char linear[] = { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 15, 0, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 48, 50, 52, 54, 56, 58, 60, 62, 65, 69, 73, 77, 83, 91, 103, 255, 231, 219, 211, 205, 201, 197, 193, 190, 188, 186, 184, 182, 180, 178, 176, 174, 173, 172, 171, 170, 169, 168, 167, 166, 165, 164, 163, 162, 161, 160, 0, 159, 0, 158, 0, 157, 0, 156, 0, 155, 0, 154, 0, 153, 0, 152, 0, 151, 0, 150, 0, 149, 0, 148, 0, 147, 0, 146, 0, 145, 0, 144, 0, 0, 143, 0, 0, 0, 142, 0, 0, 0, 141, 0, 0, 0, 140, 0, 0, 0, 139, 0, 0, 0, 138, 0, 0, 0, 137, 0, 0, 0, 136, 0, 0, 0, 135, 0, 0, 0, 134, 0, 0, 0, 133, 0, 0, 0, 132, 0, 0, 0, 131, 0, 0, 0, 130, 0, 0, 0, 129, 0, 0, 0, 128, 0, 0};static __u8 bilinear2mulaw(__u8 data){ return linear[data];}static int exp_lut[256] = { 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, 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, 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, 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, 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, 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, 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, 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};#define BIAS 0x84#define CLIP 32635#define SWAP_ENDIAN(x) ((x >> 8) | ((x & 0xff) << 8))static __u8 linear2mulaw(__u16 data){ static int sign, exponent, mantissa; /* not really sure, if swapping is ok - comment next line to disable it */ data = SWAP_ENDIAN(data); sign = (data >> 8) & 0x80; if (sign != 0) data = -data; if (data > CLIP) data = CLIP; data += BIAS; exponent = exp_lut[(data >> 7) & 0xFF]; mantissa = (data >> (exponent + 3)) & 0x0F; return (~(sign | (exponent << 4) | mantissa));}static __u16 mulaw2linear(__u8 data){ /* this conversion is not working */ return data;}#if 0#define INOUT(x,y) (((x) << 16) | (y))static int convert_audio(int in_format, int out_format, __u8* buffer, int count){ static int i,sign,exponent; static __u16 data; if (in_format == out_format) return count; switch(INOUT(in_format, out_format)) { case INOUT(AUDIO_ENCODING_ULAW, AUDIO_ENCODING_LINEAR8): for (i = 0;i < count; i++) { buffer[i] = ulaw[buffer[i]]; }; break; case INOUT(AUDIO_ENCODING_ULAW, AUDIO_ENCODING_LINEAR): break; case INOUT(AUDIO_ENCODING_LINEAR, AUDIO_ENCODING_ULAW): /* buffer is two-byte => convert to first */ for (i = 0; i < count/2; i++) { data = ((__u16*)buffer)[i]; sign = (data >> 8) & 0x80; if (data > CLIP) data = CLIP; data += BIAS; exponent = exp_lut[(data >> 7) & 0xFF]; buffer[i] = ~(sign | (exponent << 4) | ((data >> (exponent + 3)) & 0x0F)); }; break; case INOUT(AUDIO_ENCODING_LINEAR8, AUDIO_ENCODING_ULAW): for (i = 0; i < count; i++) { buffer[i] = linear[buffer[i]]; }; break; default: return 0; }; return count;}#undef INOUT#endif#undef BIAS#undef CLIP#undef SWAP_ENDIAN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -