02ecc9a8e3b61ee5f2119cbd049a208b6ded9c4f
[linux-2.6.git] / drivers / media / dvb / dvb-usb / vp7045.c
1 /* DVB USB compliant Linux driver for the
2  *  - TwinhanDTV Alpha/MagicBoxII USB2.0 DVB-T receiver
3  *  - DigitalNow TinyUSB2 DVB-t receiver
4  *
5  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
6  *
7  * Thanks to Twinhan who kindly provided hardware and information.
8  *
9  *      This program is free software; you can redistribute it and/or modify it
10  *      under the terms of the GNU General Public License as published by the Free
11  *      Software Foundation, version 2.
12  *
13  * see Documentation/dvb/README.dvb-usb for more information
14  */
15 #include "vp7045.h"
16
17 /* debug */
18 int dvb_usb_vp7045_debug;
19 module_param_named(debug,dvb_usb_vp7045_debug, int, 0644);
20 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
21
22 int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
23 {
24         int ret = 0;
25         u8 inbuf[12] = { 0 }, outbuf[20] = { 0 };
26
27         outbuf[0] = cmd;
28
29         if (outlen > 19)
30                 outlen = 19;
31
32         if (inlen > 11)
33                 inlen = 11;
34
35         if (out != NULL && outlen > 0)
36                 memcpy(&outbuf[1], out, outlen);
37
38         deb_xfer("out buffer: ");
39         debug_dump(outbuf,outlen+1,deb_xfer);
40
41         if ((ret = down_interruptible(&d->usb_sem)))
42                 return ret;
43
44         if (usb_control_msg(d->udev,
45                         usb_sndctrlpipe(d->udev,0),
46                         TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0,
47                         outbuf, 20, 2*HZ) != 20) {
48                 err("USB control message 'out' went wrong.");
49                 ret = -EIO;
50                 goto unlock;
51         }
52
53         msleep(msec);
54
55         if (usb_control_msg(d->udev,
56                         usb_rcvctrlpipe(d->udev,0),
57                         TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
58                         inbuf, 12, 2*HZ) != 12) {
59                 err("USB control message 'in' went wrong.");
60                 ret = -EIO;
61                 goto unlock;
62         }
63
64         deb_xfer("in buffer: ");
65         debug_dump(inbuf,12,deb_xfer);
66
67         if (in != NULL && inlen > 0)
68                 memcpy(in,&inbuf[1],inlen);
69
70 unlock:
71         up(&d->usb_sem);
72
73         return ret;
74 }
75
76 u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg)
77 {
78         u8 obuf[2] = { 0 },v;
79         obuf[1] = reg;
80
81         vp7045_usb_op(d,TUNER_REG_READ,obuf,2,&v,1,30);
82
83         return v;
84 }
85
86 static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)
87 {
88         u8 v = onoff;
89         return vp7045_usb_op(d,SET_TUNER_POWER,&v,1,NULL,0,150);
90 }
91
92 /* remote control stuff */
93
94 /* The keymapping struct. Somehow this should be loaded to the driver, but
95  * currently it is hardcoded. */
96 static struct dvb_usb_rc_key vp7045_rc_keys[] = {
97         /* insert the keys like this. to make the raw keys visible, enable
98          * debug=0x04 when loading dvb-usb-vp7045. */
99
100         /* these keys are probably wrong. I don't have a working IR-receiver on my
101          * vp7045, so I can't test it.  Patches are welcome. */
102         { 0x00, 0x01, KEY_1 },
103         { 0x00, 0x02, KEY_2 },
104 };
105
106 static int vp7045_rc_query(struct dvb_usb_device *d, u32 *key_buf, int *state)
107 {
108         u8 key;
109         int i;
110         vp7045_usb_op(d,RC_VAL_READ,NULL,0,&key,1,20);
111
112         deb_rc("remote query key: %x %d\n",key,key);
113
114         if (key == 0x44) {
115                 *state = REMOTE_NO_KEY_PRESSED;
116                 return 0;
117         }
118
119         for (i = 0; i < sizeof(vp7045_rc_keys)/sizeof(struct dvb_usb_rc_key); i++)
120                 if (vp7045_rc_keys[i].data == key) {
121                         *state = REMOTE_KEY_PRESSED;
122                         *key_buf = vp7045_rc_keys[i].event;
123                         break;
124                 }
125         return 0;
126 }
127
128 static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int offset)
129 {
130         int i = 0;
131         u8 v,br[2];
132         for (i=0; i < len; i++) {
133                 v = offset + i;
134                 vp7045_usb_op(d,GET_EE_VALUE,&v,1,br,2,5);
135                 buf[i] = br[1];
136         }
137         deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ",offset, i);
138         debug_dump(buf,i,deb_info);
139         return 0;
140 }
141
142
143 static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
144 {
145         return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR);
146 }
147
148 static int vp7045_frontend_attach(struct dvb_usb_device *d)
149 {
150         u8 buf[255] = { 0 };
151
152         vp7045_usb_op(d,VENDOR_STRING_READ,NULL,0,buf,20,0);
153         buf[10] = '\0';
154         deb_info("firmware says: %s ",buf);
155
156         vp7045_usb_op(d,PRODUCT_STRING_READ,NULL,0,buf,20,0);
157         buf[10] = '\0';
158         deb_info("%s ",buf);
159
160         vp7045_usb_op(d,FW_VERSION_READ,NULL,0,buf,20,0);
161         buf[10] = '\0';
162         deb_info("v%s\n",buf);
163
164 /*      Dump the EEPROM */
165 /*      vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */
166
167         d->fe = vp7045_fe_attach(d);
168
169         return 0;
170 }
171
172 static struct dvb_usb_properties vp7045_properties;
173
174 static int vp7045_usb_probe(struct usb_interface *intf,
175                 const struct usb_device_id *id)
176 {
177         return dvb_usb_device_init(intf,&vp7045_properties,THIS_MODULE);
178 }
179
180 static struct usb_device_id vp7045_usb_table [] = {
181             { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_COLD) },
182             { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_WARM) },
183             { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_COLD) },
184             { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_WARM) },
185             { 0 },
186 };
187 MODULE_DEVICE_TABLE(usb, vp7045_usb_table);
188
189 static struct dvb_usb_properties vp7045_properties = {
190         .caps = 0,
191
192         .usb_ctrl = CYPRESS_FX2,
193         .firmware = "dvb-usb-vp7045-01.fw",
194
195         .power_ctrl       = vp7045_power_ctrl,
196         .frontend_attach  = vp7045_frontend_attach,
197         .read_mac_address = vp7045_read_mac_addr,
198
199         .rc_interval      = 400,
200         .rc_key_map       = vp7045_rc_keys,
201         .rc_key_map_size  = ARRAY_SIZE(vp7045_rc_keys),
202         .rc_query         = vp7045_rc_query,
203
204         /* parameter for the MPEG2-data transfer */
205         .urb = {
206                 .type = DVB_USB_BULK,
207                 .count = 7,
208                 .endpoint = 0x02,
209                 .u = {
210                         .bulk = {
211                                 .buffersize = 4096,
212                         }
213                 }
214         },
215
216         .num_device_descs = 2,
217         .devices = {
218                 { .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)",
219                   .cold_ids = { &vp7045_usb_table[0], NULL },
220                   .warm_ids = { &vp7045_usb_table[1], NULL },
221                 },
222                 { .name = "DigitalNow TinyUSB 2 DVB-t Receiver",
223                   .cold_ids = { &vp7045_usb_table[2], NULL },
224                   .warm_ids = { &vp7045_usb_table[3], NULL },
225                 },
226                 { 0 },
227         }
228 };
229
230 /* usb specific object needed to register this driver with the usb subsystem */
231 static struct usb_driver vp7045_usb_driver = {
232         .owner          = THIS_MODULE,
233         .name           = "dvb-usb-vp7045",
234         .probe          = vp7045_usb_probe,
235         .disconnect = dvb_usb_device_exit,
236         .id_table       = vp7045_usb_table,
237 };
238
239 /* module stuff */
240 static int __init vp7045_usb_module_init(void)
241 {
242         int result;
243         if ((result = usb_register(&vp7045_usb_driver))) {
244                 err("usb_register failed. (%d)",result);
245                 return result;
246         }
247
248         return 0;
249 }
250
251 static void __exit vp7045_usb_module_exit(void)
252 {
253         /* deregister this driver from the USB subsystem */
254         usb_deregister(&vp7045_usb_driver);
255 }
256
257 module_init(vp7045_usb_module_init);
258 module_exit(vp7045_usb_module_exit);
259
260 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
261 MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0");
262 MODULE_VERSION("1.0");
263 MODULE_LICENSE("GPL");