diff options
Diffstat (limited to 'drivers/media/dvb/dvb-usb/vp7045.c')
-rw-r--r-- | drivers/media/dvb/dvb-usb/vp7045.c | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c new file mode 100644 index 000000000000..02ecc9a8e3b6 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/vp7045.c | |||
@@ -0,0 +1,263 @@ | |||
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"); | ||