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

📄 ttusb_dec.c

📁 V4l driver for DVB HD
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * TTUSB DEC Driver * * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org> * IR support by Peter Beutner <p.beutner@gmx.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "compat.h"#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)#include <linux/mutex.h>#endif#include <linux/list.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/pci.h>#include <linux/slab.h>#include <linux/spinlock.h>#include <linux/usb.h>#include <linux/interrupt.h>#include <linux/firmware.h>#include <linux/crc32.h>#include <linux/init.h>#include <linux/input.h>#include "dmxdev.h"#include "dvb_demux.h"#include "dvb_filter.h"#include "dvb_frontend.h"#include "dvb_net.h"#include "ttusbdecfe.h"static int debug;static int output_pva;static int enable_rc;module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");module_param(output_pva, int, 0444);MODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)");module_param(enable_rc, int, 0644);MODULE_PARM_DESC(enable_rc, "Turn on/off IR remote control(default: off)");#define dprintk	if (debug) printk#define DRIVER_NAME		"TechnoTrend/Hauppauge DEC USB"#define COMMAND_PIPE		0x03#define RESULT_PIPE		0x04#define IN_PIPE			0x08#define OUT_PIPE		0x07#define IRQ_PIPE		0x0A#define COMMAND_PACKET_SIZE	0x3c#define ARM_PACKET_SIZE		0x1000#define IRQ_PACKET_SIZE		0x8#define ISO_BUF_COUNT		0x04#define FRAMES_PER_ISO_BUF	0x04#define ISO_FRAME_SIZE		0x0380#define	MAX_PVA_LENGTH		6144enum ttusb_dec_model {	TTUSB_DEC2000T,	TTUSB_DEC2540T,	TTUSB_DEC3000S};enum ttusb_dec_packet_type {	TTUSB_DEC_PACKET_PVA,	TTUSB_DEC_PACKET_SECTION,	TTUSB_DEC_PACKET_EMPTY};enum ttusb_dec_interface {	TTUSB_DEC_INTERFACE_INITIAL,	TTUSB_DEC_INTERFACE_IN,	TTUSB_DEC_INTERFACE_OUT};struct ttusb_dec {	enum ttusb_dec_model		model;	char				*model_name;	char				*firmware_name;	int				can_playback;	/* DVB bits */	struct dvb_adapter		adapter;	struct dmxdev			dmxdev;	struct dvb_demux		demux;	struct dmx_frontend		frontend;	struct dvb_net			dvb_net;	struct dvb_frontend*		fe;	u16			pid[DMX_PES_OTHER];	/* USB bits */	struct usb_device		*udev;	u8				trans_count;	unsigned int			command_pipe;	unsigned int			result_pipe;	unsigned int			in_pipe;	unsigned int			out_pipe;	unsigned int			irq_pipe;	enum ttusb_dec_interface	interface;	struct mutex			usb_mutex;	void			*irq_buffer;	struct urb		*irq_urb;	dma_addr_t		irq_dma_handle;	void			*iso_buffer;	dma_addr_t		iso_dma_handle;	struct urb		*iso_urb[ISO_BUF_COUNT];	int			iso_stream_count;	struct mutex		iso_mutex;	u8				packet[MAX_PVA_LENGTH + 4];	enum ttusb_dec_packet_type	packet_type;	int				packet_state;	int				packet_length;	int				packet_payload_length;	u16				next_packet_id;	int				pva_stream_count;	int				filter_stream_count;	struct dvb_filter_pes2ts	a_pes2ts;	struct dvb_filter_pes2ts	v_pes2ts;	u8			v_pes[16 + MAX_PVA_LENGTH];	int			v_pes_length;	int			v_pes_postbytes;	struct list_head	urb_frame_list;	struct tasklet_struct	urb_tasklet;	spinlock_t		urb_frame_list_lock;	struct dvb_demux_filter	*audio_filter;	struct dvb_demux_filter	*video_filter;	struct list_head	filter_info_list;	spinlock_t		filter_info_list_lock;	struct input_dev	*rc_input_dev;	char			rc_phys[64];	int			active; /* Loaded successfully */};struct urb_frame {	u8			data[ISO_FRAME_SIZE];	int			length;	struct list_head	urb_frame_list;};struct filter_info {	u8			stream_id;	struct dvb_demux_filter	*filter;	struct list_head	filter_info_list;};static u16 rc_keys[] = {	KEY_POWER,	KEY_MUTE,	KEY_1,	KEY_2,	KEY_3,	KEY_4,	KEY_5,	KEY_6,	KEY_7,	KEY_8,	KEY_9,	KEY_0,	KEY_CHANNELUP,	KEY_VOLUMEDOWN,	KEY_OK,	KEY_VOLUMEUP,	KEY_CHANNELDOWN,	KEY_PREVIOUS,	KEY_ESC,	KEY_RED,	KEY_GREEN,	KEY_YELLOW,	KEY_BLUE,	KEY_OPTION,	KEY_M,	KEY_RADIO};static void ttusb_dec_set_model(struct ttusb_dec *dec,				enum ttusb_dec_model model);static void ttusb_dec_handle_irq( struct urb *urb, struct pt_regs *regs){	struct ttusb_dec * dec = urb->context;	char *buffer = dec->irq_buffer;	int retval;	switch(urb->status) {		case 0: /*success*/			break;		case -ECONNRESET:		case -ENOENT:		case -ESHUTDOWN:		case -ETIMEDOUT:			/* this urb is dead, cleanup */			dprintk("%s:urb shutting down with status: %d\n",					__FUNCTION__, urb->status);			return;		default:			dprintk("%s:nonzero status received: %d\n",					__FUNCTION__,urb->status);			goto exit;	}	if( (buffer[0] == 0x1) && (buffer[2] == 0x15) )  {		/* IR - Event */		/* this is an fact a bit too simple implementation;		 * the box also reports a keyrepeat signal		 * (with buffer[3] == 0x40) in an intervall of ~100ms.		 * But to handle this correctly we had to imlemenent some		 * kind of timer which signals a 'key up' event if no		 * keyrepeat signal is recieved for lets say 200ms.		 * this should/could be added later ...		 * for now lets report each signal as a key down and up*/		dprintk("%s:rc signal:%d\n", __FUNCTION__, buffer[4]);		input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1);		input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0);		input_sync(dec->rc_input_dev);	}exit:	retval = usb_submit_urb(urb, GFP_ATOMIC);	if(retval)		printk("%s - usb_commit_urb failed with result: %d\n",			__FUNCTION__, retval);}static u16 crc16(u16 crc, const u8 *buf, size_t len){	u16 tmp;	while (len--) {		crc ^= *buf++;		crc ^= (u8)crc >> 4;		tmp = (u8)crc;		crc ^= (tmp ^ (tmp << 1)) << 4;	}	return crc;}static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command,				  int param_length, const u8 params[],				  int *result_length, u8 cmd_result[]){	int result, actual_len, i;	u8 *b;	dprintk("%s\n", __FUNCTION__);	b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL);	if (!b)		return -ENOMEM;	if ((result = mutex_lock_interruptible(&dec->usb_mutex))) {		kfree(b);		printk("%s: Failed to lock usb mutex.\n", __FUNCTION__);		return result;	}	b[0] = 0xaa;	b[1] = ++dec->trans_count;	b[2] = command;	b[3] = param_length;	if (params)		memcpy(&b[4], params, param_length);	if (debug) {		printk("%s: command: ", __FUNCTION__);		for (i = 0; i < param_length + 4; i++)			printk("0x%02X ", b[i]);		printk("\n");	}	result = usb_bulk_msg(dec->udev, dec->command_pipe, b,			      COMMAND_PACKET_SIZE + 4, &actual_len, 1000);	if (result) {		printk("%s: command bulk message failed: error %d\n",		       __FUNCTION__, result);		mutex_unlock(&dec->usb_mutex);		kfree(b);		return result;	}	result = usb_bulk_msg(dec->udev, dec->result_pipe, b,			      COMMAND_PACKET_SIZE + 4, &actual_len, 1000);	if (result) {		printk("%s: result bulk message failed: error %d\n",		       __FUNCTION__, result);		mutex_unlock(&dec->usb_mutex);		kfree(b);		return result;	} else {		if (debug) {			printk("%s: result: ", __FUNCTION__);			for (i = 0; i < actual_len; i++)				printk("0x%02X ", b[i]);			printk("\n");		}		if (result_length)			*result_length = b[3];		if (cmd_result && b[3] > 0)			memcpy(cmd_result, &b[4], b[3]);		mutex_unlock(&dec->usb_mutex);		kfree(b);		return 0;	}}static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode,				    unsigned int *model, unsigned int *version){	u8 c[COMMAND_PACKET_SIZE];	int c_length;	int result;	unsigned int tmp;	dprintk("%s\n", __FUNCTION__);	result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c);	if (result)		return result;	if (c_length >= 0x0c) {		if (mode != NULL) {			memcpy(&tmp, c, 4);			*mode = ntohl(tmp);		}		if (model != NULL) {			memcpy(&tmp, &c[4], 4);			*model = ntohl(tmp);		}		if (version != NULL) {			memcpy(&tmp, &c[8], 4);			*version = ntohl(tmp);		}		return 0;	} else {		return -1;	}}static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data){	struct ttusb_dec *dec = priv;	dec->audio_filter->feed->cb.ts(data, 188, NULL, 0,				       &dec->audio_filter->feed->feed.ts,				       DMX_OK);	return 0;}static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data){	struct ttusb_dec *dec = priv;	dec->video_filter->feed->cb.ts(data, 188, NULL, 0,				       &dec->video_filter->feed->feed.ts,				       DMX_OK);	return 0;}static void ttusb_dec_set_pids(struct ttusb_dec *dec){	u8 b[] = { 0x00, 0x00, 0x00, 0x00,		   0x00, 0x00, 0xff, 0xff,		   0xff, 0xff, 0xff, 0xff };	u16 pcr = htons(dec->pid[DMX_PES_PCR]);	u16 audio = htons(dec->pid[DMX_PES_AUDIO]);	u16 video = htons(dec->pid[DMX_PES_VIDEO]);	dprintk("%s\n", __FUNCTION__);	memcpy(&b[0], &pcr, 2);	memcpy(&b[2], &audio, 2);	memcpy(&b[4], &video, 2);	ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL);	dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO],			       ttusb_dec_audio_pes2ts_cb, dec);	dvb_filter_pes2ts_init(&dec->v_pes2ts, dec->pid[DMX_PES_VIDEO],			       ttusb_dec_video_pes2ts_cb, dec);	dec->v_pes_length = 0;	dec->v_pes_postbytes = 0;}static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length){	if (length < 8) {		printk("%s: packet too short - discarding\n", __FUNCTION__);		return;	}	if (length > 8 + MAX_PVA_LENGTH) {		printk("%s: packet too long - discarding\n", __FUNCTION__);		return;	}	switch (pva[2]) {	case 0x01: {		/* VideoStream */		int prebytes = pva[5] & 0x03;		int postbytes = (pva[5] & 0x0c) >> 2;		u16 v_pes_payload_length;		if (output_pva) {			dec->video_filter->feed->cb.ts(pva, length, NULL, 0,				&dec->video_filter->feed->feed.ts, DMX_OK);			return;		}		if (dec->v_pes_postbytes > 0 &&		    dec->v_pes_postbytes == prebytes) {			memcpy(&dec->v_pes[dec->v_pes_length],			       &pva[12], prebytes);			dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,					  dec->v_pes_length + prebytes, 1);		}		if (pva[5] & 0x10) {			dec->v_pes[7] = 0x80;			dec->v_pes[8] = 0x05;			dec->v_pes[9] = 0x21 | ((pva[8] & 0xc0) >> 5);			dec->v_pes[10] = ((pva[8] & 0x3f) << 2) |					 ((pva[9] & 0xc0) >> 6);			dec->v_pes[11] = 0x01 |					 ((pva[9] & 0x3f) << 2) |					 ((pva[10] & 0x80) >> 6);			dec->v_pes[12] = ((pva[10] & 0x7f) << 1) |					 ((pva[11] & 0xc0) >> 7);			dec->v_pes[13] = 0x01 | ((pva[11] & 0x7f) << 1);			memcpy(&dec->v_pes[14], &pva[12 + prebytes],			       length - 12 - prebytes);			dec->v_pes_length = 14 + length - 12 - prebytes;		} else {			dec->v_pes[7] = 0x00;			dec->v_pes[8] = 0x00;			memcpy(&dec->v_pes[9], &pva[8], length - 8);			dec->v_pes_length = 9 + length - 8;		}		dec->v_pes_postbytes = postbytes;		if (dec->v_pes[9 + dec->v_pes[8]] == 0x00 &&		    dec->v_pes[10 + dec->v_pes[8]] == 0x00 &&		    dec->v_pes[11 + dec->v_pes[8]] == 0x01)			dec->v_pes[6] = 0x84;		else			dec->v_pes[6] = 0x80;		v_pes_payload_length = htons(dec->v_pes_length - 6 +					     postbytes);		memcpy(&dec->v_pes[4], &v_pes_payload_length, 2);		if (postbytes == 0)			dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes,					  dec->v_pes_length, 1);		break;	}	case 0x02:		/* MainAudioStream */		if (output_pva) {			dec->audio_filter->feed->cb.ts(pva, length, NULL, 0,				&dec->audio_filter->feed->feed.ts, DMX_OK);			return;		}		dvb_filter_pes2ts(&dec->a_pes2ts, &pva[8], length - 8,				  pva[5] & 0x10);		break;	default:		printk("%s: unknown PVA type: %02x.\n", __FUNCTION__,		       pva[2]);		break;	}}static void ttusb_dec_process_filter(struct ttusb_dec *dec, u8 *packet,				     int length){	struct list_head *item;	struct filter_info *finfo;	struct dvb_demux_filter *filter = NULL;	unsigned long flags;	u8 sid;	sid = packet[1];	spin_lock_irqsave(&dec->filter_info_list_lock, flags);	for (item = dec->filter_info_list.next; item != &dec->filter_info_list;	     item = item->next) {		finfo = list_entry(item, struct filter_info, filter_info_list);		if (finfo->stream_id == sid) {			filter = finfo->filter;			break;		}	}	spin_unlock_irqrestore(&dec->filter_info_list_lock, flags);	if (filter)		filter->feed->cb.sec(&packet[2], length - 2, NULL, 0,				     &filter->filter, DMX_OK);}static void ttusb_dec_process_packet(struct ttusb_dec *dec){	int i;	u16 csum = 0;	u16 packet_id;	if (dec->packet_length % 2) {		printk("%s: odd sized packet - discarding\n", __FUNCTION__);		return;	}	for (i = 0; i < dec->packet_length; i += 2)		csum ^= ((dec->packet[i] << 8) + dec->packet[i + 1]);	if (csum) {		printk("%s: checksum failed - discarding\n", __FUNCTION__);		return;	}	packet_id = dec->packet[dec->packet_length - 4] << 8;	packet_id += dec->packet[dec->packet_length - 3];	if ((packet_id != dec->next_packet_id) && dec->next_packet_id) {		printk("%s: warning: lost packets between %u and %u\n",		       __FUNCTION__, dec->next_packet_id - 1, packet_id);	}	if (packet_id == 0xffff)		dec->next_packet_id = 0x8000;	else		dec->next_packet_id = packet_id + 1;	switch (dec->packet_type) {	case TTUSB_DEC_PACKET_PVA:		if (dec->pva_stream_count)			ttusb_dec_process_pva(dec, dec->packet,					      dec->packet_payload_length);		break;	case TTUSB_DEC_PACKET_SECTION:		if (dec->filter_stream_count)			ttusb_dec_process_filter(dec, dec->packet,						 dec->packet_payload_length);		break;

⌨️ 快捷键说明

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