📄 ttusb_dec.c
字号:
} else { memcpy(&dec->packet[dec->packet_length], b, length); dec->packet_length += length; length = 0; } break; } case 7: { int tail = 4; dec->packet[dec->packet_length++] = *b++; if (dec->packet_type == TTUSB_DEC_PACKET_SECTION && dec->packet_payload_length % 2) tail++; if (dec->packet_length == dec->packet_payload_length + tail) { ttusb_dec_process_packet(dec); dec->packet_state = 0; } length--; break; } default: printk("%s: illegal packet state encountered.\n", __FUNCTION__); dec->packet_state = 0; } }}static void ttusb_dec_process_urb_frame_list(unsigned long data){ struct ttusb_dec *dec = (struct ttusb_dec *)data; struct list_head *item; struct urb_frame *frame; unsigned long flags; while (1) { spin_lock_irqsave(&dec->urb_frame_list_lock, flags); if ((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); } else { spin_unlock_irqrestore(&dec->urb_frame_list_lock, flags); return; } spin_unlock_irqrestore(&dec->urb_frame_list_lock, flags); ttusb_dec_process_urb_frame(dec, frame->data, frame->length); kfree(frame); }}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)static void ttusb_dec_process_urb(struct urb *urb)#elsestatic void ttusb_dec_process_urb(struct urb *urb, struct pt_regs *ptregs)#endif{ struct ttusb_dec *dec = urb->context; if (!urb->status) { int i; for (i = 0; i < FRAMES_PER_ISO_BUF; i++) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20) piso_packet_descriptor_t d;#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) struct iso_packet_descriptor *d;#else struct usb_iso_packet_descriptor *d;#endif u8 *b; int length; struct urb_frame *frame; d = &urb->iso_frame_desc[i]; b = urb->transfer_buffer + d->offset; length = d->actual_length; if ((frame = kmalloc(sizeof(struct urb_frame), GFP_ATOMIC))) { unsigned long flags; memcpy(frame->data, b, length); frame->length = length; spin_lock_irqsave(&dec->urb_frame_list_lock, flags); list_add_tail(&frame->urb_frame_list, &dec->urb_frame_list); spin_unlock_irqrestore(&dec->urb_frame_list_lock, flags); tasklet_schedule(&dec->urb_tasklet); } } } else { /* -ENOENT is expected when unlinking urbs */ if (urb->status != -ENOENT) dprintk("%s: urb error: %d\n", __FUNCTION__, urb->status); }#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) if (dec->iso_stream_count) usb_submit_urb(urb, GFP_ATOMIC);#endif}static void ttusb_dec_setup_urbs(struct ttusb_dec *dec){ int i, j, buffer_offset = 0; dprintk("%s\n", __FUNCTION__); for (i = 0; i < ISO_BUF_COUNT; i++) { int frame_offset = 0; struct urb *urb = dec->iso_urb[i]; urb->dev = dec->udev; urb->context = dec; urb->complete = ttusb_dec_process_urb; urb->pipe = dec->in_pipe;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) urb->transfer_flags = URB_ISO_ASAP; urb->interval = 1;#else urb->transfer_flags = USB_ISO_ASAP;#endif urb->number_of_packets = FRAMES_PER_ISO_BUF; urb->transfer_buffer_length = ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; urb->transfer_buffer = dec->iso_buffer + buffer_offset; buffer_offset += ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF; for (j = 0; j < FRAMES_PER_ISO_BUF; j++) { urb->iso_frame_desc[j].offset = frame_offset; urb->iso_frame_desc[j].length = ISO_FRAME_SIZE; frame_offset += ISO_FRAME_SIZE; } }}static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec){ int i; dprintk("%s\n", __FUNCTION__); if (down_interruptible(&dec->iso_sem)) return; dec->iso_stream_count--; if (!dec->iso_stream_count) { for (i = 0; i < ISO_BUF_COUNT; i++) usb_unlink_urb(dec->iso_urb[i]); } up(&dec->iso_sem);}/* Setting the interface of the DEC tends to take down the USB communications * for a short period, so it's important not to call this function just before * trying to talk to it. */static int ttusb_dec_set_interface(struct ttusb_dec *dec, enum ttusb_dec_interface interface){ int result = 0; u8 b[] = { 0x05 }; if (interface != dec->interface) { switch (interface) { case TTUSB_DEC_INTERFACE_INITIAL: result = usb_set_interface(dec->udev, 0, 0); break; case TTUSB_DEC_INTERFACE_IN: result = ttusb_dec_send_command(dec, 0x80, sizeof(b), b, NULL, NULL); if (result) return result; result = usb_set_interface(dec->udev, 0, 7); break; case TTUSB_DEC_INTERFACE_OUT: result = usb_set_interface(dec->udev, 0, 1); break; } if (result) return result; dec->interface = interface; } return 0;}static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec){ int i, result; dprintk("%s\n", __FUNCTION__); if (down_interruptible(&dec->iso_sem)) return -EAGAIN; if (!dec->iso_stream_count) { ttusb_dec_setup_urbs(dec); dec->packet_state = 0; dec->v_pes_postbytes = 0; dec->next_packet_id = 0; for (i = 0; i < ISO_BUF_COUNT; i++) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) if ((result = usb_submit_urb(dec->iso_urb[i], GFP_ATOMIC))) {#else if ((result = usb_submit_urb(dec->iso_urb[i]))) {#endif printk("%s: failed urb submission %d: " "error %d\n", __FUNCTION__, i, result); while (i) { usb_unlink_urb(dec->iso_urb[i - 1]); i--; } up(&dec->iso_sem); return result; } } } dec->iso_stream_count++; up(&dec->iso_sem); return 0;}static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed){ struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct ttusb_dec *dec = dvbdmx->priv; u8 b0[] = { 0x05 }; int result = 0; dprintk("%s\n", __FUNCTION__); dprintk(" ts_type:"); if (dvbdmxfeed->ts_type & TS_DECODER) dprintk(" TS_DECODER"); if (dvbdmxfeed->ts_type & TS_PACKET) dprintk(" TS_PACKET"); if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) dprintk(" TS_PAYLOAD_ONLY"); dprintk("\n"); switch (dvbdmxfeed->pes_type) { case DMX_TS_PES_VIDEO: dprintk(" pes_type: DMX_TS_PES_VIDEO\n"); dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; dec->pid[DMX_PES_VIDEO] = dvbdmxfeed->pid; dec->video_filter = dvbdmxfeed->filter; ttusb_dec_set_pids(dec); break; case DMX_TS_PES_AUDIO: dprintk(" pes_type: DMX_TS_PES_AUDIO\n"); dec->pid[DMX_PES_AUDIO] = dvbdmxfeed->pid; dec->audio_filter = dvbdmxfeed->filter; ttusb_dec_set_pids(dec); break; case DMX_TS_PES_TELETEXT: dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid; dprintk(" pes_type: DMX_TS_PES_TELETEXT\n"); break; case DMX_TS_PES_PCR: dprintk(" pes_type: DMX_TS_PES_PCR\n"); dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; ttusb_dec_set_pids(dec); break; case DMX_TS_PES_OTHER: dprintk(" pes_type: DMX_TS_PES_OTHER\n"); break; default: dprintk(" pes_type: unknown (%d)\n", dvbdmxfeed->pes_type); return -EINVAL; } result = ttusb_dec_send_command(dec, 0x80, sizeof(b0), b0, NULL, NULL); if (result) return result; dec->pva_stream_count++; return ttusb_dec_start_iso_xfer(dec);}static int ttusb_dec_start_sec_feed(struct dvb_demux_feed *dvbdmxfeed){ struct ttusb_dec *dec = dvbdmxfeed->demux->priv; u8 b0[] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; u16 pid; u8 c[COMMAND_PACKET_SIZE]; int c_length; int result; struct filter_info *finfo; unsigned long flags; u8 x = 1; dprintk("%s\n", __FUNCTION__); pid = htons(dvbdmxfeed->pid); memcpy(&b0[0], &pid, 2); memcpy(&b0[4], &x, 1); memcpy(&b0[5], &dvbdmxfeed->filter->filter.filter_value[0], 1); result = ttusb_dec_send_command(dec, 0x60, sizeof(b0), b0, &c_length, c); if (!result) { if (c_length == 2) { if (!(finfo = kmalloc(sizeof(struct filter_info), GFP_ATOMIC))) return -ENOMEM; finfo->stream_id = c[1]; finfo->filter = dvbdmxfeed->filter; spin_lock_irqsave(&dec->filter_info_list_lock, flags); list_add_tail(&finfo->filter_info_list, &dec->filter_info_list); spin_unlock_irqrestore(&dec->filter_info_list_lock, flags); dvbdmxfeed->priv = finfo; dec->filter_stream_count++; return ttusb_dec_start_iso_xfer(dec); } return -EAGAIN; } else return result;}static int ttusb_dec_start_feed(struct dvb_demux_feed *dvbdmxfeed){ struct dvb_demux *dvbdmx = dvbdmxfeed->demux; dprintk("%s\n", __FUNCTION__); if (!dvbdmx->dmx.frontend) return -EINVAL; dprintk(" pid: 0x%04X\n", dvbdmxfeed->pid); switch (dvbdmxfeed->type) { case DMX_TYPE_TS: return ttusb_dec_start_ts_feed(dvbdmxfeed); break; case DMX_TYPE_SEC: return ttusb_dec_start_sec_feed(dvbdmxfeed); break; default: dprintk(" type: unknown (%d)\n", dvbdmxfeed->type); return -EINVAL; }}static int ttusb_dec_stop_ts_feed(struct dvb_demux_feed *dvbdmxfeed){ struct ttusb_dec *dec = dvbdmxfeed->demux->priv; u8 b0[] = { 0x00 }; ttusb_dec_send_command(dec, 0x81, sizeof(b0), b0, NULL, NULL); dec->pva_stream_count--; ttusb_dec_stop_iso_xfer(dec); return 0;}static int ttusb_dec_stop_sec_feed(struct dvb_demux_feed *dvbdmxfeed){ struct ttusb_dec *dec = dvbdmxfeed->demux->priv; u8 b0[] = { 0x00, 0x00 }; struct filter_info *finfo = (struct filter_info *)dvbdmxfeed->priv; unsigned long flags; b0[1] = finfo->stream_id; spin_lock_irqsave(&dec->filter_info_list_lock, flags); list_del(&finfo->filter_info_list); spin_unlock_irqrestore(&dec->filter_info_list_lock, flags); kfree(finfo); ttusb_dec_send_command(dec, 0x62, sizeof(b0), b0, NULL, NULL); dec->filter_stream_count--; ttusb_dec_stop_iso_xfer(dec); return 0;}static int ttusb_dec_stop_feed(struct dvb_demux_feed *dvbdmxfeed){ dprintk("%s\n", __FUNCTION__); switch (dvbdmxfeed->type) { case DMX_TYPE_TS: return ttusb_dec_stop_ts_feed(dvbdmxfeed); break; case DMX_TYPE_SEC: return ttusb_dec_stop_sec_feed(dvbdmxfeed); break; } return 0;}static void ttusb_dec_free_iso_urbs(struct ttusb_dec *dec){ int i; dprintk("%s\n", __FUNCTION__); for (i = 0; i < ISO_BUF_COUNT; i++) if (dec->iso_urb[i]) usb_free_urb(dec->iso_urb[i]); pci_free_consistent(NULL, ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT), dec->iso_buffer, dec->iso_dma_handle);}static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec){ int i; dprintk("%s\n", __FUNCTION__); dec->iso_buffer = pci_alloc_consistent(NULL, ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT), &dec->iso_dma_handle); memset(dec->iso_buffer, 0, sizeof(ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT))); for (i = 0; i < ISO_BUF_COUNT; i++) { struct urb *urb;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) {#else if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF))) {#endif ttusb_dec_free_iso_urbs(dec); return -ENOMEM; } dec->iso_urb[i] = urb; } ttusb_dec_setup_urbs(dec);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) for (i = 0; i < ISO_BUF_COUNT; i++) { int next = (i + 1) % ISO_BUF_COUNT; dec->iso_urb[i]->next = dec->iso_urb[next]; }#endif return 0;}static void ttusb_dec_init_tasklet(struct ttusb_dec *dec){ dec->urb_frame_list_lock = SPIN_LOCK_UNLOCKED; INIT_LIST_HEAD(&dec->urb_frame_list); tasklet_init(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list, (unsigned long)dec);}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 void ttusb_dec_init_usb(struct ttusb_dec *dec){ dprintk("%s\n", __FUNCTION__); sema_init(&dec->usb_sem, 1); sema_init(&dec->iso_sem, 1); 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); ttusb_dec_alloc_iso_urbs(dec);}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)#include "dsp_dec2000t.h"#include "dsp_dec2540t.h"#include "dsp_dec3000s.h"#endifstatic 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;#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE) u32 crc32_csum, crc32_check, tmp;#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) const struct firmware *fw_entry = NULL;#endif dprintk("%s\n", __FUNCTION__);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) 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;#else switch (dec->model) { case TTUSB_DEC2000T: firmware = &dsp_dec2000t[0]; firmware_size = sizeof(dsp_dec2000t); break; case TTUSB_DEC2540T: firmware = &dsp_dec2540t[0]; firmware_size = sizeof(dsp_dec2540t); break; case TTUSB_DEC3000S: firmware = &dsp_dec3000s[0]; firmware_size = sizeof(dsp_dec3000s); break; }#endif if (firmware_size < 60) { printk("%s: firmware size too small for DSP code (%u < 60).\n", __FUNCTION__, firmware_size); 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. */#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE) 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); return -1; }#endif 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) return result; trans_count = 0; j = 0; b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL); if (b == NULL) 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -