📄 ttusb_dec.c
字号:
}static void ttusb_dec_init_tasklet(struct ttusb_dec *dec){ spin_lock_init(&dec->urb_frame_list_lock); INIT_LIST_HEAD(&dec->urb_frame_list); tasklet_init(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list, (unsigned long)dec);}static int ttusb_init_rc( struct ttusb_dec *dec){ struct input_dev *input_dev; u8 b[] = { 0x00, 0x01 }; int i; usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys)); strlcpy(dec->rc_phys, "/input0", sizeof(dec->rc_phys)); dec->rc_input_dev = input_dev = input_allocate_device(); if (!input_dev) return -ENOMEM; input_dev->name = "ttusb_dec remote control"; input_dev->phys = dec->rc_phys; input_dev->evbit[0] = BIT(EV_KEY); input_dev->keycodesize = sizeof(u16); input_dev->keycodemax = 0x1a; input_dev->keycode = rc_keys; for (i = 0; i < ARRAY_SIZE(rc_keys); i++) set_bit(rc_keys[i], input_dev->keybit); input_register_device(input_dev); if (usb_submit_urb(dec->irq_urb, GFP_KERNEL)) printk("%s: usb_submit_urb failed\n",__FUNCTION__); /* enable irq pipe */ ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL); return 0;}static void ttusb_dec_init_v_pes(struct ttusb_dec *dec){ dprintk("%s\n", __FUNCTION__); dec->v_pes[0] = 0x00; dec->v_pes[1] = 0x00; dec->v_pes[2] = 0x01; dec->v_pes[3] = 0xe0;}static int ttusb_dec_init_usb(struct ttusb_dec *dec){ dprintk("%s\n", __FUNCTION__); mutex_init(&dec->usb_mutex); mutex_init(&dec->iso_mutex); dec->command_pipe = usb_sndbulkpipe(dec->udev, COMMAND_PIPE); dec->result_pipe = usb_rcvbulkpipe(dec->udev, RESULT_PIPE); dec->in_pipe = usb_rcvisocpipe(dec->udev, IN_PIPE); dec->out_pipe = usb_sndisocpipe(dec->udev, OUT_PIPE); dec->irq_pipe = usb_rcvintpipe(dec->udev, IRQ_PIPE); if(enable_rc) { dec->irq_urb = usb_alloc_urb(0, GFP_KERNEL); if(!dec->irq_urb) { return -ENOMEM; } dec->irq_buffer = usb_buffer_alloc(dec->udev,IRQ_PACKET_SIZE, SLAB_ATOMIC, &dec->irq_dma_handle); if(!dec->irq_buffer) { return -ENOMEM; } usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe, dec->irq_buffer, IRQ_PACKET_SIZE, ttusb_dec_handle_irq, dec, 1); dec->irq_urb->transfer_dma = dec->irq_dma_handle; dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } return ttusb_dec_alloc_iso_urbs(dec);}static int ttusb_dec_boot_dsp(struct ttusb_dec *dec){ int i, j, actual_len, result, size, trans_count; u8 b0[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x00 }; u8 b1[] = { 0x61 }; u8 *b; char idstring[21]; u8 *firmware = NULL; size_t firmware_size = 0; u16 firmware_csum = 0; u16 firmware_csum_ns; u32 firmware_size_nl; u32 crc32_csum, crc32_check, tmp; const struct firmware *fw_entry = NULL; dprintk("%s\n", __FUNCTION__); if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) { printk(KERN_ERR "%s: Firmware (%s) unavailable.\n", __FUNCTION__, dec->firmware_name); return 1; } firmware = fw_entry->data; firmware_size = fw_entry->size; if (firmware_size < 60) { printk("%s: firmware size too small for DSP code (%zu < 60).\n", __FUNCTION__, firmware_size); release_firmware(fw_entry); return -1; } /* a 32 bit checksum over the first 56 bytes of the DSP Code is stored at offset 56 of file, so use it to check if the firmware file is valid. */ crc32_csum = crc32(~0L, firmware, 56) ^ ~0L; memcpy(&tmp, &firmware[56], 4); crc32_check = htonl(tmp); if (crc32_csum != crc32_check) { printk("%s: crc32 check of DSP code failed (calculated " "0x%08x != 0x%08x in file), file invalid.\n", __FUNCTION__, crc32_csum, crc32_check); release_firmware(fw_entry); return -1; } memcpy(idstring, &firmware[36], 20); idstring[20] = '\0'; printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring); firmware_size_nl = htonl(firmware_size); memcpy(b0, &firmware_size_nl, 4); firmware_csum = crc16(~0, firmware, firmware_size) ^ ~0; firmware_csum_ns = htons(firmware_csum); memcpy(&b0[6], &firmware_csum_ns, 2); result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL); if (result) { release_firmware(fw_entry); return result; } trans_count = 0; j = 0; b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL); if (b == NULL) { release_firmware(fw_entry); return -ENOMEM; } for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) { size = firmware_size - i; if (size > COMMAND_PACKET_SIZE) size = COMMAND_PACKET_SIZE; b[j + 0] = 0xaa; b[j + 1] = trans_count++; b[j + 2] = 0xf0; b[j + 3] = size; memcpy(&b[j + 4], &firmware[i], size); j += COMMAND_PACKET_SIZE + 4; if (j >= ARM_PACKET_SIZE) { result = usb_bulk_msg(dec->udev, dec->command_pipe, b, ARM_PACKET_SIZE, &actual_len, 100); j = 0; } else if (size < COMMAND_PACKET_SIZE) { result = usb_bulk_msg(dec->udev, dec->command_pipe, b, j - COMMAND_PACKET_SIZE + size, &actual_len, 100); } } result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL); release_firmware(fw_entry); kfree(b); return result;}static int ttusb_dec_init_stb(struct ttusb_dec *dec){ int result; unsigned int mode, model, version; dprintk("%s\n", __FUNCTION__); result = ttusb_dec_get_stb_state(dec, &mode, &model, &version); if (!result) { if (!mode) { if (version == 0xABCDEFAB) printk(KERN_INFO "ttusb_dec: no version " "info in Firmware\n"); else printk(KERN_INFO "ttusb_dec: Firmware " "%x.%02x%c%c\n", version >> 24, (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); result = ttusb_dec_boot_dsp(dec); if (result) return result; else return 1; } else { /* We can't trust the USB IDs that some firmwares give the box */ switch (model) { case 0x00070001: case 0x00070008: case 0x0007000c: ttusb_dec_set_model(dec, TTUSB_DEC3000S); break; case 0x00070009: case 0x00070013: ttusb_dec_set_model(dec, TTUSB_DEC2000T); break; case 0x00070011: ttusb_dec_set_model(dec, TTUSB_DEC2540T); break; default: printk(KERN_ERR "%s: unknown model returned " "by firmware (%08x) - please report\n", __FUNCTION__, model); return -1; break; } if (version >= 0x01770000) dec->can_playback = 1; return 0; } } else return result;}static int ttusb_dec_init_dvb(struct ttusb_dec *dec){ int result; dprintk("%s\n", __FUNCTION__); if ((result = dvb_register_adapter(&dec->adapter, dec->model_name, THIS_MODULE, &dec->udev->dev)) < 0) { printk("%s: dvb_register_adapter failed: error %d\n", __FUNCTION__, result); return result; } dec->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; dec->demux.priv = (void *)dec; dec->demux.filternum = 31; dec->demux.feednum = 31; dec->demux.start_feed = ttusb_dec_start_feed; dec->demux.stop_feed = ttusb_dec_stop_feed; dec->demux.write_to_decoder = NULL; if ((result = dvb_dmx_init(&dec->demux)) < 0) { printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__, result); dvb_unregister_adapter(&dec->adapter); return result; } dec->dmxdev.filternum = 32; dec->dmxdev.demux = &dec->demux.dmx; dec->dmxdev.capabilities = 0; if ((result = dvb_dmxdev_init(&dec->dmxdev, &dec->adapter)) < 0) { printk("%s: dvb_dmxdev_init failed: error %d\n", __FUNCTION__, result); dvb_dmx_release(&dec->demux); dvb_unregister_adapter(&dec->adapter); return result; } dec->frontend.source = DMX_FRONTEND_0; if ((result = dec->demux.dmx.add_frontend(&dec->demux.dmx, &dec->frontend)) < 0) { printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__, result); dvb_dmxdev_release(&dec->dmxdev); dvb_dmx_release(&dec->demux); dvb_unregister_adapter(&dec->adapter); return result; } if ((result = dec->demux.dmx.connect_frontend(&dec->demux.dmx, &dec->frontend)) < 0) { printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__, result); dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); dvb_dmxdev_release(&dec->dmxdev); dvb_dmx_release(&dec->demux); dvb_unregister_adapter(&dec->adapter); return result; } dvb_net_init(&dec->adapter, &dec->dvb_net, &dec->demux.dmx); return 0;}static void ttusb_dec_exit_dvb(struct ttusb_dec *dec){ dprintk("%s\n", __FUNCTION__); dvb_net_release(&dec->dvb_net); dec->demux.dmx.close(&dec->demux.dmx); dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); dvb_dmxdev_release(&dec->dmxdev); dvb_dmx_release(&dec->demux); if (dec->fe) dvb_unregister_frontend(dec->fe); dvb_unregister_adapter(&dec->adapter);}static void ttusb_dec_exit_rc(struct ttusb_dec *dec){ dprintk("%s\n", __FUNCTION__); /* we have to check whether the irq URB is already submitted. * As the irq is submitted after the interface is changed, * this is the best method i figured out. * Any others?*/ if (dec->interface == TTUSB_DEC_INTERFACE_IN) usb_kill_urb(dec->irq_urb); usb_free_urb(dec->irq_urb); usb_buffer_free(dec->udev,IRQ_PACKET_SIZE, dec->irq_buffer, dec->irq_dma_handle); if (dec->rc_input_dev) { input_unregister_device(dec->rc_input_dev); dec->rc_input_dev = NULL; }}static void ttusb_dec_exit_usb(struct ttusb_dec *dec){ int i; dprintk("%s\n", __FUNCTION__); dec->iso_stream_count = 0; for (i = 0; i < ISO_BUF_COUNT; i++) usb_kill_urb(dec->iso_urb[i]); ttusb_dec_free_iso_urbs(dec);}static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec){ struct list_head *item; struct urb_frame *frame; tasklet_kill(&dec->urb_tasklet); while ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) { frame = list_entry(item, struct urb_frame, urb_frame_list); list_del(&frame->urb_frame_list); kfree(frame); }}static void ttusb_dec_init_filters(struct ttusb_dec *dec){ INIT_LIST_HEAD(&dec->filter_info_list); spin_lock_init(&dec->filter_info_list_lock);}static void ttusb_dec_exit_filters(struct ttusb_dec *dec){ struct list_head *item; struct filter_info *finfo; while ((item = dec->filter_info_list.next) != &dec->filter_info_list) { finfo = list_entry(item, struct filter_info, filter_info_list); list_del(&finfo->filter_info_list); kfree(finfo); }}static int fe_send_command(struct dvb_frontend* fe, const u8 command, int param_length, const u8 params[], int *result_length, u8 cmd_result[]){ struct ttusb_dec* dec = fe->dvb->priv; return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result);}static struct ttusbdecfe_config fe_config = { .send_command = fe_send_command};static int ttusb_dec_probe(struct usb_interface *intf, const struct usb_device_id *id){ struct usb_device *udev; struct ttusb_dec *dec; dprintk("%s\n", __FUNCTION__); udev = interface_to_usbdev(intf); if (!(dec = kzalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) { printk("%s: couldn't allocate memory.\n", __FUNCTION__); return -ENOMEM; } usb_set_intfdata(intf, (void *)dec); switch (le16_to_cpu(id->idProduct)) { case 0x1006: ttusb_dec_set_model(dec, TTUSB_DEC3000S); break; case 0x1008: ttusb_dec_set_model(dec, TTUSB_DEC2000T); break; case 0x1009: ttusb_dec_set_model(dec, TTUSB_DEC2540T); break; } dec->udev = udev; if (ttusb_dec_init_usb(dec)) return 0; if (ttusb_dec_init_stb(dec)) { ttusb_dec_exit_usb(dec); return 0; } ttusb_dec_init_dvb(dec); dec->adapter.priv = dec; switch (le16_to_cpu(id->idProduct)) { case 0x1006: dec->fe = ttusbdecfe_dvbs_attach(&fe_config); break; case 0x1008: case 0x1009: dec->fe = ttusbdecfe_dvbt_attach(&fe_config); break; } if (dec->fe == NULL) { printk("dvb-ttusb-dec: A frontend driver was not found for device %04x/%04x\n", le16_to_cpu(dec->udev->descriptor.idVendor), le16_to_cpu(dec->udev->descriptor.idProduct)); } else { if (dvb_register_frontend(&dec->adapter, dec->fe)) { printk("budget-ci: Frontend registration failed!\n"); if (dec->fe->ops->release) dec->fe->ops->release(dec->fe); dec->fe = NULL; } } ttusb_dec_init_v_pes(dec); ttusb_dec_init_filters(dec); ttusb_dec_init_tasklet(dec); dec->active = 1; ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN); if (enable_rc) ttusb_init_rc(dec); return 0;}static void ttusb_dec_disconnect(struct usb_interface *intf){ struct ttusb_dec *dec = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); dprintk("%s\n", __FUNCTION__); if (dec->active) { ttusb_dec_exit_tasklet(dec); ttusb_dec_exit_filters(dec); if(enable_rc) ttusb_dec_exit_rc(dec); ttusb_dec_exit_usb(dec); ttusb_dec_exit_dvb(dec); } kfree(dec);}static void ttusb_dec_set_model(struct ttusb_dec *dec, enum ttusb_dec_model model){ dec->model = model; switch (model) { case TTUSB_DEC2000T: dec->model_name = "DEC2000-t"; dec->firmware_name = "dvb-ttusb-dec-2000t.fw"; break; case TTUSB_DEC2540T: dec->model_name = "DEC2540-t"; dec->firmware_name = "dvb-ttusb-dec-2540t.fw"; break; case TTUSB_DEC3000S: dec->model_name = "DEC3000-s"; dec->firmware_name = "dvb-ttusb-dec-3000s.fw"; break; }}static struct usb_device_id ttusb_dec_table[] = { {USB_DEVICE(0x0b48, 0x1006)}, /* DEC3000-s */ /*{USB_DEVICE(0x0b48, 0x1007)}, Unconfirmed */ {USB_DEVICE(0x0b48, 0x1008)}, /* DEC2000-t */ {USB_DEVICE(0x0b48, 0x1009)}, /* DEC2540-t */ {}};static struct usb_driver ttusb_dec_driver = { .name = "ttusb-dec", .probe = ttusb_dec_probe, .disconnect = ttusb_dec_disconnect, .id_table = ttusb_dec_table,};static int __init ttusb_dec_init(void){ int result; if ((result = usb_register(&ttusb_dec_driver)) < 0) { printk("%s: initialisation failed: error %d.\n", __FUNCTION__, result); return result; } return 0;}static void __exit ttusb_dec_exit(void){ usb_deregister(&ttusb_dec_driver);}module_init(ttusb_dec_init);module_exit(ttusb_dec_exit);MODULE_AUTHOR("Alex Woods <linux-dvb@giblets.org>");MODULE_DESCRIPTION(DRIVER_NAME);MODULE_LICENSE("GPL");MODULE_DEVICE_TABLE(usb, ttusb_dec_table);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -