X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fdvb%2Fttusb-dec%2Fttusb_dec.c;h=bd6e7baae2ec9d6bd5d53f0b5b04d414b51a432a;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=5e3f5eacc776737c2312a0b16b958b5f41bc03d8;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 5e3f5eacc..bd6e7baae 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -2,6 +2,7 @@ * TTUSB DEC Driver * * Copyright (C) 2003-2004 Alex Woods + * IR support by Peter Beutner * * 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 @@ -19,53 +20,59 @@ * */ -#include +#include + #include #include +#include #include #include #include #include #include #include -#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE) #include -#else -#warning "CRC checking of firmware not available" -#endif #include +#include #include "dmxdev.h" #include "dvb_demux.h" -#include "dvb_i2c.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; -static int debug = 0; -static int output_pva = 0; +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 0x84 -#define IN_PIPE 0x88 +#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 0x03FF +#define ISO_FRAME_SIZE 0x0380 #define MAX_PVA_LENGTH 6144 -#define LOF_HI 10600000 -#define LOF_LO 9750000 - enum ttusb_dec_model { TTUSB_DEC2000T, TTUSB_DEC2540T, @@ -91,34 +98,34 @@ struct ttusb_dec { int can_playback; /* DVB bits */ - struct dvb_adapter *adapter; + 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 *); + struct dvb_frontend* fe; 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; + 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 semaphore usb_sem; + 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 semaphore iso_sem; + struct mutex iso_mutex; u8 packet[MAX_PVA_LENGTH + 4]; enum ttusb_dec_packet_type packet_type; @@ -146,6 +153,9 @@ struct ttusb_dec { 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 */ }; @@ -161,35 +171,84 @@ struct filter_info { 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 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 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 -ETIME: + /* 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_sync(dec->rc_input_dev); + 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; @@ -211,14 +270,14 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, u8 *b; dprintk("%s\n", __FUNCTION__); - + b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL); if (!b) return -ENOMEM; - if ((result = down_interruptible(&dec->usb_sem))) { + if ((result = mutex_lock_interruptible(&dec->usb_mutex))) { kfree(b); - printk("%s: Failed to down usb semaphore.\n", __FUNCTION__); + printk("%s: Failed to lock usb mutex.\n", __FUNCTION__); return result; } @@ -238,23 +297,23 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, } result = usb_bulk_msg(dec->udev, dec->command_pipe, b, - COMMAND_PACKET_SIZE + 4, &actual_len, HZ); + COMMAND_PACKET_SIZE + 4, &actual_len, 1000); if (result) { printk("%s: command bulk message failed: error %d\n", __FUNCTION__, result); - up(&dec->usb_sem); + 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, HZ); + COMMAND_PACKET_SIZE + 4, &actual_len, 1000); if (result) { printk("%s: result bulk message failed: error %d\n", __FUNCTION__, result); - up(&dec->usb_sem); + mutex_unlock(&dec->usb_mutex); kfree(b); return result; } else { @@ -270,7 +329,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, if (cmd_result && b[3] > 0) memcpy(cmd_result, &b[4], b[3]); - up(&dec->usb_sem); + mutex_unlock(&dec->usb_mutex); kfree(b); return 0; @@ -312,7 +371,7 @@ static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode, static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data) { - struct ttusb_dec *dec = (struct ttusb_dec *)priv; + struct ttusb_dec *dec = priv; dec->audio_filter->feed->cb.ts(data, 188, NULL, 0, &dec->audio_filter->feed->feed.ts, @@ -323,7 +382,7 @@ static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data) static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data) { - struct ttusb_dec *dec = (struct ttusb_dec *)priv; + struct ttusb_dec *dec = priv; dec->video_filter->feed->cb.ts(data, 188, NULL, 0, &dec->video_filter->feed->feed.ts, @@ -350,9 +409,9 @@ static void ttusb_dec_set_pids(struct ttusb_dec *dec) ttusb_dec_send_command(dec, 0x50, sizeof(b), b, NULL, NULL); - dvb_filter_pes2ts_init(&dec->a_pes2ts, dec->pid[DMX_PES_AUDIO], + 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], + 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; @@ -375,7 +434,7 @@ static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length) case 0x01: { /* VideoStream */ int prebytes = pva[5] & 0x03; int postbytes = (pva[5] & 0x0c) >> 2; - u16 v_pes_payload_length; + u16 v_pes_payload_length; if (output_pva) { dec->video_filter->feed->cb.ts(pva, length, NULL, 0, @@ -383,23 +442,23 @@ static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length) return; } - if (dec->v_pes_postbytes > 0 && - dec->v_pes_postbytes == prebytes) { - memcpy(&dec->v_pes[dec->v_pes_length], + 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, + 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[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 | + dec->v_pes[11] = 0x01 | ((pva[9] & 0x3f) << 2) | ((pva[10] & 0x80) >> 6); dec->v_pes[12] = ((pva[10] & 0x7f) << 1) | @@ -409,33 +468,33 @@ static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length) 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; + } 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; + 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; + 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); + 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); + if (postbytes == 0) + dvb_filter_pes2ts(&dec->v_pes2ts, dec->v_pes, + dec->v_pes_length, 1); - break; - } + break; + } case 0x02: /* MainAudioStream */ if (output_pva) { @@ -517,7 +576,7 @@ static void ttusb_dec_process_packet(struct ttusb_dec *dec) case TTUSB_DEC_PACKET_PVA: if (dec->pva_stream_count) ttusb_dec_process_pva(dec, dec->packet, - dec->packet_payload_length); + dec->packet_payload_length); break; case TTUSB_DEC_PACKET_SECTION: @@ -543,7 +602,7 @@ static void swap_bytes(u8 *b, int length) } } -static void ttusb_dec_process_urb_frame(struct ttusb_dec * dec, u8 * b, +static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b, int length) { swap_bytes(b, length); @@ -592,7 +651,7 @@ static void ttusb_dec_process_urb_frame(struct ttusb_dec * dec, u8 * b, TTUSB_DEC_PACKET_EMPTY; dec->packet_payload_length = 2; dec->packet_state = 7; - } else { + } else { printk("%s: unknown packet type: " "%02x%02x\n", __FUNCTION__, dec->packet[0], dec->packet[1]); @@ -628,23 +687,23 @@ static void ttusb_dec_process_urb_frame(struct ttusb_dec * dec, u8 * b, int remainder = dec->packet_payload_length - dec->packet_length; - if (length >= remainder) { + if (length >= remainder) { memcpy(dec->packet + dec->packet_length, - b, remainder); + b, remainder); dec->packet_length += remainder; - b += remainder; - length -= remainder; + b += remainder; + length -= remainder; dec->packet_state++; - } else { + } else { memcpy(&dec->packet[dec->packet_length], - b, length); + b, length); dec->packet_length += length; - length = 0; - } - - break; + length = 0; } + break; + } + case 7: { int tail = 4; @@ -697,7 +756,7 @@ static void ttusb_dec_process_urb_frame_list(unsigned long data) } } -static void ttusb_dec_process_urb(struct urb *urb, struct pt_regs *ptregs) +static void ttusb_dec_process_urb(struct urb *urb) { struct ttusb_dec *dec = urb->context; @@ -706,7 +765,6 @@ static void ttusb_dec_process_urb(struct urb *urb, struct pt_regs *ptregs) for (i = 0; i < FRAMES_PER_ISO_BUF; i++) { struct usb_iso_packet_descriptor *d; - u8 *b; int length; struct urb_frame *frame; @@ -779,17 +837,17 @@ static void ttusb_dec_stop_iso_xfer(struct ttusb_dec *dec) dprintk("%s\n", __FUNCTION__); - if (down_interruptible(&dec->iso_sem)) + 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_unlink_urb(dec->iso_urb[i]); + usb_kill_urb(dec->iso_urb[i]); } - up(&dec->iso_sem); + mutex_unlock(&dec->iso_mutex); } /* Setting the interface of the DEC tends to take down the USB communications @@ -812,7 +870,7 @@ static int ttusb_dec_set_interface(struct ttusb_dec *dec, b, NULL, NULL); if (result) return result; - result = usb_set_interface(dec->udev, 0, 7); + result = usb_set_interface(dec->udev, 0, 8); break; case TTUSB_DEC_INTERFACE_OUT: result = usb_set_interface(dec->udev, 0, 1); @@ -834,7 +892,7 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) dprintk("%s\n", __FUNCTION__); - if (down_interruptible(&dec->iso_sem)) + if (mutex_lock_interruptible(&dec->iso_mutex)) return -EAGAIN; if (!dec->iso_stream_count) { @@ -851,11 +909,11 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) "error %d\n", __FUNCTION__, i, result); while (i) { - usb_unlink_urb(dec->iso_urb[i - 1]); + usb_kill_urb(dec->iso_urb[i - 1]); i--; } - up(&dec->iso_sem); + mutex_unlock(&dec->iso_mutex); return result; } } @@ -863,7 +921,7 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) dec->iso_stream_count++; - up(&dec->iso_sem); + mutex_unlock(&dec->iso_mutex); return 0; } @@ -909,8 +967,8 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) case DMX_TS_PES_TELETEXT: dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid; - dprintk(" pes_type: DMX_TS_PES_TELETEXT\n"); - break; + 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"); @@ -919,8 +977,8 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) break; case DMX_TS_PES_OTHER: - dprintk(" pes_type: DMX_TS_PES_OTHER\n"); - break; + dprintk(" pes_type: DMX_TS_PES_OTHER(not supported)\n"); + return -ENOSYS; default: dprintk(" pes_type: unknown (%d)\n", dvbdmxfeed->pes_type); @@ -1078,8 +1136,7 @@ static void ttusb_dec_free_iso_urbs(struct ttusb_dec *dec) dprintk("%s\n", __FUNCTION__); for (i = 0; i < ISO_BUF_COUNT; i++) - if (dec->iso_urb[i]) - usb_free_urb(dec->iso_urb[i]); + usb_free_urb(dec->iso_urb[i]); pci_free_consistent(NULL, ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * @@ -1097,10 +1154,10 @@ static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec) ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT), - &dec->iso_dma_handle); + &dec->iso_dma_handle); memset(dec->iso_buffer, 0, - sizeof(ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT))); + ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT)); for (i = 0; i < ISO_BUF_COUNT; i++) { struct urb *urb; @@ -1120,12 +1177,51 @@ static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec) static void ttusb_dec_init_tasklet(struct ttusb_dec *dec) { - dec->urb_frame_list_lock = SPIN_LOCK_UNLOCKED; + 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; + int err; + + usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys)); + strlcpy(dec->rc_phys, "/input0", sizeof(dec->rc_phys)); + + 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); + + err = input_register_device(input_dev); + if (err) { + input_free_device(input_dev); + return err; + } + + dec->rc_input_dev = 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__); @@ -1136,19 +1232,37 @@ static void ttusb_dec_init_v_pes(struct ttusb_dec *dec) dec->v_pes[3] = 0xe0; } -static void ttusb_dec_init_usb(struct ttusb_dec *dec) +static int ttusb_dec_init_usb(struct ttusb_dec *dec) { dprintk("%s\n", __FUNCTION__); - sema_init(&dec->usb_sem, 1); - sema_init(&dec->iso_sem, 1); + 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, + GFP_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; + } - ttusb_dec_alloc_iso_urbs(dec); + return ttusb_dec_alloc_iso_urbs(dec); } static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) @@ -1165,10 +1279,9 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) 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 const struct firmware *fw_entry = NULL; + dprintk("%s\n", __FUNCTION__); if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) { @@ -1181,15 +1294,15 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) firmware_size = fw_entry->size; if (firmware_size < 60) { - printk("%s: firmware size too small for DSP code (%u < 60).\n", + 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. */ -#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE) crc32_csum = crc32(~0L, firmware, 56) ^ ~0L; memcpy(&tmp, &firmware[56], 4); crc32_check = htonl(tmp); @@ -1197,9 +1310,9 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) 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; } -#endif memcpy(idstring, &firmware[36], 20); idstring[20] = '\0'; printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring); @@ -1212,15 +1325,19 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL); - if (result) + if (result) { + release_firmware(fw_entry); return result; + } trans_count = 0; j = 0; b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL); - if (b == NULL) + if (b == NULL) { + release_firmware(fw_entry); return -ENOMEM; + } for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) { size = firmware_size - i; @@ -1238,17 +1355,18 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) if (j >= ARM_PACKET_SIZE) { result = usb_bulk_msg(dec->udev, dec->command_pipe, b, ARM_PACKET_SIZE, &actual_len, - HZ / 10); + 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, HZ / 10); + &actual_len, 100); } } result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL); + release_firmware(fw_entry); kfree(b); return result; @@ -1277,17 +1395,19 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec) result = ttusb_dec_boot_dsp(dec); if (result) return result; - else + 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: @@ -1305,7 +1425,7 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec) dec->can_playback = 1; return 0; - } + } } else return result; @@ -1318,7 +1438,7 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec) dprintk("%s\n", __FUNCTION__); if ((result = dvb_register_adapter(&dec->adapter, - dec->model_name, THIS_MODULE)) < 0) { + dec->model_name, THIS_MODULE, &dec->udev->dev)) < 0) { printk("%s: dvb_register_adapter failed: error %d\n", __FUNCTION__, result); @@ -1338,7 +1458,7 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec) printk("%s: dvb_dmx_init failed: error %d\n", __FUNCTION__, result); - dvb_unregister_adapter(dec->adapter); + dvb_unregister_adapter(&dec->adapter); return result; } @@ -1347,12 +1467,12 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec) dec->dmxdev.demux = &dec->demux.dmx; dec->dmxdev.capabilities = 0; - if ((result = dvb_dmxdev_init(&dec->dmxdev, dec->adapter)) < 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); + dvb_unregister_adapter(&dec->adapter); return result; } @@ -1366,7 +1486,7 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec) dvb_dmxdev_release(&dec->dmxdev); dvb_dmx_release(&dec->demux); - dvb_unregister_adapter(dec->adapter); + dvb_unregister_adapter(&dec->adapter); return result; } @@ -1379,12 +1499,12 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec) 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); + dvb_unregister_adapter(&dec->adapter); return result; } - dvb_net_init(dec->adapter, &dec->dvb_net, &dec->demux.dmx); + dvb_net_init(&dec->adapter, &dec->dvb_net, &dec->demux.dmx); return 0; } @@ -1398,9 +1518,37 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec) 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); + if (dec->fe) { + dvb_unregister_frontend(dec->fe); + if (dec->fe->ops.release) + dec->fe->ops.release(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; @@ -1410,7 +1558,7 @@ static void ttusb_dec_exit_usb(struct ttusb_dec *dec) dec->iso_stream_count = 0; for (i = 0; i < ISO_BUF_COUNT; i++) - usb_unlink_urb(dec->iso_urb[i]); + usb_kill_urb(dec->iso_urb[i]); ttusb_dec_free_iso_urbs(dec); } @@ -1429,261 +1577,10 @@ static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec) } } -static int ttusb_dec_2000t_frontend_ioctl(struct dvb_frontend *fe, unsigned int cmd, - void *arg) -{ - struct ttusb_dec *dec = fe->data; - - dprintk("%s\n", __FUNCTION__); - - switch (cmd) { - - case FE_GET_INFO: - dprintk("%s: FE_GET_INFO\n", __FUNCTION__); - memcpy(arg, dec->frontend_info, - sizeof (struct dvb_frontend_info)); - break; - - case FE_READ_STATUS: { - fe_status_t *status = (fe_status_t *)arg; - dprintk("%s: FE_READ_STATUS\n", __FUNCTION__); - *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; - break; - } - - case FE_READ_BER: { - u32 *ber = (u32 *)arg; - dprintk("%s: FE_READ_BER\n", __FUNCTION__); - *ber = 0; - return -ENOSYS; - break; - } - - case FE_READ_SIGNAL_STRENGTH: { - dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__); - *(s32 *)arg = 0xFF; - return -ENOSYS; - break; - } - - case FE_READ_SNR: - dprintk("%s: FE_READ_SNR\n", __FUNCTION__); - *(s32 *)arg = 0; - return -ENOSYS; - break; - - case FE_READ_UNCORRECTED_BLOCKS: - dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__); - *(u32 *)arg = 0; - return -ENOSYS; - break; - - case FE_SET_FRONTEND: { - struct dvb_frontend_parameters *p = - (struct dvb_frontend_parameters *)arg; - u8 b[] = { 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff }; - u32 freq; - - dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__); - - dprintk(" frequency->%d\n", p->frequency); - dprintk(" symbol_rate->%d\n", - p->u.qam.symbol_rate); - dprintk(" inversion->%d\n", p->inversion); - - freq = htonl(p->frequency / 1000); - memcpy(&b[4], &freq, sizeof (u32)); - ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL); - - break; - } - - case FE_GET_FRONTEND: - dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__); - break; - - case FE_SLEEP: - dprintk("%s: FE_SLEEP\n", __FUNCTION__); - return -ENOSYS; - break; - - case FE_INIT: - dprintk("%s: FE_INIT\n", __FUNCTION__); - break; - - default: - dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd); - return -EINVAL; - - } - - return 0; -} - -static int ttusb_dec_3000s_frontend_ioctl(struct dvb_frontend *fe, - unsigned int cmd, void *arg) -{ - struct ttusb_dec *dec = fe->data; - - dprintk("%s\n", __FUNCTION__); - - switch (cmd) { - - case FE_GET_INFO: - dprintk("%s: FE_GET_INFO\n", __FUNCTION__); - memcpy(arg, dec->frontend_info, - sizeof (struct dvb_frontend_info)); - break; - - case FE_READ_STATUS: { - fe_status_t *status = (fe_status_t *)arg; - dprintk("%s: FE_READ_STATUS\n", __FUNCTION__); - *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; - break; - } - - case FE_READ_BER: { - u32 *ber = (u32 *)arg; - dprintk("%s: FE_READ_BER\n", __FUNCTION__); - *ber = 0; - return -ENOSYS; - break; - } - - case FE_READ_SIGNAL_STRENGTH: { - dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__); - *(s32 *)arg = 0xFF; - return -ENOSYS; - break; - } - - case FE_READ_SNR: - dprintk("%s: FE_READ_SNR\n", __FUNCTION__); - *(s32 *)arg = 0; - return -ENOSYS; - break; - - case FE_READ_UNCORRECTED_BLOCKS: - dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__); - *(u32 *)arg = 0; - return -ENOSYS; - break; - - case FE_SET_FRONTEND: { - struct dvb_frontend_parameters *p = - (struct dvb_frontend_parameters *)arg; - u8 b[] = { 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 }; - u32 freq; - u32 sym_rate; - u32 band; - u32 lnb_voltage; - - dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__); - - dprintk(" frequency->%d\n", p->frequency); - dprintk(" symbol_rate->%d\n", - p->u.qam.symbol_rate); - dprintk(" inversion->%d\n", p->inversion); - - freq = htonl(p->frequency * 1000 + - (dec->hi_band ? LOF_HI : LOF_LO)); - memcpy(&b[4], &freq, sizeof(u32)); - sym_rate = htonl(p->u.qam.symbol_rate); - memcpy(&b[12], &sym_rate, sizeof(u32)); - band = htonl(dec->hi_band ? LOF_HI : LOF_LO); - memcpy(&b[24], &band, sizeof(u32)); - lnb_voltage = htonl(dec->voltage); - memcpy(&b[28], &lnb_voltage, sizeof(u32)); - - ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL); - - break; - } - - case FE_GET_FRONTEND: - dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__); - break; - - case FE_SLEEP: - dprintk("%s: FE_SLEEP\n", __FUNCTION__); - return -ENOSYS; - break; - - case FE_INIT: - dprintk("%s: FE_INIT\n", __FUNCTION__); - break; - - case FE_DISEQC_SEND_MASTER_CMD: - dprintk("%s: FE_DISEQC_SEND_MASTER_CMD\n", __FUNCTION__); - break; - - case FE_DISEQC_SEND_BURST: - dprintk("%s: FE_DISEQC_SEND_BURST\n", __FUNCTION__); - break; - - case FE_SET_TONE: { - fe_sec_tone_mode_t tone = (fe_sec_tone_mode_t)arg; - dprintk("%s: FE_SET_TONE\n", __FUNCTION__); - dec->hi_band = (SEC_TONE_ON == tone); - break; - } - - case FE_SET_VOLTAGE: - dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__); - switch ((fe_sec_voltage_t) arg) { - case SEC_VOLTAGE_13: - dec->voltage = 13; - break; - case SEC_VOLTAGE_18: - dec->voltage = 18; - break; - default: - return -EINVAL; - break; - } - break; - - default: - dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd); - return -EINVAL; - - } - - return 0; -} - -static void ttusb_dec_init_frontend(struct ttusb_dec *dec) -{ - dec->i2c_bus.adapter = dec->adapter; - - dvb_register_frontend(dec->frontend_ioctl, &dec->i2c_bus, (void *)dec, - dec->frontend_info); -} - -static void ttusb_dec_exit_frontend(struct ttusb_dec *dec) -{ - dvb_unregister_frontend(dec->frontend_ioctl, &dec->i2c_bus); -} - static void ttusb_dec_init_filters(struct ttusb_dec *dec) { INIT_LIST_HEAD(&dec->filter_info_list); - dec->filter_info_list_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&dec->filter_info_list_lock); } static void ttusb_dec_exit_filters(struct ttusb_dec *dec) @@ -1698,6 +1595,18 @@ static void ttusb_dec_exit_filters(struct ttusb_dec *dec) } } +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) { @@ -1708,38 +1617,62 @@ static int ttusb_dec_probe(struct usb_interface *intf, udev = interface_to_usbdev(intf); - if (!(dec = kmalloc(sizeof(struct ttusb_dec), GFP_KERNEL))) { + 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); - memset(dec, 0, sizeof(struct ttusb_dec)); - - switch (id->idProduct) { - case 0x1006: + switch (le16_to_cpu(id->idProduct)) { + case 0x1006: ttusb_dec_set_model(dec, TTUSB_DEC3000S); - break; + break; - case 0x1008: + case 0x1008: ttusb_dec_set_model(dec, TTUSB_DEC2000T); break; case 0x1009: ttusb_dec_set_model(dec, TTUSB_DEC2540T); - break; + break; } dec->udev = udev; - ttusb_dec_init_usb(dec); + 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); - ttusb_dec_init_frontend(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); @@ -1748,6 +1681,9 @@ static int ttusb_dec_probe(struct usb_interface *intf, ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN); + if (enable_rc) + ttusb_init_rc(dec); + return 0; } @@ -1760,11 +1696,12 @@ static void ttusb_dec_disconnect(struct usb_interface *intf) dprintk("%s\n", __FUNCTION__); if (dec->active) { - ttusb_dec_exit_tasklet(dec); + ttusb_dec_exit_tasklet(dec); ttusb_dec_exit_filters(dec); - ttusb_dec_exit_usb(dec); - ttusb_dec_exit_frontend(dec); - ttusb_dec_exit_dvb(dec); + if(enable_rc) + ttusb_dec_exit_rc(dec); + ttusb_dec_exit_usb(dec); + ttusb_dec_exit_dvb(dec); } kfree(dec); @@ -1779,22 +1716,16 @@ static void ttusb_dec_set_model(struct ttusb_dec *dec, case TTUSB_DEC2000T: dec->model_name = "DEC2000-t"; dec->firmware_name = "dvb-ttusb-dec-2000t.fw"; - dec->frontend_info = &dec2000t_frontend_info; - dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl; break; case TTUSB_DEC2540T: dec->model_name = "DEC2540-t"; dec->firmware_name = "dvb-ttusb-dec-2540t.fw"; - dec->frontend_info = &dec2000t_frontend_info; - dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl; break; case TTUSB_DEC3000S: dec->model_name = "DEC3000-s"; dec->firmware_name = "dvb-ttusb-dec-3000s.fw"; - dec->frontend_info = &dec3000s_frontend_info; - dec->frontend_ioctl = ttusb_dec_3000s_frontend_ioctl; break; } } @@ -1809,9 +1740,9 @@ static struct usb_device_id ttusb_dec_table[] = { static struct usb_driver ttusb_dec_driver = { .name = "ttusb-dec", - .probe = ttusb_dec_probe, - .disconnect = ttusb_dec_disconnect, - .id_table = ttusb_dec_table, + .probe = ttusb_dec_probe, + .disconnect = ttusb_dec_disconnect, + .id_table = ttusb_dec_table, }; static int __init ttusb_dec_init(void) @@ -1839,8 +1770,3 @@ MODULE_AUTHOR("Alex Woods "); MODULE_DESCRIPTION(DRIVER_NAME); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(usb, ttusb_dec_table); - -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debug level"); -MODULE_PARM(output_pva, "i"); -MODULE_PARM_DESC(output_pva, "Output PVA from dvr device");