2 * Copyright (C) 2004 Patrick Boettcher <patrick.boettcher@desy.de>,
5 * based on information provided by John Jurrius from BBTI, Inc.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, version 2.
13 #include <linux/config.h>
14 #include <linux/kernel.h>
15 #include <linux/usb.h>
16 #include <linux/moduleparam.h>
17 #include <linux/pci.h>
18 #include <linux/version.h>
21 #include "dvb_demux.h"
22 #include "dvb_filter.h"
24 #include "dvb_frontend.h"
27 #define dprintk(level,args...) \
28 do { if ((debug & level)) { printk(args); } } while (0)
29 #define debug_dump(b,l) if (debug) {\
30 int i; deb_xfer("%s: %d > ",__FUNCTION__,l); \
31 for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \
36 module_param(debug, int, 0x644);
37 MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4 (or-able)).");
39 #define deb_info(args...) dprintk(0x01,args)
40 #define deb_ts(args...) dprintk(0x02,args)
41 #define deb_ctrl(args...) dprintk(0x04,args)
43 /* Version information */
44 #define DRIVER_VERSION "0.0"
45 #define DRIVER_DESC "Driver for B2C2/Technisat Air/Cable/Sky-2-PC USB devices"
46 #define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
48 /* transfer parameters */
49 #define B2C2_USB_FRAMES_PER_ISO 4
50 #define B2C2_USB_NUM_ISO_URB 4 /* TODO check out a good value */
52 #define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(b2c2->udev,0)
53 #define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(b2c2->udev,0)
54 #define B2C2_USB_DATA_PIPE usb_rcvisocpipe(b2c2->udev,0x81)
57 struct usb_device *udev;
58 struct usb_interface *uintf;
62 dma_addr_t iso_dma_handle;
63 struct urb *iso_urb[B2C2_USB_NUM_ISO_URB];
69 * 10 90 34 12 78 56 04 00
70 * usb_control_msg(udev, usb_sndctrlpipe(udev,0),
79 * extern int usb_control_msg(struct usb_device *dev, unsigned int pipe,
92 RTYPE_READ_DW = (1 << 6),
93 RTYPE_WRITE_DW_1 = (3 << 6),
94 RTYPE_READ_V8_MEMORY = (6 << 6),
95 RTYPE_WRITE_V8_MEMORY = (7 << 6),
96 RTYPE_WRITE_V8_FLASH = (8 << 6),
97 RTYPE_GENERIC = (9 << 6),
98 } b2c2_usb_request_type_t;
102 B2C2_USB_WRITE_V8_MEM = 0x04,
103 B2C2_USB_READ_V8_MEM = 0x05,
104 B2C2_USB_READ_REG = 0x08,
105 B2C2_USB_WRITE_REG = 0x0A,
106 /* B2C2_USB_WRITEREGLO = 0x0A, */
107 B2C2_USB_WRITEREGHI = 0x0B,
108 B2C2_USB_FLASH_BLOCK = 0x10,
109 B2C2_USB_I2C_REQUEST = 0x11,
110 B2C2_USB_UTILITY = 0x12,
111 } b2c2_usb_request_t;
113 /* function definition for I2C_REQUEST */
115 USB_FUNC_I2C_WRITE = 0x01,
116 USB_FUNC_I2C_MULTIWRITE = 0x02,
117 USB_FUNC_I2C_READ = 0x03,
118 USB_FUNC_I2C_REPEATWRITE = 0x04,
119 USB_FUNC_GET_DESCRIPTOR = 0x05,
120 USB_FUNC_I2C_REPEATREAD = 0x06,
121 /* DKT 020208 - add this to support special case of DiSEqC */
122 USB_FUNC_I2C_CHECKWRITE = 0x07,
123 USB_FUNC_I2C_CHECKRESULT = 0x08,
124 } b2c2_usb_i2c_function_t;
127 * function definition for UTILITY request 0x12
128 * DKT 020304 - new utility function
131 UTILITY_SET_FILTER = 0x01,
132 UTILITY_DATA_ENABLE = 0x02,
133 UTILITY_FLEX_MULTIWRITE = 0x03,
134 UTILITY_SET_BUFFER_SIZE = 0x04,
135 UTILITY_FLEX_OPERATOR = 0x05,
136 UTILITY_FLEX_RESET300_START = 0x06,
137 UTILITY_FLEX_RESET300_STOP = 0x07,
138 UTILITY_FLEX_RESET300 = 0x08,
139 UTILITY_SET_ISO_SIZE = 0x09,
140 UTILITY_DATA_RESET = 0x0A,
141 UTILITY_GET_DATA_STATUS = 0x10,
142 UTILITY_GET_V8_REG = 0x11,
143 /* DKT 020326 - add function for v1.14 */
144 UTILITY_SRAM_WRITE = 0x12,
145 UTILITY_SRAM_READ = 0x13,
146 UTILITY_SRAM_TESTFILL = 0x14,
147 UTILITY_SRAM_TESTSET = 0x15,
148 UTILITY_SRAM_TESTVERIFY = 0x16,
149 } b2c2_usb_utility_function_t;
151 #define B2C2_WAIT_FOR_OPERATION_RW 1 // 1 s
152 #define B2C2_WAIT_FOR_OPERATION_RDW 3 // 3 s
153 #define B2C2_WAIT_FOR_OPERATION_WDW 1 // 1 s
155 #define B2C2_WAIT_FOR_OPERATION_V8READ 3 // 3 s
156 #define B2C2_WAIT_FOR_OPERATION_V8WRITE 3 // 3 s
157 #define B2C2_WAIT_FOR_OPERATION_V8FLASH 3 // 3 s
159 /* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
160 * in the IBI address, to make the V8 code simpler.
161 * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (these are the six bits used)
162 * in general: 0000 0HHH 000L LL00
163 * IBI ADDRESS FORMAT: RHHH BLLL
165 * where R is the read(1)/write(0) bit, B is the busy bit
166 * and HHH and LLL are the two sets of three bits from the PCI address.
168 #define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
169 #define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
172 * DKT 020228 - forget about this VENDOR_BUFFER_SIZE, read and write register
173 * deal with DWORD or 4 bytes, that should be should from now on
175 static u32 b2c2_usb_read_dw(struct usb_b2c2_usb *b2c2, u16 wRegOffsPCI)
178 u16 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | 0x0080;
179 int len = usb_control_msg(b2c2->udev,
180 B2C2_USB_CTRL_PIPE_IN,
187 B2C2_WAIT_FOR_OPERATION_RDW * HZ);
189 if (len != sizeof(u32)) {
190 err("error while reading dword from %d (%d).",wAddress,wRegOffsPCI);
197 * DKT 020228 - from now on, we don't support anything older than firm 1.00
198 * I eliminated the write register as a 2 trip of writing hi word and lo word
199 * and force this to write only 4 bytes at a time.
200 * NOTE: this should work with all the firmware from 1.00 and newer
202 static int b2c2_usb_write_dw(struct usb_b2c2_usb *b2c2, u16 wRegOffsPCI, u32 val)
204 u16 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI);
205 int len = usb_control_msg(b2c2->udev,
206 B2C2_USB_CTRL_PIPE_OUT,
213 B2C2_WAIT_FOR_OPERATION_RDW * HZ);
215 if (len != sizeof(u32)) {
216 err("error while reading dword from %d (%d).",wAddress,wRegOffsPCI);
223 * DKT 010817 - add support for V8 memory read/write and flash update
225 static int b2c2_usb_v8_memory_req(struct usb_b2c2_usb *b2c2,
226 b2c2_usb_request_t req, u8 page, u16 wAddress,
227 u16 buflen, u8 *pbBuffer)
231 int nWaitTime,pipe,len;
236 case B2C2_USB_READ_V8_MEM:
237 nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
238 dwRequestType = (u8) RTYPE_READ_V8_MEMORY;
239 pipe = B2C2_USB_CTRL_PIPE_IN;
241 case B2C2_USB_WRITE_V8_MEM:
242 wIndex |= pbBuffer[0];
243 nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
244 dwRequestType = (u8) RTYPE_WRITE_V8_MEMORY;
245 pipe = B2C2_USB_CTRL_PIPE_OUT;
247 case B2C2_USB_FLASH_BLOCK:
248 nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
249 dwRequestType = (u8) RTYPE_WRITE_V8_FLASH;
250 pipe = B2C2_USB_CTRL_PIPE_OUT;
253 deb_info("unsupported request for v8_mem_req %x.\n",req);
256 len = usb_control_msg(b2c2->udev,pipe,
264 return len == buflen ? 0 : -EIO;
267 static int b2c2_usb_i2c_req(struct usb_b2c2_usb *b2c2,
268 b2c2_usb_request_t req, b2c2_usb_i2c_function_t func,
269 u8 port, u8 chipaddr, u8 addr, u8 buflen, u8 *buf)
272 int nWaitTime,pipe,len;
276 case USB_FUNC_I2C_WRITE:
277 case USB_FUNC_I2C_MULTIWRITE:
278 case USB_FUNC_I2C_REPEATWRITE:
279 /* DKT 020208 - add this to support special case of DiSEqC */
280 case USB_FUNC_I2C_CHECKWRITE:
281 pipe = B2C2_USB_CTRL_PIPE_OUT;
283 dwRequestType = (u8) RTYPE_GENERIC;
285 case USB_FUNC_I2C_READ:
286 case USB_FUNC_I2C_REPEATREAD:
287 pipe = B2C2_USB_CTRL_PIPE_IN;
289 dwRequestType = (u8) RTYPE_GENERIC;
292 deb_info("unsupported function for i2c_req %x\n",func);
295 wValue = (func << 8 ) | port;
296 wIndex = (chipaddr << 8 ) | addr;
298 len = usb_control_msg(b2c2->udev,pipe,
306 return len == buflen ? 0 : -EIO;
309 int static b2c2_usb_utility_req(struct usb_b2c2_usb *b2c2, int set,
310 b2c2_usb_utility_function_t func, u8 extra, u16 wIndex,
311 u16 buflen, u8 *pvBuffer)
315 pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN,
318 wValue = (func << 8) | extra;
320 len = usb_control_msg(b2c2->udev,pipe,
328 return len == buflen ? 0 : -EIO;
333 static void b2c2_dumpfourreg(struct usb_b2c2_usb *b2c2, u16 offs)
336 r0 = r1 = r2 = r3 = 0;
337 r0 = b2c2_usb_read_dw(b2c2,offs);
338 r1 = b2c2_usb_read_dw(b2c2,offs + 0x04);
339 r2 = b2c2_usb_read_dw(b2c2,offs + 0x08);
340 r3 = b2c2_usb_read_dw(b2c2,offs + 0x0c);
341 deb_ctrl("dump: offset: %03x, %08x, %08x, %08x, %08x\n",offs,r0,r1,r2,r3);
344 static void b2c2_urb_complete(struct urb *urb, struct pt_regs *ptregs)
346 struct usb_b2c2_usb *b2c2 = urb->context;
347 deb_ts("urb completed, bufsize: %d\n",urb->transfer_buffer_length);
349 // urb_submit_urb(urb,GFP_ATOMIC); enable for real action
352 static void b2c2_exit_usb(struct usb_b2c2_usb *b2c2)
355 for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
356 if (b2c2->iso_urb[i] != NULL) { /* not sure about unlink_urb and iso-urbs TODO */
357 deb_info("unlinking/killing urb no. %d\n",i);
358 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7)
359 usb_unlink_urb(b2c2->iso_urb[i]);
361 usb_kill_urb(b2c2->iso_urb[i]);
363 usb_free_urb(b2c2->iso_urb[i]);
366 if (b2c2->iso_buffer != NULL)
367 pci_free_consistent(NULL,b2c2->buffer_size, b2c2->iso_buffer, b2c2->iso_dma_handle);
371 static int b2c2_init_usb(struct usb_b2c2_usb *b2c2)
373 u16 frame_size = b2c2->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize;
374 int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * frame_size,i,j,ret;
375 int buffer_offset = 0;
377 deb_info("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n",
378 B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size,bufsize);
380 b2c2->iso_buffer = pci_alloc_consistent(NULL,bufsize,&b2c2->iso_dma_handle);
381 if (b2c2->iso_buffer == NULL)
383 memset(b2c2->iso_buffer, 0, bufsize);
384 b2c2->buffer_size = bufsize;
386 /* creating iso urbs */
387 for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
388 if (!(b2c2->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,GFP_ATOMIC))) {
392 /* initialising and submitting iso urbs */
393 for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
394 deb_info("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset);
395 int frame_offset = 0;
396 struct urb *urb = b2c2->iso_urb[i];
398 urb->dev = b2c2->udev;
400 urb->complete = b2c2_urb_complete;
401 urb->pipe = B2C2_USB_DATA_PIPE;
402 urb->transfer_flags = URB_ISO_ASAP;
404 urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO;
405 urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO;
406 urb->transfer_buffer = b2c2->iso_buffer + buffer_offset;
408 buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
409 for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
410 deb_info("urb no: %d, frame: %d, frame_offset: %d\n",i,j,frame_offset);
411 urb->iso_frame_desc[j].offset = frame_offset;
412 urb->iso_frame_desc[j].length = frame_size;
413 frame_offset += frame_size;
416 if ((ret = usb_submit_urb(b2c2->iso_urb[i],GFP_ATOMIC))) {
417 err("submitting urb %d failed with %d.",i,ret);
420 deb_info("submitted urb no. %d.\n",i);
431 static int b2c2_usb_probe(struct usb_interface *intf,
432 const struct usb_device_id *id)
434 struct usb_device *udev = interface_to_usbdev(intf);
435 struct usb_b2c2_usb *b2c2 = NULL;
438 b2c2 = kmalloc(sizeof(struct usb_b2c2_usb),GFP_KERNEL);
446 /* use the alternate setting with the larges buffer */
447 usb_set_interface(udev,0,1);
449 if ((ret = b2c2_init_usb(b2c2)))
452 usb_set_intfdata(intf,b2c2);
454 switch (udev->speed) {
456 err("cannot handle USB speed because it is to sLOW.");
459 info("running at FULL speed.");
462 info("running at HIGH speed.");
464 case USB_SPEED_UNKNOWN: /* fall through */
466 err("cannot handle USB speed because it is unkown.");
470 b2c2_dumpfourreg(b2c2,0x200);
471 b2c2_dumpfourreg(b2c2,0x300);
472 b2c2_dumpfourreg(b2c2,0x400);
473 b2c2_dumpfourreg(b2c2,0x700);
477 info("%s successfully initialized and connected.",DRIVER_DESC);
479 info("%s error while loading driver (%d)",DRIVER_DESC,ret);
490 static void b2c2_usb_disconnect(struct usb_interface *intf)
492 struct usb_b2c2_usb *b2c2 = usb_get_intfdata(intf);
493 usb_set_intfdata(intf,NULL);
498 info("%s successfully deinitialized and disconnected.",DRIVER_DESC);
502 static struct usb_device_id b2c2_usb_table [] = {
503 { USB_DEVICE(0x0af7, 0x0101) }
506 /* usb specific object needed to register this driver with the usb subsystem */
507 static struct usb_driver b2c2_usb_driver = {
508 .owner = THIS_MODULE,
509 .name = "dvb_b2c2_usb",
510 .probe = b2c2_usb_probe,
511 .disconnect = b2c2_usb_disconnect,
512 .id_table = b2c2_usb_table,
516 static int __init b2c2_usb_init(void)
519 if ((result = usb_register(&b2c2_usb_driver))) {
520 err("usb_register failed. Error number %d",result);
527 static void __exit b2c2_usb_exit(void)
529 /* deregister this driver from the USB subsystem */
530 usb_deregister(&b2c2_usb_driver);
533 module_init (b2c2_usb_init);
534 module_exit (b2c2_usb_exit);
536 MODULE_AUTHOR(DRIVER_AUTHOR);
537 MODULE_DESCRIPTION(DRIVER_DESC);
538 MODULE_LICENSE("GPL");