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

📄 ttusb_dec.c

📁 V4l driver for DVB HD
💻 C
📖 第 1 页 / 共 3 页
字号:
	case TTUSB_DEC_PACKET_EMPTY:		break;	}}static void swap_bytes(u8 *b, int length){	u8 c;	length -= length % 2;	for (; length; b += 2, length -= 2) {		c = *b;		*b = *(b + 1);		*(b + 1) = c;	}}static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b,					int length){	swap_bytes(b, length);	while (length) {		switch (dec->packet_state) {		case 0:		case 1:		case 2:			if (*b++ == 0xaa)				dec->packet_state++;			else				dec->packet_state = 0;			length--;			break;		case 3:			if (*b == 0x00) {				dec->packet_state++;				dec->packet_length = 0;			} else if (*b != 0xaa) {				dec->packet_state = 0;			}			b++;			length--;			break;		case 4:			dec->packet[dec->packet_length++] = *b++;			if (dec->packet_length == 2) {				if (dec->packet[0] == 'A' &&				    dec->packet[1] == 'V') {					dec->packet_type =						TTUSB_DEC_PACKET_PVA;					dec->packet_state++;				} else if (dec->packet[0] == 'S') {					dec->packet_type =						TTUSB_DEC_PACKET_SECTION;					dec->packet_state++;				} else if (dec->packet[0] == 0x00) {					dec->packet_type =						TTUSB_DEC_PACKET_EMPTY;					dec->packet_payload_length = 2;					dec->packet_state = 7;				} else {					printk("%s: unknown packet type: "					       "%02x%02x\n", __FUNCTION__,					       dec->packet[0], dec->packet[1]);					dec->packet_state = 0;				}			}			length--;			break;		case 5:			dec->packet[dec->packet_length++] = *b++;			if (dec->packet_type == TTUSB_DEC_PACKET_PVA &&			    dec->packet_length == 8) {				dec->packet_state++;				dec->packet_payload_length = 8 +					(dec->packet[6] << 8) +					dec->packet[7];			} else if (dec->packet_type ==					TTUSB_DEC_PACKET_SECTION &&				   dec->packet_length == 5) {				dec->packet_state++;				dec->packet_payload_length = 5 +					((dec->packet[3] & 0x0f) << 8) +					dec->packet[4];			}			length--;			break;		case 6: {			int remainder = dec->packet_payload_length -					dec->packet_length;			if (length >= remainder) {				memcpy(dec->packet + dec->packet_length,				       b, remainder);				dec->packet_length += remainder;				b += remainder;				length -= remainder;				dec->packet_state++;			} 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);	}}static void ttusb_dec_process_urb(struct urb *urb, struct pt_regs *ptregs){	struct ttusb_dec *dec = urb->context;	if (!urb->status) {		int i;		for (i = 0; i < FRAMES_PER_ISO_BUF; i++) {			struct usb_iso_packet_descriptor *d;			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 (dec->iso_stream_count)		usb_submit_urb(urb, GFP_ATOMIC);}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;		urb->transfer_flags = URB_ISO_ASAP;		urb->interval = 1;		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 (mutex_lock_interruptible(&dec->iso_mutex))		return;	dec->iso_stream_count--;	if (!dec->iso_stream_count) {		for (i = 0; i < ISO_BUF_COUNT; i++)			usb_kill_urb(dec->iso_urb[i]);	}	mutex_unlock(&dec->iso_mutex);}/* 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, 8);			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 (mutex_lock_interruptible(&dec->iso_mutex))		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 ((result = usb_submit_urb(dec->iso_urb[i],						     GFP_ATOMIC))) {				printk("%s: failed urb submission %d: "				       "error %d\n", __FUNCTION__, i, result);				while (i) {					usb_kill_urb(dec->iso_urb[i - 1]);					i--;				}				mutex_unlock(&dec->iso_mutex);				return result;			}		}	}	dec->iso_stream_count++;	mutex_unlock(&dec->iso_mutex);	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(not supported)\n");		return -ENOSYS;	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(not supported)\n");		return -ENOSYS;	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,	       ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT));	for (i = 0; i < ISO_BUF_COUNT; i++) {		struct urb *urb;		if (!(urb = usb_alloc_urb(FRAMES_PER_ISO_BUF, GFP_ATOMIC))) {			ttusb_dec_free_iso_urbs(dec);			return -ENOMEM;		}		dec->iso_urb[i] = urb;	}	ttusb_dec_setup_urbs(dec);	return 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -