⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ttusb_dec.c

📁 linux_dvb的驱动程序:linuxtv-dvb-1.1.1.rar
💻 C
📖 第 1 页 / 共 3 页
字号:
			} 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 + -