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, 0644);
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,
93 /* something is wrong with this part
94 RTYPE_READ_DW = (1 << 6),
95 RTYPE_WRITE_DW_1 = (3 << 6),
96 RTYPE_READ_V8_MEMORY = (6 << 6),
97 RTYPE_WRITE_V8_MEMORY = (7 << 6),
98 RTYPE_WRITE_V8_FLASH = (8 << 6),
99 RTYPE_GENERIC = (9 << 6),
101 RTYPE_READ_DW
= (3 << 6),
102 RTYPE_WRITE_DW_1
= (1 << 6),
104 RTYPE_READ_V8_MEMORY
= (6 << 6),
105 RTYPE_WRITE_V8_MEMORY
= (7 << 6),
106 RTYPE_WRITE_V8_FLASH
= (8 << 6),
107 RTYPE_GENERIC
= (9 << 6),
108 } b2c2_usb_request_type_t
;
112 B2C2_USB_WRITE_V8_MEM
= 0x04,
113 B2C2_USB_READ_V8_MEM
= 0x05,
114 B2C2_USB_READ_REG
= 0x08,
115 B2C2_USB_WRITE_REG
= 0x0A,
116 /* B2C2_USB_WRITEREGLO = 0x0A, */
117 B2C2_USB_WRITEREGHI
= 0x0B,
118 B2C2_USB_FLASH_BLOCK
= 0x10,
119 B2C2_USB_I2C_REQUEST
= 0x11,
120 B2C2_USB_UTILITY
= 0x12,
121 } b2c2_usb_request_t
;
123 /* function definition for I2C_REQUEST */
125 USB_FUNC_I2C_WRITE
= 0x01,
126 USB_FUNC_I2C_MULTIWRITE
= 0x02,
127 USB_FUNC_I2C_READ
= 0x03,
128 USB_FUNC_I2C_REPEATWRITE
= 0x04,
129 USB_FUNC_GET_DESCRIPTOR
= 0x05,
130 USB_FUNC_I2C_REPEATREAD
= 0x06,
131 /* DKT 020208 - add this to support special case of DiSEqC */
132 USB_FUNC_I2C_CHECKWRITE
= 0x07,
133 USB_FUNC_I2C_CHECKRESULT
= 0x08,
134 } b2c2_usb_i2c_function_t
;
137 * function definition for UTILITY request 0x12
138 * DKT 020304 - new utility function
141 UTILITY_SET_FILTER
= 0x01,
142 UTILITY_DATA_ENABLE
= 0x02,
143 UTILITY_FLEX_MULTIWRITE
= 0x03,
144 UTILITY_SET_BUFFER_SIZE
= 0x04,
145 UTILITY_FLEX_OPERATOR
= 0x05,
146 UTILITY_FLEX_RESET300_START
= 0x06,
147 UTILITY_FLEX_RESET300_STOP
= 0x07,
148 UTILITY_FLEX_RESET300
= 0x08,
149 UTILITY_SET_ISO_SIZE
= 0x09,
150 UTILITY_DATA_RESET
= 0x0A,
151 UTILITY_GET_DATA_STATUS
= 0x10,
152 UTILITY_GET_V8_REG
= 0x11,
153 /* DKT 020326 - add function for v1.14 */
154 UTILITY_SRAM_WRITE
= 0x12,
155 UTILITY_SRAM_READ
= 0x13,
156 UTILITY_SRAM_TESTFILL
= 0x14,
157 UTILITY_SRAM_TESTSET
= 0x15,
158 UTILITY_SRAM_TESTVERIFY
= 0x16,
159 } b2c2_usb_utility_function_t
;
161 #define B2C2_WAIT_FOR_OPERATION_RW 1 // 1 s
162 #define B2C2_WAIT_FOR_OPERATION_RDW 3 // 3 s
163 #define B2C2_WAIT_FOR_OPERATION_WDW 1 // 1 s
165 #define B2C2_WAIT_FOR_OPERATION_V8READ 3 // 3 s
166 #define B2C2_WAIT_FOR_OPERATION_V8WRITE 3 // 3 s
167 #define B2C2_WAIT_FOR_OPERATION_V8FLASH 3 // 3 s
169 /* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
170 * in the IBI address, to make the V8 code simpler.
171 * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (these are the six bits used)
172 * in general: 0000 0HHH 000L LL00
173 * IBI ADDRESS FORMAT: RHHH BLLL
175 * where R is the read(1)/write(0) bit, B is the busy bit
176 * and HHH and LLL are the two sets of three bits from the PCI address.
178 #define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
179 #define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
182 * DKT 020228 - forget about this VENDOR_BUFFER_SIZE, read and write register
183 * deal with DWORD or 4 bytes, that should be should from now on
185 static u32
b2c2_usb_read_dw(struct usb_b2c2_usb
*b2c2
, u16 wRegOffsPCI
)
188 u16 wAddress
= B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI
) | 0x0080;
189 int len
= usb_control_msg(b2c2
->udev
,
190 B2C2_USB_CTRL_PIPE_IN
,
197 B2C2_WAIT_FOR_OPERATION_RDW
* 1000);
199 if (len
!= sizeof(u32
)) {
200 err("error while reading dword from %d (%d).",wAddress
,wRegOffsPCI
);
207 * DKT 020228 - from now on, we don't support anything older than firm 1.00
208 * I eliminated the write register as a 2 trip of writing hi word and lo word
209 * and force this to write only 4 bytes at a time.
210 * NOTE: this should work with all the firmware from 1.00 and newer
212 static int b2c2_usb_write_dw(struct usb_b2c2_usb
*b2c2
, u16 wRegOffsPCI
, u32 val
)
214 u16 wAddress
= B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI
);
215 int len
= usb_control_msg(b2c2
->udev
,
216 B2C2_USB_CTRL_PIPE_OUT
,
223 B2C2_WAIT_FOR_OPERATION_RDW
* 1000);
225 if (len
!= sizeof(u32
)) {
226 err("error while reading dword from %d (%d).",wAddress
,wRegOffsPCI
);
233 * DKT 010817 - add support for V8 memory read/write and flash update
235 static int b2c2_usb_v8_memory_req(struct usb_b2c2_usb
*b2c2
,
236 b2c2_usb_request_t req
, u8 page
, u16 wAddress
,
237 u16 buflen
, u8
*pbBuffer
)
241 int nWaitTime
,pipe
,len
;
246 case B2C2_USB_READ_V8_MEM
:
247 nWaitTime
= B2C2_WAIT_FOR_OPERATION_V8READ
;
248 dwRequestType
= (u8
) RTYPE_READ_V8_MEMORY
;
249 pipe
= B2C2_USB_CTRL_PIPE_IN
;
251 case B2C2_USB_WRITE_V8_MEM
:
252 wIndex
|= pbBuffer
[0];
253 nWaitTime
= B2C2_WAIT_FOR_OPERATION_V8WRITE
;
254 dwRequestType
= (u8
) RTYPE_WRITE_V8_MEMORY
;
255 pipe
= B2C2_USB_CTRL_PIPE_OUT
;
257 case B2C2_USB_FLASH_BLOCK
:
258 nWaitTime
= B2C2_WAIT_FOR_OPERATION_V8FLASH
;
259 dwRequestType
= (u8
) RTYPE_WRITE_V8_FLASH
;
260 pipe
= B2C2_USB_CTRL_PIPE_OUT
;
263 deb_info("unsupported request for v8_mem_req %x.\n",req
);
266 len
= usb_control_msg(b2c2
->udev
,pipe
,
274 return len
== buflen
? 0 : -EIO
;
277 static int b2c2_usb_i2c_req(struct usb_b2c2_usb
*b2c2
,
278 b2c2_usb_request_t req
, b2c2_usb_i2c_function_t func
,
279 u8 port
, u8 chipaddr
, u8 addr
, u8 buflen
, u8
*buf
)
282 int nWaitTime
,pipe
,len
;
286 case USB_FUNC_I2C_WRITE
:
287 case USB_FUNC_I2C_MULTIWRITE
:
288 case USB_FUNC_I2C_REPEATWRITE
:
289 /* DKT 020208 - add this to support special case of DiSEqC */
290 case USB_FUNC_I2C_CHECKWRITE
:
291 pipe
= B2C2_USB_CTRL_PIPE_OUT
;
293 dwRequestType
= (u8
) RTYPE_GENERIC
;
295 case USB_FUNC_I2C_READ
:
296 case USB_FUNC_I2C_REPEATREAD
:
297 pipe
= B2C2_USB_CTRL_PIPE_IN
;
299 dwRequestType
= (u8
) RTYPE_GENERIC
;
302 deb_info("unsupported function for i2c_req %x\n",func
);
305 wValue
= (func
<< 8 ) | port
;
306 wIndex
= (chipaddr
<< 8 ) | addr
;
308 len
= usb_control_msg(b2c2
->udev
,pipe
,
316 return len
== buflen
? 0 : -EIO
;
319 int static b2c2_usb_utility_req(struct usb_b2c2_usb
*b2c2
, int set
,
320 b2c2_usb_utility_function_t func
, u8 extra
, u16 wIndex
,
321 u16 buflen
, u8
*pvBuffer
)
325 pipe
= set
? B2C2_USB_CTRL_PIPE_OUT
: B2C2_USB_CTRL_PIPE_IN
,
328 wValue
= (func
<< 8) | extra
;
330 len
= usb_control_msg(b2c2
->udev
,pipe
,
338 return len
== buflen
? 0 : -EIO
;
343 static void b2c2_dumpfourreg(struct usb_b2c2_usb
*b2c2
, u16 offs
)
346 r0
= r1
= r2
= r3
= 0;
347 r0
= b2c2_usb_read_dw(b2c2
,offs
);
348 r1
= b2c2_usb_read_dw(b2c2
,offs
+ 0x04);
349 r2
= b2c2_usb_read_dw(b2c2
,offs
+ 0x08);
350 r3
= b2c2_usb_read_dw(b2c2
,offs
+ 0x0c);
351 deb_ctrl("dump: offset: %03x, %08x, %08x, %08x, %08x\n",offs
,r0
,r1
,r2
,r3
);
354 static void b2c2_urb_complete(struct urb
*urb
, struct pt_regs
*ptregs
)
356 struct usb_b2c2_usb
*b2c2
= urb
->context
;
357 deb_ts("urb completed, bufsize: %d\n",urb
->transfer_buffer_length
);
359 // urb_submit_urb(urb,GFP_ATOMIC); enable for real action
362 static void b2c2_exit_usb(struct usb_b2c2_usb
*b2c2
)
365 for (i
= 0; i
< B2C2_USB_NUM_ISO_URB
; i
++)
366 if (b2c2
->iso_urb
[i
] != NULL
) { /* not sure about unlink_urb and iso-urbs TODO */
367 deb_info("unlinking/killing urb no. %d\n",i
);
368 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7)
369 usb_unlink_urb(b2c2
->iso_urb
[i
]);
371 usb_kill_urb(b2c2
->iso_urb
[i
]);
373 usb_free_urb(b2c2
->iso_urb
[i
]);
376 if (b2c2
->iso_buffer
!= NULL
)
377 pci_free_consistent(NULL
,b2c2
->buffer_size
, b2c2
->iso_buffer
, b2c2
->iso_dma_handle
);
381 static int b2c2_init_usb(struct usb_b2c2_usb
*b2c2
)
383 u16 frame_size
= le16_to_cpu(b2c2
->uintf
->cur_altsetting
->endpoint
[0].desc
.wMaxPacketSize
);
384 int bufsize
= B2C2_USB_NUM_ISO_URB
* B2C2_USB_FRAMES_PER_ISO
* frame_size
,i
,j
,ret
;
385 int buffer_offset
= 0;
387 deb_info("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n",
388 B2C2_USB_NUM_ISO_URB
, B2C2_USB_FRAMES_PER_ISO
, frame_size
,bufsize
);
390 b2c2
->iso_buffer
= pci_alloc_consistent(NULL
,bufsize
,&b2c2
->iso_dma_handle
);
391 if (b2c2
->iso_buffer
== NULL
)
393 memset(b2c2
->iso_buffer
, 0, bufsize
);
394 b2c2
->buffer_size
= bufsize
;
396 /* creating iso urbs */
397 for (i
= 0; i
< B2C2_USB_NUM_ISO_URB
; i
++)
398 if (!(b2c2
->iso_urb
[i
] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO
,GFP_ATOMIC
))) {
402 /* initialising and submitting iso urbs */
403 for (i
= 0; i
< B2C2_USB_NUM_ISO_URB
; i
++) {
404 int frame_offset
= 0;
405 struct urb
*urb
= b2c2
->iso_urb
[i
];
406 deb_info("initializing and submitting urb no. %d (buf_offset: %d).\n",i
,buffer_offset
);
408 urb
->dev
= b2c2
->udev
;
410 urb
->complete
= b2c2_urb_complete
;
411 urb
->pipe
= B2C2_USB_DATA_PIPE
;
412 urb
->transfer_flags
= URB_ISO_ASAP
;
414 urb
->number_of_packets
= B2C2_USB_FRAMES_PER_ISO
;
415 urb
->transfer_buffer_length
= frame_size
* B2C2_USB_FRAMES_PER_ISO
;
416 urb
->transfer_buffer
= b2c2
->iso_buffer
+ buffer_offset
;
418 buffer_offset
+= frame_size
* B2C2_USB_FRAMES_PER_ISO
;
419 for (j
= 0; j
< B2C2_USB_FRAMES_PER_ISO
; j
++) {
420 deb_info("urb no: %d, frame: %d, frame_offset: %d\n",i
,j
,frame_offset
);
421 urb
->iso_frame_desc
[j
].offset
= frame_offset
;
422 urb
->iso_frame_desc
[j
].length
= frame_size
;
423 frame_offset
+= frame_size
;
426 if ((ret
= usb_submit_urb(b2c2
->iso_urb
[i
],GFP_ATOMIC
))) {
427 err("submitting urb %d failed with %d.",i
,ret
);
430 deb_info("submitted urb no. %d.\n",i
);
441 static int b2c2_usb_probe(struct usb_interface
*intf
,
442 const struct usb_device_id
*id
)
444 struct usb_device
*udev
= interface_to_usbdev(intf
);
445 struct usb_b2c2_usb
*b2c2
= NULL
;
448 b2c2
= kmalloc(sizeof(struct usb_b2c2_usb
),GFP_KERNEL
);
456 /* use the alternate setting with the larges buffer */
457 usb_set_interface(udev
,0,1);
459 if ((ret
= b2c2_init_usb(b2c2
)))
462 usb_set_intfdata(intf
,b2c2
);
464 switch (udev
->speed
) {
466 err("cannot handle USB speed because it is to sLOW.");
469 info("running at FULL speed.");
472 info("running at HIGH speed.");
474 case USB_SPEED_UNKNOWN
: /* fall through */
476 err("cannot handle USB speed because it is unkown.");
480 b2c2_dumpfourreg(b2c2
,0x200);
481 b2c2_dumpfourreg(b2c2
,0x300);
482 b2c2_dumpfourreg(b2c2
,0x400);
483 b2c2_dumpfourreg(b2c2
,0x700);
487 info("%s successfully initialized and connected.",DRIVER_DESC
);
489 info("%s error while loading driver (%d)",DRIVER_DESC
,ret
);
500 static void b2c2_usb_disconnect(struct usb_interface
*intf
)
502 struct usb_b2c2_usb
*b2c2
= usb_get_intfdata(intf
);
503 usb_set_intfdata(intf
,NULL
);
508 info("%s successfully deinitialized and disconnected.",DRIVER_DESC
);
512 static struct usb_device_id b2c2_usb_table
[] = {
513 { USB_DEVICE(0x0af7, 0x0101) }
516 /* usb specific object needed to register this driver with the usb subsystem */
517 static struct usb_driver b2c2_usb_driver
= {
518 .owner
= THIS_MODULE
,
519 .name
= "dvb_b2c2_usb",
520 .probe
= b2c2_usb_probe
,
521 .disconnect
= b2c2_usb_disconnect
,
522 .id_table
= b2c2_usb_table
,
526 static int __init
b2c2_usb_init(void)
529 if ((result
= usb_register(&b2c2_usb_driver
))) {
530 err("usb_register failed. Error number %d",result
);
537 static void __exit
b2c2_usb_exit(void)
539 /* deregister this driver from the USB subsystem */
540 usb_deregister(&b2c2_usb_driver
);
543 module_init (b2c2_usb_init
);
544 module_exit (b2c2_usb_exit
);
546 MODULE_AUTHOR(DRIVER_AUTHOR
);
547 MODULE_DESCRIPTION(DRIVER_DESC
);
548 MODULE_LICENSE("GPL");
549 MODULE_DEVICE_TABLE(usb
, b2c2_usb_table
);