Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
flexcop-usb.c
Go to the documentation of this file.
1 /*
2  * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
3  * flexcop-usb.c - covers the USB part
4  * see flexcop.c for copyright information
5  */
6 #define FC_LOG_PREFIX "flexcop_usb"
7 #include "flexcop-usb.h"
8 #include "flexcop-common.h"
9 
10 /* Version information */
11 #define DRIVER_VERSION "0.1"
12 #define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver"
13 #define DRIVER_AUTHOR "Patrick Boettcher <[email protected]>"
14 
15 /* debug */
16 #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
17 #define dprintk(level,args...) \
18  do { if ((debug & level)) printk(args); } while (0)
19 
20 #define debug_dump(b, l, method) do {\
21  int i; \
22  for (i = 0; i < l; i++) \
23  method("%02x ", b[i]); \
24  method("\n"); \
25 } while (0)
26 
27 #define DEBSTATUS ""
28 #else
29 #define dprintk(level, args...)
30 #define debug_dump(b, l, method)
31 #define DEBSTATUS " (debugging is not enabled)"
32 #endif
33 
34 static int debug;
35 module_param(debug, int, 0644);
36 MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,"
37  "ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
38 #undef DEBSTATUS
39 
40 #define deb_info(args...) dprintk(0x01, args)
41 #define deb_ts(args...) dprintk(0x02, args)
42 #define deb_ctrl(args...) dprintk(0x04, args)
43 #define deb_i2c(args...) dprintk(0x08, args)
44 #define deb_v8(args...) dprintk(0x10, args)
45 
46 /* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
47  * in the IBI address, to make the V8 code simpler.
48  * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (the six bits used)
49  * in general: 0000 0HHH 000L LL00
50  * IBI ADDRESS FORMAT: RHHH BLLL
51  *
52  * where R is the read(1)/write(0) bit, B is the busy bit
53  * and HHH and LLL are the two sets of three bits from the PCI address.
54  */
55 #define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) \
56  (((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
57 #define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) \
58  (((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
59 
60 /*
61  * DKT 020228
62  * - forget about this VENDOR_BUFFER_SIZE, read and write register
63  * deal with DWORD or 4 bytes, that should be should from now on
64  * - from now on, we don't support anything older than firm 1.00
65  * I eliminated the write register as a 2 trip of writing hi word and lo word
66  * and force this to write only 4 bytes at a time.
67  * NOTE: this should work with all the firmware from 1.00 and newer
68  */
69 static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read)
70 {
71  struct flexcop_usb *fc_usb = fc->bus_specific;
74  u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) |
75  (read ? 0x80 : 0);
76 
77  int len = usb_control_msg(fc_usb->udev,
79  request,
80  request_type, /* 0xc0 read or 0x40 write */
81  wAddress,
82  0,
83  val,
84  sizeof(u32),
86 
87  if (len != sizeof(u32)) {
88  err("error while %s dword from %d (%d).", read ? "reading" :
89  "writing", wAddress, wRegOffsPCI);
90  return -EIO;
91  }
92  return 0;
93 }
94 /*
95  * DKT 010817 - add support for V8 memory read/write and flash update
96  */
97 static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
98  flexcop_usb_request_t req, u8 page, u16 wAddress,
99  u8 *pbBuffer, u32 buflen)
100 {
102  u16 wIndex;
103  int nWaitTime, pipe, len;
104  wIndex = page << 8;
105 
106  switch (req) {
108  nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
109  request_type |= USB_DIR_IN;
110  pipe = B2C2_USB_CTRL_PIPE_IN;
111  break;
113  wIndex |= pbBuffer[0];
114  request_type |= USB_DIR_OUT;
116  pipe = B2C2_USB_CTRL_PIPE_OUT;
117  break;
119  request_type |= USB_DIR_OUT;
121  pipe = B2C2_USB_CTRL_PIPE_OUT;
122  break;
123  default:
124  deb_info("unsupported request for v8_mem_req %x.\n", req);
125  return -EINVAL;
126  }
127  deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n", request_type, req,
128  wAddress, wIndex, buflen);
129 
130  len = usb_control_msg(fc_usb->udev, pipe,
131  req,
132  request_type,
133  wAddress,
134  wIndex,
135  pbBuffer,
136  buflen,
137  nWaitTime * HZ);
138 
139  debug_dump(pbBuffer, len, deb_v8);
140  return len == buflen ? 0 : -EIO;
141 }
142 
143 #define bytes_left_to_read_on_page(paddr,buflen) \
144  ((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \
145  ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)))
146 
147 static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
149  u32 addr, int extended, u8 *buf, u32 len)
150 {
151  int i,ret = 0;
152  u16 wMax;
153  u32 pagechunk = 0;
154 
155  switch(req) {
157  wMax = USB_MEM_READ_MAX;
158  break;
160  wMax = USB_MEM_WRITE_MAX;
161  break;
163  wMax = USB_FLASH_MAX;
164  break;
165  default:
166  return -EINVAL;
167  break;
168  }
169  for (i = 0; i < len;) {
170  pagechunk =
171  wMax < bytes_left_to_read_on_page(addr, len) ?
172  wMax :
173  bytes_left_to_read_on_page(addr, len);
174  deb_info("%x\n",
175  (addr & V8_MEMORY_PAGE_MASK) |
176  (V8_MEMORY_EXTENDED*extended));
177 
178  ret = flexcop_usb_v8_memory_req(fc_usb, req,
179  page_start + (addr / V8_MEMORY_PAGE_SIZE),
180  (addr & V8_MEMORY_PAGE_MASK) |
181  (V8_MEMORY_EXTENDED*extended),
182  &buf[i], pagechunk);
183 
184  if (ret < 0)
185  return ret;
186  addr += pagechunk;
187  len -= pagechunk;
188  }
189  return 0;
190 }
191 
192 static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended)
193 {
194  return flexcop_usb_memory_req(fc->bus_specific, B2C2_USB_READ_V8_MEM,
195  V8_MEMORY_PAGE_FLASH, 0x1f010, 1,
196  fc->dvb_adapter.proposed_mac, 6);
197 }
198 
199 #if 0
200 static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set,
202  u16 buflen, u8 *pvBuffer)
203 {
204  u16 wValue;
205  u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR;
206  int nWaitTime = 2,
207  pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, len;
208  wValue = (func << 8) | extra;
209 
210  len = usb_control_msg(fc_usb->udev,pipe,
212  request_type,
213  wValue,
214  wIndex,
215  pvBuffer,
216  buflen,
217  nWaitTime * HZ);
218  return len == buflen ? 0 : -EIO;
219 }
220 #endif
221 
222 /* usb i2c stuff */
223 static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
225  u8 chipaddr, u8 addr, u8 *buf, u8 buflen)
226 {
227  struct flexcop_usb *fc_usb = i2c->fc->bus_specific;
228  u16 wValue, wIndex;
229  int nWaitTime,pipe,len;
230  u8 request_type = USB_TYPE_VENDOR;
231 
232  switch (func) {
233  case USB_FUNC_I2C_WRITE:
236  /* DKT 020208 - add this to support special case of DiSEqC */
238  pipe = B2C2_USB_CTRL_PIPE_OUT;
239  nWaitTime = 2;
240  request_type |= USB_DIR_OUT;
241  break;
242  case USB_FUNC_I2C_READ:
244  pipe = B2C2_USB_CTRL_PIPE_IN;
245  nWaitTime = 2;
246  request_type |= USB_DIR_IN;
247  break;
248  default:
249  deb_info("unsupported function for i2c_req %x\n", func);
250  return -EINVAL;
251  }
252  wValue = (func << 8) | (i2c->port << 4);
253  wIndex = (chipaddr << 8 ) | addr;
254 
255  deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",
256  func, request_type, req,
257  wValue & 0xff, wValue >> 8,
258  wIndex & 0xff, wIndex >> 8);
259 
260  len = usb_control_msg(fc_usb->udev,pipe,
261  req,
262  request_type,
263  wValue,
264  wIndex,
265  buf,
266  buflen,
267  nWaitTime * HZ);
268  return len == buflen ? 0 : -EREMOTEIO;
269 }
270 
271 /* actual bus specific access functions,
272  make sure prototype are/will be equal to pci */
273 static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc,
275 {
277  val.raw = 0;
278  flexcop_usb_readwrite_dw(fc, reg, &val.raw, 1);
279  return val;
280 }
281 
282 static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc,
284 {
285  return flexcop_usb_readwrite_dw(fc, reg, &val.raw, 0);
286 }
287 
288 static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c,
289  flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
290 {
291  if (op == FC_READ)
292  return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
293  USB_FUNC_I2C_READ, chipaddr, addr, buf, len);
294  else
295  return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
296  USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len);
297 }
298 
299 static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb,
300  u8 *buffer, int buffer_length)
301 {
302  u8 *b;
303  int l;
304 
305  deb_ts("tmp_buffer_length=%d, buffer_length=%d\n",
306  fc_usb->tmp_buffer_length, buffer_length);
307 
308  if (fc_usb->tmp_buffer_length > 0) {
309  memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer,
310  buffer_length);
311  fc_usb->tmp_buffer_length += buffer_length;
312  b = fc_usb->tmp_buffer;
313  l = fc_usb->tmp_buffer_length;
314  } else {
315  b=buffer;
316  l=buffer_length;
317  }
318 
319  while (l >= 190) {
320  if (*b == 0xff) {
321  switch (*(b+1) & 0x03) {
322  case 0x01: /* media packet */
323  if (*(b+2) == 0x47)
325  fc_usb->fc_dev, b+2, 1);
326  else
327  deb_ts("not ts packet %*ph\n", 4, b+2);
328  b += 190;
329  l -= 190;
330  break;
331  default:
332  deb_ts("wrong packet type\n");
333  l = 0;
334  break;
335  }
336  } else {
337  deb_ts("wrong header\n");
338  l = 0;
339  }
340  }
341 
342  if (l>0)
343  memcpy(fc_usb->tmp_buffer, b, l);
344  fc_usb->tmp_buffer_length = l;
345 }
346 
347 static void flexcop_usb_urb_complete(struct urb *urb)
348 {
349  struct flexcop_usb *fc_usb = urb->context;
350  int i;
351 
352  if (urb->actual_length > 0)
353  deb_ts("urb completed, bufsize: %d actlen; %d\n",
354  urb->transfer_buffer_length, urb->actual_length);
355 
356  for (i = 0; i < urb->number_of_packets; i++) {
357  if (urb->iso_frame_desc[i].status < 0) {
358  err("iso frame descriptor %d has an error: %d\n", i,
359  urb->iso_frame_desc[i].status);
360  } else
361  if (urb->iso_frame_desc[i].actual_length > 0) {
362  deb_ts("passed %d bytes to the demux\n",
363  urb->iso_frame_desc[i].actual_length);
364 
365  flexcop_usb_process_frame(fc_usb,
366  urb->transfer_buffer +
367  urb->iso_frame_desc[i].offset,
368  urb->iso_frame_desc[i].actual_length);
369  }
370  urb->iso_frame_desc[i].status = 0;
371  urb->iso_frame_desc[i].actual_length = 0;
372  }
374 }
375 
376 static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff)
377 {
378  /* submit/kill iso packets */
379  return 0;
380 }
381 
382 static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
383 {
384  int i;
385  for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
386  if (fc_usb->iso_urb[i] != NULL) {
387  deb_ts("unlinking/killing urb no. %d\n",i);
388  usb_kill_urb(fc_usb->iso_urb[i]);
389  usb_free_urb(fc_usb->iso_urb[i]);
390  }
391 
392  if (fc_usb->iso_buffer != NULL)
394  fc_usb->buffer_size, fc_usb->iso_buffer,
395  fc_usb->dma_addr);
396 }
397 
398 static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
399 {
400  u16 frame_size = le16_to_cpu(
401  fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
402  int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO *
403  frame_size, i, j, ret;
404  int buffer_offset = 0;
405 
406  deb_ts("creating %d iso-urbs with %d frames "
407  "each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB,
408  B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize);
409 
411  bufsize, &fc_usb->dma_addr);
412  if (fc_usb->iso_buffer == NULL)
413  return -ENOMEM;
414 
415  memset(fc_usb->iso_buffer, 0, bufsize);
416  fc_usb->buffer_size = bufsize;
417 
418  /* creating iso urbs */
419  for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
421  GFP_ATOMIC);
422  if (fc_usb->iso_urb[i] == NULL) {
423  ret = -ENOMEM;
424  goto urb_error;
425  }
426  }
427 
428  /* initialising and submitting iso urbs */
429  for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
430  int frame_offset = 0;
431  struct urb *urb = fc_usb->iso_urb[i];
432  deb_ts("initializing and submitting urb no. %d "
433  "(buf_offset: %d).\n", i, buffer_offset);
434 
435  urb->dev = fc_usb->udev;
436  urb->context = fc_usb;
437  urb->complete = flexcop_usb_urb_complete;
438  urb->pipe = B2C2_USB_DATA_PIPE;
439  urb->transfer_flags = URB_ISO_ASAP;
440  urb->interval = 1;
441  urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO;
442  urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO;
443  urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset;
444 
445  buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
446  for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
447  deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",
448  i, j, frame_offset);
449  urb->iso_frame_desc[j].offset = frame_offset;
450  urb->iso_frame_desc[j].length = frame_size;
451  frame_offset += frame_size;
452  }
453 
454  if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) {
455  err("submitting urb %d failed with %d.", i, ret);
456  goto urb_error;
457  }
458  deb_ts("submitted urb no. %d.\n",i);
459  }
460 
461  /* SRAM */
466  flexcop_sram_ctrl(fc_usb->fc_dev, 1, 1, 1);
467  return 0;
468 
469 urb_error:
470  flexcop_usb_transfer_exit(fc_usb);
471  return ret;
472 }
473 
474 static int flexcop_usb_init(struct flexcop_usb *fc_usb)
475 {
476  /* use the alternate setting with the larges buffer */
477  usb_set_interface(fc_usb->udev,0,1);
478  switch (fc_usb->udev->speed) {
479  case USB_SPEED_LOW:
480  err("cannot handle USB speed because it is too slow.");
481  return -ENODEV;
482  break;
483  case USB_SPEED_FULL:
484  info("running at FULL speed.");
485  break;
486  case USB_SPEED_HIGH:
487  info("running at HIGH speed.");
488  break;
489  case USB_SPEED_UNKNOWN: /* fall through */
490  default:
491  err("cannot handle USB speed because it is unknown.");
492  return -ENODEV;
493  }
494  usb_set_intfdata(fc_usb->uintf, fc_usb);
495  return 0;
496 }
497 
498 static void flexcop_usb_exit(struct flexcop_usb *fc_usb)
499 {
500  usb_set_intfdata(fc_usb->uintf, NULL);
501 }
502 
503 static int flexcop_usb_probe(struct usb_interface *intf,
504  const struct usb_device_id *id)
505 {
506  struct usb_device *udev = interface_to_usbdev(intf);
507  struct flexcop_usb *fc_usb = NULL;
508  struct flexcop_device *fc = NULL;
509  int ret;
510 
511  if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) {
512  err("out of memory\n");
513  return -ENOMEM;
514  }
515 
516  /* general flexcop init */
517  fc_usb = fc->bus_specific;
518  fc_usb->fc_dev = fc;
519 
520  fc->read_ibi_reg = flexcop_usb_read_ibi_reg;
521  fc->write_ibi_reg = flexcop_usb_write_ibi_reg;
522  fc->i2c_request = flexcop_usb_i2c_request;
523  fc->get_mac_addr = flexcop_usb_get_mac_addr;
524 
525  fc->stream_control = flexcop_usb_stream_control;
526 
527  fc->pid_filtering = 1;
528  fc->bus_type = FC_USB;
529 
530  fc->dev = &udev->dev;
531  fc->owner = THIS_MODULE;
532 
533  /* bus specific part */
534  fc_usb->udev = udev;
535  fc_usb->uintf = intf;
536  if ((ret = flexcop_usb_init(fc_usb)) != 0)
537  goto err_kfree;
538 
539  /* init flexcop */
540  if ((ret = flexcop_device_initialize(fc)) != 0)
541  goto err_usb_exit;
542 
543  /* xfer init */
544  if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0)
545  goto err_fc_exit;
546 
547  info("%s successfully initialized and connected.", DRIVER_NAME);
548  return 0;
549 
550 err_fc_exit:
552 err_usb_exit:
553  flexcop_usb_exit(fc_usb);
554 err_kfree:
556  return ret;
557 }
558 
559 static void flexcop_usb_disconnect(struct usb_interface *intf)
560 {
561  struct flexcop_usb *fc_usb = usb_get_intfdata(intf);
562  flexcop_usb_transfer_exit(fc_usb);
563  flexcop_device_exit(fc_usb->fc_dev);
564  flexcop_usb_exit(fc_usb);
565  flexcop_device_kfree(fc_usb->fc_dev);
566  info("%s successfully deinitialized and disconnected.", DRIVER_NAME);
567 }
568 
569 static struct usb_device_id flexcop_usb_table [] = {
570  { USB_DEVICE(0x0af7, 0x0101) },
571  { }
572 };
573 MODULE_DEVICE_TABLE (usb, flexcop_usb_table);
574 
575 /* usb specific object needed to register this driver with the usb subsystem */
576 static struct usb_driver flexcop_usb_driver = {
577  .name = "b2c2_flexcop_usb",
578  .probe = flexcop_usb_probe,
579  .disconnect = flexcop_usb_disconnect,
580  .id_table = flexcop_usb_table,
581 };
582 
583 module_usb_driver(flexcop_usb_driver);
584 
587 MODULE_LICENSE("GPL");