diff options
Diffstat (limited to 'drivers/media/dvb/dvb-usb/gp8psk.c')
-rw-r--r-- | drivers/media/dvb/dvb-usb/gp8psk.c | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c new file mode 100644 index 00000000000..1cb3d9a66e0 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/gp8psk.c | |||
@@ -0,0 +1,344 @@ | |||
1 | /* DVB USB compliant Linux driver for the | ||
2 | * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module | ||
3 | * | ||
4 | * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) | ||
5 | * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) | ||
6 | * | ||
7 | * Thanks to GENPIX for the sample code used to implement this module. | ||
8 | * | ||
9 | * This module is based off the vp7045 and vp702x modules | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the Free | ||
13 | * Software Foundation, version 2. | ||
14 | * | ||
15 | * see Documentation/dvb/README.dvb-usb for more information | ||
16 | */ | ||
17 | #include "gp8psk.h" | ||
18 | |||
19 | /* debug */ | ||
20 | static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw"; | ||
21 | int dvb_usb_gp8psk_debug; | ||
22 | module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644); | ||
23 | MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); | ||
24 | |||
25 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
26 | |||
27 | static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers) | ||
28 | { | ||
29 | return (gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6)); | ||
30 | } | ||
31 | |||
32 | static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers) | ||
33 | { | ||
34 | return (gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1)); | ||
35 | } | ||
36 | |||
37 | static void gp8psk_info(struct dvb_usb_device *d) | ||
38 | { | ||
39 | u8 fpga_vers, fw_vers[6]; | ||
40 | |||
41 | if (!gp8psk_get_fw_version(d, fw_vers)) | ||
42 | info("FW Version = %i.%02i.%i (0x%x) Build %4i/%02i/%02i", | ||
43 | fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers), | ||
44 | 2000 + fw_vers[5], fw_vers[4], fw_vers[3]); | ||
45 | else | ||
46 | info("failed to get FW version"); | ||
47 | |||
48 | if (!gp8psk_get_fpga_version(d, &fpga_vers)) | ||
49 | info("FPGA Version = %i", fpga_vers); | ||
50 | else | ||
51 | info("failed to get FPGA version"); | ||
52 | } | ||
53 | |||
54 | int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) | ||
55 | { | ||
56 | int ret = 0,try = 0; | ||
57 | |||
58 | if ((ret = mutex_lock_interruptible(&d->usb_mutex))) | ||
59 | return ret; | ||
60 | |||
61 | while (ret >= 0 && ret != blen && try < 3) { | ||
62 | ret = usb_control_msg(d->udev, | ||
63 | usb_rcvctrlpipe(d->udev,0), | ||
64 | req, | ||
65 | USB_TYPE_VENDOR | USB_DIR_IN, | ||
66 | value,index,b,blen, | ||
67 | 2000); | ||
68 | deb_info("reading number %d (ret: %d)\n",try,ret); | ||
69 | try++; | ||
70 | } | ||
71 | |||
72 | if (ret < 0 || ret != blen) { | ||
73 | warn("usb in %d operation failed.", req); | ||
74 | ret = -EIO; | ||
75 | } else | ||
76 | ret = 0; | ||
77 | |||
78 | deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index); | ||
79 | debug_dump(b,blen,deb_xfer); | ||
80 | |||
81 | mutex_unlock(&d->usb_mutex); | ||
82 | |||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, | ||
87 | u16 index, u8 *b, int blen) | ||
88 | { | ||
89 | int ret; | ||
90 | |||
91 | deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index); | ||
92 | debug_dump(b,blen,deb_xfer); | ||
93 | |||
94 | if ((ret = mutex_lock_interruptible(&d->usb_mutex))) | ||
95 | return ret; | ||
96 | |||
97 | if (usb_control_msg(d->udev, | ||
98 | usb_sndctrlpipe(d->udev,0), | ||
99 | req, | ||
100 | USB_TYPE_VENDOR | USB_DIR_OUT, | ||
101 | value,index,b,blen, | ||
102 | 2000) != blen) { | ||
103 | warn("usb out operation failed."); | ||
104 | ret = -EIO; | ||
105 | } else | ||
106 | ret = 0; | ||
107 | mutex_unlock(&d->usb_mutex); | ||
108 | |||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) | ||
113 | { | ||
114 | int ret; | ||
115 | const struct firmware *fw = NULL; | ||
116 | const u8 *ptr; | ||
117 | u8 *buf; | ||
118 | if ((ret = request_firmware(&fw, bcm4500_firmware, | ||
119 | &d->udev->dev)) != 0) { | ||
120 | err("did not find the bcm4500 firmware file. (%s) " | ||
121 | "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", | ||
122 | bcm4500_firmware,ret); | ||
123 | return ret; | ||
124 | } | ||
125 | |||
126 | ret = -EINVAL; | ||
127 | |||
128 | if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0)) | ||
129 | goto out_rel_fw; | ||
130 | |||
131 | info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware); | ||
132 | |||
133 | ptr = fw->data; | ||
134 | buf = kmalloc(64, GFP_KERNEL | GFP_DMA); | ||
135 | if (!buf) { | ||
136 | ret = -ENOMEM; | ||
137 | goto out_rel_fw; | ||
138 | } | ||
139 | |||
140 | while (ptr[0] != 0xff) { | ||
141 | u16 buflen = ptr[0] + 4; | ||
142 | if (ptr + buflen >= fw->data + fw->size) { | ||
143 | err("failed to load bcm4500 firmware."); | ||
144 | goto out_free; | ||
145 | } | ||
146 | memcpy(buf, ptr, buflen); | ||
147 | if (dvb_usb_generic_write(d, buf, buflen)) { | ||
148 | err("failed to load bcm4500 firmware."); | ||
149 | goto out_free; | ||
150 | } | ||
151 | ptr += buflen; | ||
152 | } | ||
153 | |||
154 | ret = 0; | ||
155 | |||
156 | out_free: | ||
157 | kfree(buf); | ||
158 | out_rel_fw: | ||
159 | release_firmware(fw); | ||
160 | |||
161 | return ret; | ||
162 | } | ||
163 | |||
164 | static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) | ||
165 | { | ||
166 | u8 status, buf; | ||
167 | int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); | ||
168 | |||
169 | if (onoff) { | ||
170 | gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1); | ||
171 | if (! (status & bm8pskStarted)) { /* started */ | ||
172 | if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) | ||
173 | gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0); | ||
174 | if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) | ||
175 | return -EINVAL; | ||
176 | gp8psk_info(d); | ||
177 | } | ||
178 | |||
179 | if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) | ||
180 | if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */ | ||
181 | if(gp8psk_load_bcm4500fw(d)) | ||
182 | return -EINVAL; | ||
183 | |||
184 | if (! (status & bmIntersilOn)) /* LNB Power */ | ||
185 | if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0, | ||
186 | &buf, 1)) | ||
187 | return -EINVAL; | ||
188 | |||
189 | /* Set DVB mode to 1 */ | ||
190 | if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) | ||
191 | if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0)) | ||
192 | return -EINVAL; | ||
193 | /* Abort possible TS (if previous tune crashed) */ | ||
194 | if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0)) | ||
195 | return -EINVAL; | ||
196 | } else { | ||
197 | /* Turn off LNB power */ | ||
198 | if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1)) | ||
199 | return -EINVAL; | ||
200 | /* Turn off 8psk power */ | ||
201 | if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) | ||
202 | return -EINVAL; | ||
203 | if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K) | ||
204 | gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0); | ||
205 | } | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | int gp8psk_bcm4500_reload(struct dvb_usb_device *d) | ||
210 | { | ||
211 | u8 buf; | ||
212 | int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); | ||
213 | /* Turn off 8psk power */ | ||
214 | if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) | ||
215 | return -EINVAL; | ||
216 | /* Turn On 8psk power */ | ||
217 | if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) | ||
218 | return -EINVAL; | ||
219 | /* load BCM4500 firmware */ | ||
220 | if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) | ||
221 | if (gp8psk_load_bcm4500fw(d)) | ||
222 | return -EINVAL; | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | ||
227 | { | ||
228 | return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0); | ||
229 | } | ||
230 | |||
231 | static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap) | ||
232 | { | ||
233 | adap->fe = gp8psk_fe_attach(adap->dev); | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static struct dvb_usb_device_properties gp8psk_properties; | ||
238 | |||
239 | static int gp8psk_usb_probe(struct usb_interface *intf, | ||
240 | const struct usb_device_id *id) | ||
241 | { | ||
242 | int ret; | ||
243 | struct usb_device *udev = interface_to_usbdev(intf); | ||
244 | ret = dvb_usb_device_init(intf, &gp8psk_properties, | ||
245 | THIS_MODULE, NULL, adapter_nr); | ||
246 | if (ret == 0) { | ||
247 | info("found Genpix USB device pID = %x (hex)", | ||
248 | le16_to_cpu(udev->descriptor.idProduct)); | ||
249 | } | ||
250 | return ret; | ||
251 | } | ||
252 | |||
253 | static struct usb_device_id gp8psk_usb_table [] = { | ||
254 | { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) }, | ||
255 | { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) }, | ||
256 | { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) }, | ||
257 | { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) }, | ||
258 | { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_2) }, | ||
259 | /* { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */ | ||
260 | { 0 }, | ||
261 | }; | ||
262 | MODULE_DEVICE_TABLE(usb, gp8psk_usb_table); | ||
263 | |||
264 | static struct dvb_usb_device_properties gp8psk_properties = { | ||
265 | .usb_ctrl = CYPRESS_FX2, | ||
266 | .firmware = "dvb-usb-gp8psk-01.fw", | ||
267 | |||
268 | .num_adapters = 1, | ||
269 | .adapter = { | ||
270 | { | ||
271 | .streaming_ctrl = gp8psk_streaming_ctrl, | ||
272 | .frontend_attach = gp8psk_frontend_attach, | ||
273 | /* parameter for the MPEG2-data transfer */ | ||
274 | .stream = { | ||
275 | .type = USB_BULK, | ||
276 | .count = 7, | ||
277 | .endpoint = 0x82, | ||
278 | .u = { | ||
279 | .bulk = { | ||
280 | .buffersize = 8192, | ||
281 | } | ||
282 | } | ||
283 | }, | ||
284 | } | ||
285 | }, | ||
286 | .power_ctrl = gp8psk_power_ctrl, | ||
287 | |||
288 | .generic_bulk_ctrl_endpoint = 0x01, | ||
289 | |||
290 | .num_device_descs = 4, | ||
291 | .devices = { | ||
292 | { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver", | ||
293 | .cold_ids = { &gp8psk_usb_table[0], NULL }, | ||
294 | .warm_ids = { &gp8psk_usb_table[1], NULL }, | ||
295 | }, | ||
296 | { .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver", | ||
297 | .cold_ids = { NULL }, | ||
298 | .warm_ids = { &gp8psk_usb_table[2], NULL }, | ||
299 | }, | ||
300 | { .name = "Genpix SkyWalker-1 DVB-S receiver", | ||
301 | .cold_ids = { NULL }, | ||
302 | .warm_ids = { &gp8psk_usb_table[3], NULL }, | ||
303 | }, | ||
304 | { .name = "Genpix SkyWalker-2 DVB-S receiver", | ||
305 | .cold_ids = { NULL }, | ||
306 | .warm_ids = { &gp8psk_usb_table[4], NULL }, | ||
307 | }, | ||
308 | { NULL }, | ||
309 | } | ||
310 | }; | ||
311 | |||
312 | /* usb specific object needed to register this driver with the usb subsystem */ | ||
313 | static struct usb_driver gp8psk_usb_driver = { | ||
314 | .name = "dvb_usb_gp8psk", | ||
315 | .probe = gp8psk_usb_probe, | ||
316 | .disconnect = dvb_usb_device_exit, | ||
317 | .id_table = gp8psk_usb_table, | ||
318 | }; | ||
319 | |||
320 | /* module stuff */ | ||
321 | static int __init gp8psk_usb_module_init(void) | ||
322 | { | ||
323 | int result; | ||
324 | if ((result = usb_register(&gp8psk_usb_driver))) { | ||
325 | err("usb_register failed. (%d)",result); | ||
326 | return result; | ||
327 | } | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static void __exit gp8psk_usb_module_exit(void) | ||
333 | { | ||
334 | /* deregister this driver from the USB subsystem */ | ||
335 | usb_deregister(&gp8psk_usb_driver); | ||
336 | } | ||
337 | |||
338 | module_init(gp8psk_usb_module_init); | ||
339 | module_exit(gp8psk_usb_module_exit); | ||
340 | |||
341 | MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>"); | ||
342 | MODULE_DESCRIPTION("Driver for Genpix DVB-S"); | ||
343 | MODULE_VERSION("1.1"); | ||
344 | MODULE_LICENSE("GPL"); | ||