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

📄 ttusb_dec.c

📁 V4l driver for DVB HD
💻 C
📖 第 1 页 / 共 3 页
字号:
}static void ttusb_dec_init_tasklet(struct ttusb_dec *dec){	spin_lock_init(&dec->urb_frame_list_lock);	INIT_LIST_HEAD(&dec->urb_frame_list);	tasklet_init(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list,		     (unsigned long)dec);}static int ttusb_init_rc( struct ttusb_dec *dec){	struct input_dev *input_dev;	u8 b[] = { 0x00, 0x01 };	int i;	usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys));	strlcpy(dec->rc_phys, "/input0", sizeof(dec->rc_phys));	dec->rc_input_dev = input_dev = input_allocate_device();	if (!input_dev)		return -ENOMEM;	input_dev->name = "ttusb_dec remote control";	input_dev->phys = dec->rc_phys;	input_dev->evbit[0] = BIT(EV_KEY);	input_dev->keycodesize = sizeof(u16);	input_dev->keycodemax = 0x1a;	input_dev->keycode = rc_keys;	for (i = 0; i < ARRAY_SIZE(rc_keys); i++)		  set_bit(rc_keys[i], input_dev->keybit);	input_register_device(input_dev);	if (usb_submit_urb(dec->irq_urb, GFP_KERNEL))		printk("%s: usb_submit_urb failed\n",__FUNCTION__);	/* enable irq pipe */	ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL);	return 0;}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 int ttusb_dec_init_usb(struct ttusb_dec *dec){	dprintk("%s\n", __FUNCTION__);	mutex_init(&dec->usb_mutex);	mutex_init(&dec->iso_mutex);	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);	dec->irq_pipe = usb_rcvintpipe(dec->udev, IRQ_PIPE);	if(enable_rc) {		dec->irq_urb = usb_alloc_urb(0, GFP_KERNEL);		if(!dec->irq_urb) {			return -ENOMEM;		}		dec->irq_buffer = usb_buffer_alloc(dec->udev,IRQ_PACKET_SIZE,					SLAB_ATOMIC, &dec->irq_dma_handle);		if(!dec->irq_buffer) {			return -ENOMEM;		}		usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe,				 dec->irq_buffer, IRQ_PACKET_SIZE,				 ttusb_dec_handle_irq, dec, 1);		dec->irq_urb->transfer_dma = dec->irq_dma_handle;		dec->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;	}	return ttusb_dec_alloc_iso_urbs(dec);}static 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;	u32 crc32_csum, crc32_check, tmp;	const struct firmware *fw_entry = NULL;	dprintk("%s\n", __FUNCTION__);	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;	if (firmware_size < 60) {		printk("%s: firmware size too small for DSP code (%zu < 60).\n",			__FUNCTION__, firmware_size);		release_firmware(fw_entry);		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. */	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);		release_firmware(fw_entry);		return -1;	}	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) {		release_firmware(fw_entry);		return result;	}	trans_count = 0;	j = 0;	b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL);	if (b == NULL) {		release_firmware(fw_entry);		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;		b[j + 0] = 0xaa;		b[j + 1] = trans_count++;		b[j + 2] = 0xf0;		b[j + 3] = size;		memcpy(&b[j + 4], &firmware[i], size);		j += COMMAND_PACKET_SIZE + 4;		if (j >= ARM_PACKET_SIZE) {			result = usb_bulk_msg(dec->udev, dec->command_pipe, b,					      ARM_PACKET_SIZE, &actual_len,					      100);			j = 0;		} else if (size < COMMAND_PACKET_SIZE) {			result = usb_bulk_msg(dec->udev, dec->command_pipe, b,					      j - COMMAND_PACKET_SIZE + size,					      &actual_len, 100);		}	}	result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL);	release_firmware(fw_entry);	kfree(b);	return result;}static int ttusb_dec_init_stb(struct ttusb_dec *dec){	int result;	unsigned int mode, model, version;	dprintk("%s\n", __FUNCTION__);	result = ttusb_dec_get_stb_state(dec, &mode, &model, &version);	if (!result) {		if (!mode) {			if (version == 0xABCDEFAB)				printk(KERN_INFO "ttusb_dec: no version "				       "info in Firmware\n");			else				printk(KERN_INFO "ttusb_dec: Firmware "				       "%x.%02x%c%c\n",				       version >> 24, (version >> 16) & 0xff,				       (version >> 8) & 0xff, version & 0xff);			result = ttusb_dec_boot_dsp(dec);			if (result)				return result;			else				return 1;		} else {			/* We can't trust the USB IDs that some firmwares			   give the box */			switch (model) {			case 0x00070001:			case 0x00070008:			case 0x0007000c:				ttusb_dec_set_model(dec, TTUSB_DEC3000S);				break;			case 0x00070009:			case 0x00070013:				ttusb_dec_set_model(dec, TTUSB_DEC2000T);				break;			case 0x00070011:				ttusb_dec_set_model(dec, TTUSB_DEC2540T);				break;			default:				printk(KERN_ERR "%s: unknown model returned "				       "by firmware (%08x) - please report\n",				       __FUNCTION__, model);				return -1;				break;			}			if (version >= 0x01770000)				dec->can_playback = 1;			return 0;		}	}	else		return result;}static int ttusb_dec_init_dvb(struct ttusb_dec *dec){	int result;	dprintk("%s\n", __FUNCTION__);	if ((result = dvb_register_adapter(&dec->adapter,					   dec->model_name, THIS_MODULE, &dec->udev->dev)) < 0) {		printk("%s: dvb_register_adapter failed: error %d\n",		       __FUNCTION__, result);		return result;	}	dec->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;	dec->demux.priv = (void *)dec;	dec->demux.filternum = 31;	dec->demux.feednum = 31;	dec->demux.start_feed = ttusb_dec_start_feed;	dec->demux.stop_feed = ttusb_dec_stop_feed;	dec->demux.write_to_decoder = NULL;	if ((result = dvb_dmx_init(&dec->demux)) < 0) {		printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__,		       result);		dvb_unregister_adapter(&dec->adapter);		return result;	}	dec->dmxdev.filternum = 32;	dec->dmxdev.demux = &dec->demux.dmx;	dec->dmxdev.capabilities = 0;	if ((result = dvb_dmxdev_init(&dec->dmxdev, &dec->adapter)) < 0) {		printk("%s: dvb_dmxdev_init failed: error %d\n",		       __FUNCTION__, result);		dvb_dmx_release(&dec->demux);		dvb_unregister_adapter(&dec->adapter);		return result;	}	dec->frontend.source = DMX_FRONTEND_0;	if ((result = dec->demux.dmx.add_frontend(&dec->demux.dmx,						  &dec->frontend)) < 0) {		printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__,		       result);		dvb_dmxdev_release(&dec->dmxdev);		dvb_dmx_release(&dec->demux);		dvb_unregister_adapter(&dec->adapter);		return result;	}	if ((result = dec->demux.dmx.connect_frontend(&dec->demux.dmx,						      &dec->frontend)) < 0) {		printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__,		       result);		dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);		dvb_dmxdev_release(&dec->dmxdev);		dvb_dmx_release(&dec->demux);		dvb_unregister_adapter(&dec->adapter);		return result;	}	dvb_net_init(&dec->adapter, &dec->dvb_net, &dec->demux.dmx);	return 0;}static void ttusb_dec_exit_dvb(struct ttusb_dec *dec){	dprintk("%s\n", __FUNCTION__);	dvb_net_release(&dec->dvb_net);	dec->demux.dmx.close(&dec->demux.dmx);	dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);	dvb_dmxdev_release(&dec->dmxdev);	dvb_dmx_release(&dec->demux);	if (dec->fe) dvb_unregister_frontend(dec->fe);	dvb_unregister_adapter(&dec->adapter);}static void ttusb_dec_exit_rc(struct ttusb_dec *dec){	dprintk("%s\n", __FUNCTION__);	/* we have to check whether the irq URB is already submitted.	  * As the irq is submitted after the interface is changed,	  * this is the best method i figured out.	  * Any others?*/	if (dec->interface == TTUSB_DEC_INTERFACE_IN)		usb_kill_urb(dec->irq_urb);	usb_free_urb(dec->irq_urb);	usb_buffer_free(dec->udev,IRQ_PACKET_SIZE,			   dec->irq_buffer, dec->irq_dma_handle);	if (dec->rc_input_dev) {		input_unregister_device(dec->rc_input_dev);		dec->rc_input_dev = NULL;	}}static void ttusb_dec_exit_usb(struct ttusb_dec *dec){	int i;	dprintk("%s\n", __FUNCTION__);	dec->iso_stream_count = 0;	for (i = 0; i < ISO_BUF_COUNT; i++)		usb_kill_urb(dec->iso_urb[i]);	ttusb_dec_free_iso_urbs(dec);}static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec){	struct list_head *item;	struct urb_frame *frame;	tasklet_kill(&dec->urb_tasklet);	while ((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);		kfree(frame);	}}static void ttusb_dec_init_filters(struct ttusb_dec *dec){	INIT_LIST_HEAD(&dec->filter_info_list);	spin_lock_init(&dec->filter_info_list_lock);}static void ttusb_dec_exit_filters(struct ttusb_dec *dec){	struct list_head *item;	struct filter_info *finfo;	while ((item = dec->filter_info_list.next) != &dec->filter_info_list) {		finfo = list_entry(item, struct filter_info, filter_info_list);		list_del(&finfo->filter_info_list);		kfree(finfo);	}}static int fe_send_command(struct dvb_frontend* fe, const u8 command,			   int param_length, const u8 params[],			   int *result_length, u8 cmd_result[]){	struct ttusb_dec* dec = fe->dvb->priv;	return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result);}static struct ttusbdecfe_config fe_config = {	.send_command = fe_send_command};static int ttusb_dec_probe(struct usb_interface *intf,			   const struct usb_device_id *id){	struct usb_device *udev;	struct ttusb_dec *dec;	dprintk("%s\n", __FUNCTION__);	udev = interface_to_usbdev(intf);	if (!(dec = kzalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) {		printk("%s: couldn't allocate memory.\n", __FUNCTION__);		return -ENOMEM;	}	usb_set_intfdata(intf, (void *)dec);	switch (le16_to_cpu(id->idProduct)) {	case 0x1006:		ttusb_dec_set_model(dec, TTUSB_DEC3000S);		break;	case 0x1008:		ttusb_dec_set_model(dec, TTUSB_DEC2000T);		break;	case 0x1009:		ttusb_dec_set_model(dec, TTUSB_DEC2540T);		break;	}	dec->udev = udev;	if (ttusb_dec_init_usb(dec))		return 0;	if (ttusb_dec_init_stb(dec)) {		ttusb_dec_exit_usb(dec);		return 0;	}	ttusb_dec_init_dvb(dec);	dec->adapter.priv = dec;	switch (le16_to_cpu(id->idProduct)) {	case 0x1006:		dec->fe = ttusbdecfe_dvbs_attach(&fe_config);		break;	case 0x1008:	case 0x1009:		dec->fe = ttusbdecfe_dvbt_attach(&fe_config);		break;	}	if (dec->fe == NULL) {		printk("dvb-ttusb-dec: A frontend driver was not found for device %04x/%04x\n",		       le16_to_cpu(dec->udev->descriptor.idVendor),		       le16_to_cpu(dec->udev->descriptor.idProduct));	} else {		if (dvb_register_frontend(&dec->adapter, dec->fe)) {			printk("budget-ci: Frontend registration failed!\n");			if (dec->fe->ops->release)				dec->fe->ops->release(dec->fe);			dec->fe = NULL;		}	}	ttusb_dec_init_v_pes(dec);	ttusb_dec_init_filters(dec);	ttusb_dec_init_tasklet(dec);	dec->active = 1;	ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN);	if (enable_rc)		ttusb_init_rc(dec);	return 0;}static void ttusb_dec_disconnect(struct usb_interface *intf){	struct ttusb_dec *dec = usb_get_intfdata(intf);	usb_set_intfdata(intf, NULL);	dprintk("%s\n", __FUNCTION__);	if (dec->active) {		ttusb_dec_exit_tasklet(dec);		ttusb_dec_exit_filters(dec);		if(enable_rc)			ttusb_dec_exit_rc(dec);		ttusb_dec_exit_usb(dec);		ttusb_dec_exit_dvb(dec);	}	kfree(dec);}static void ttusb_dec_set_model(struct ttusb_dec *dec,				enum ttusb_dec_model model){	dec->model = model;	switch (model) {	case TTUSB_DEC2000T:		dec->model_name = "DEC2000-t";		dec->firmware_name = "dvb-ttusb-dec-2000t.fw";		break;	case TTUSB_DEC2540T:		dec->model_name = "DEC2540-t";		dec->firmware_name = "dvb-ttusb-dec-2540t.fw";		break;	case TTUSB_DEC3000S:		dec->model_name = "DEC3000-s";		dec->firmware_name = "dvb-ttusb-dec-3000s.fw";		break;	}}static struct usb_device_id ttusb_dec_table[] = {	{USB_DEVICE(0x0b48, 0x1006)},	/* DEC3000-s */	/*{USB_DEVICE(0x0b48, 0x1007)},	   Unconfirmed */	{USB_DEVICE(0x0b48, 0x1008)},	/* DEC2000-t */	{USB_DEVICE(0x0b48, 0x1009)},	/* DEC2540-t */	{}};static struct usb_driver ttusb_dec_driver = {	.name		= "ttusb-dec",	.probe		= ttusb_dec_probe,	.disconnect	= ttusb_dec_disconnect,	.id_table	= ttusb_dec_table,};static int __init ttusb_dec_init(void){	int result;	if ((result = usb_register(&ttusb_dec_driver)) < 0) {		printk("%s: initialisation failed: error %d.\n", __FUNCTION__,		       result);		return result;	}	return 0;}static void __exit ttusb_dec_exit(void){	usb_deregister(&ttusb_dec_driver);}module_init(ttusb_dec_init);module_exit(ttusb_dec_exit);MODULE_AUTHOR("Alex Woods <linux-dvb@giblets.org>");MODULE_DESCRIPTION(DRIVER_NAME);MODULE_LICENSE("GPL");MODULE_DEVICE_TABLE(usb, ttusb_dec_table);

⌨️ 快捷键说明

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