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

📄 ttusb_dec.c

📁 linux_dvb的驱动程序:linuxtv-dvb-1.1.1.rar
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * TTUSB DEC Driver * * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org> * * 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 <asm/semaphore.h>#include <linux/list.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/slab.h>#include <linux/spinlock.h>#include <linux/usb.h>#include <linux/version.h>#include <linux/interrupt.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)#include <linux/firmware.h>#endif#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE)#include <linux/crc32.h>#else#warning "CRC checking of firmware not available"#endif#include <linux/init.h>#include "dmxdev.h"#include "dvb_demux.h"#include "dvb_i2c.h"#include "dvb_filter.h"#include "dvb_frontend.h"#include "dvb_net.h"static int debug = 0;static int output_pva = 0;#define dprintk	if (debug) printk#define DRIVER_NAME		"TechnoTrend/Hauppauge DEC USB"#define COMMAND_PIPE		0x03#define RESULT_PIPE		0x84#define IN_PIPE			0x88#define OUT_PIPE		0x07#define COMMAND_PACKET_SIZE	0x3c#define ARM_PACKET_SIZE		0x1000#define ISO_BUF_COUNT		0x04#define FRAMES_PER_ISO_BUF	0x04#define ISO_FRAME_SIZE		0x03FF#define	MAX_PVA_LENGTH		6144#define LOF_HI			10600000#define LOF_LO			9750000enum 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_i2c_bus		i2c_bus;	struct dvb_net			dvb_net;	struct dvb_frontend_info	*frontend_info;	int (*frontend_ioctl) (struct dvb_frontend *, unsigned int, void *);	u16			pid[DMX_PES_OTHER];	int			hi_band;	int			voltage;	/* 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;	enum ttusb_dec_interface	interface;	struct semaphore		usb_sem;	void			*iso_buffer;	dma_addr_t		iso_dma_handle;	struct urb		*iso_urb[ISO_BUF_COUNT];	int			iso_stream_count;	struct semaphore	iso_sem;	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;	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 struct dvb_frontend_info dec2000t_frontend_info = {	.name			= "TechnoTrend/Hauppauge DEC2000-t Frontend",	.type			= FE_OFDM,	.frequency_min		= 51000000,	.frequency_max		= 858000000,	.frequency_stepsize	= 62500,	.caps =	FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |		FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |		FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |		FE_CAN_HIERARCHY_AUTO,};static struct dvb_frontend_info dec3000s_frontend_info = {	.name			= "TechnoTrend/Hauppauge DEC3000-s Frontend",	.type			= FE_QPSK,	.frequency_min		= 950000,	.frequency_max		= 2150000,	.frequency_stepsize	= 125,	.caps =	FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |		FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |		FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |		FE_CAN_HIERARCHY_AUTO,};static void ttusb_dec_set_model(struct ttusb_dec *dec,				enum ttusb_dec_model model);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;	u8 *c;	dprintk("%s\n", __FUNCTION__);	b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL);	if (!b)		return -ENOMEM;	c = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL);	if (!c) {		kfree(b);		return -ENOMEM;	}	if ((result = down_interruptible(&dec->usb_sem))) {		kfree(b);		kfree(c);		printk("%s: Failed to down usb semaphore.\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, HZ);	if (result) {		printk("%s: command bulk message failed: error %d\n",		       __FUNCTION__, result);		up(&dec->usb_sem);		kfree(b);		kfree(c);		return result;	}	result = usb_bulk_msg(dec->udev, dec->result_pipe, c,			      COMMAND_PACKET_SIZE + 4, &actual_len, HZ);	if (result) {		printk("%s: result bulk message failed: error %d\n",		       __FUNCTION__, result);		up(&dec->usb_sem);		kfree(b);		kfree(c);		return result;	} else {		if (debug) {			printk("%s: result: ", __FUNCTION__);			for (i = 0; i < actual_len; i++)				printk("0x%02X ", c[i]);			printk("\n");		}		if (result_length)			*result_length = c[3];		if (cmd_result && c[3] > 0)			memcpy(cmd_result, &c[4], c[3]);		up(&dec->usb_sem);		kfree(b);		kfree(c);		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 = (struct ttusb_dec *)priv;	dec->audio_filter->feed->cb.ts(data, 188, 0, 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 = (struct ttusb_dec *)priv;	dec->video_filter->feed->cb.ts(data, 188, 0, 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, 0, 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, 0, 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;	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++;

⌨️ 快捷键说明

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