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 <patrick.boettcher@desy.de>" 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 34static int debug; 35module_param(debug, int, 0644); 36MODULE_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 */ 69static 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; 72 u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG; 73 u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR; 74 u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) | 75 (read ? 0x80 : 0); 76 77 int len = usb_control_msg(fc_usb->udev, 78 read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT, 79 request, 80 request_type, /* 0xc0 read or 0x40 write */ 81 wAddress, 82 0, 83 val, 84 sizeof(u32), 85 B2C2_WAIT_FOR_OPERATION_RDW * HZ); 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 */ 97static 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{ 101 u8 request_type = USB_TYPE_VENDOR; 102 u16 wIndex; 103 int nWaitTime, pipe, len; 104 wIndex = page << 8; 105 106 switch (req) { 107 case B2C2_USB_READ_V8_MEM: 108 nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ; 109 request_type |= USB_DIR_IN; 110 pipe = B2C2_USB_CTRL_PIPE_IN; 111 break; 112 case B2C2_USB_WRITE_V8_MEM: 113 wIndex |= pbBuffer[0]; 114 request_type |= USB_DIR_OUT; 115 nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE; 116 pipe = B2C2_USB_CTRL_PIPE_OUT; 117 break; 118 case B2C2_USB_FLASH_BLOCK: 119 request_type |= USB_DIR_OUT; 120 nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH; 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 147static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb, 148 flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start, 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) { 156 case B2C2_USB_READ_V8_MEM: 157 wMax = USB_MEM_READ_MAX; 158 break; 159 case B2C2_USB_WRITE_V8_MEM: 160 wMax = USB_MEM_WRITE_MAX; 161 break; 162 case B2C2_USB_FLASH_BLOCK: 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 192static 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 200static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set, 201 flexcop_usb_utility_function_t func, u8 extra, u16 wIndex, 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, 211 B2C2_USB_UTILITY, 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 */ 223static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c, 224 flexcop_usb_request_t req, flexcop_usb_i2c_function_t func, 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: 234 case USB_FUNC_I2C_MULTIWRITE: 235 case USB_FUNC_I2C_REPEATWRITE: 236 /* DKT 020208 - add this to support special case of DiSEqC */ 237 case USB_FUNC_I2C_CHECKWRITE: 238 pipe = B2C2_USB_CTRL_PIPE_OUT; 239 nWaitTime = 2; 240 request_type |= USB_DIR_OUT; 241 break; 242 case USB_FUNC_I2C_READ: 243 case USB_FUNC_I2C_REPEATREAD: 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 */ 273static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc, 274 flexcop_ibi_register reg) 275{ 276 flexcop_ibi_value val; 277 val.raw = 0; 278 flexcop_usb_readwrite_dw(fc, reg, &val.raw, 1); 279 return val; 280} 281 282static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc, 283 flexcop_ibi_register reg, flexcop_ibi_value val) 284{ 285 return flexcop_usb_readwrite_dw(fc, reg, &val.raw, 0); 286} 287 288static 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 299static 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) 324 flexcop_pass_dmx_packets( 325 fc_usb->fc_dev, b+2, 1); 326 else 327 deb_ts( 328 "not ts packet %02x %02x %02x %02x \n", 329 *(b+2), *(b+3), 330 *(b+4), *(b+5)); 331 b += 190; 332 l -= 190; 333 break; 334 default: 335 deb_ts("wrong packet type\n"); 336 l = 0; 337 break; 338 } 339 } else { 340 deb_ts("wrong header\n"); 341 l = 0; 342 } 343 } 344 345 if (l>0) 346 memcpy(fc_usb->tmp_buffer, b, l); 347 fc_usb->tmp_buffer_length = l; 348} 349 350static void flexcop_usb_urb_complete(struct urb *urb) 351{ 352 struct flexcop_usb *fc_usb = urb->context; 353 int i; 354 355 if (urb->actual_length > 0) 356 deb_ts("urb completed, bufsize: %d actlen; %d\n", 357 urb->transfer_buffer_length, urb->actual_length); 358 359 for (i = 0; i < urb->number_of_packets; i++) { 360 if (urb->iso_frame_desc[i].status < 0) { 361 err("iso frame descriptor %d has an error: %d\n", i, 362 urb->iso_frame_desc[i].status); 363 } else 364 if (urb->iso_frame_desc[i].actual_length > 0) { 365 deb_ts("passed %d bytes to the demux\n", 366 urb->iso_frame_desc[i].actual_length); 367 368 flexcop_usb_process_frame(fc_usb, 369 urb->transfer_buffer + 370 urb->iso_frame_desc[i].offset, 371 urb->iso_frame_desc[i].actual_length); 372 } 373 urb->iso_frame_desc[i].status = 0; 374 urb->iso_frame_desc[i].actual_length = 0; 375 } 376 usb_submit_urb(urb,GFP_ATOMIC); 377} 378 379static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff) 380{ 381 /* submit/kill iso packets */ 382 return 0; 383} 384 385static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb) 386{ 387 int i; 388 for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) 389 if (fc_usb->iso_urb[i] != NULL) { 390 deb_ts("unlinking/killing urb no. %d\n",i); 391 usb_kill_urb(fc_usb->iso_urb[i]); 392 usb_free_urb(fc_usb->iso_urb[i]); 393 } 394 395 if (fc_usb->iso_buffer != NULL) 396 pci_free_consistent(NULL, 397 fc_usb->buffer_size, fc_usb->iso_buffer, 398 fc_usb->dma_addr); 399} 400 401static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb) 402{ 403 u16 frame_size = le16_to_cpu( 404 fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize); 405 int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO * 406 frame_size, i, j, ret; 407 int buffer_offset = 0; 408 409 deb_ts("creating %d iso-urbs with %d frames " 410 "each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB, 411 B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize); 412 413 fc_usb->iso_buffer = pci_alloc_consistent(NULL, 414 bufsize, &fc_usb->dma_addr); 415 if (fc_usb->iso_buffer == NULL) 416 return -ENOMEM; 417 418 memset(fc_usb->iso_buffer, 0, bufsize); 419 fc_usb->buffer_size = bufsize; 420 421 /* creating iso urbs */ 422 for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { 423 fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO, 424 GFP_ATOMIC); 425 if (fc_usb->iso_urb[i] == NULL) { 426 ret = -ENOMEM; 427 goto urb_error; 428 } 429 } 430 431 /* initialising and submitting iso urbs */ 432 for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { 433 int frame_offset = 0; 434 struct urb *urb = fc_usb->iso_urb[i]; 435 deb_ts("initializing and submitting urb no. %d " 436 "(buf_offset: %d).\n", i, buffer_offset); 437 438 urb->dev = fc_usb->udev; 439 urb->context = fc_usb; 440 urb->complete = flexcop_usb_urb_complete; 441 urb->pipe = B2C2_USB_DATA_PIPE; 442 urb->transfer_flags = URB_ISO_ASAP; 443 urb->interval = 1; 444 urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO; 445 urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO; 446 urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset; 447 448 buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO; 449 for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) { 450 deb_ts("urb no: %d, frame: %d, frame_offset: %d\n", 451 i, j, frame_offset); 452 urb->iso_frame_desc[j].offset = frame_offset; 453 urb->iso_frame_desc[j].length = frame_size; 454 frame_offset += frame_size; 455 } 456 457 if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) { 458 err("submitting urb %d failed with %d.", i, ret); 459 goto urb_error; 460 } 461 deb_ts("submitted urb no. %d.\n",i); 462 } 463 464 /* SRAM */ 465 flexcop_sram_set_dest(fc_usb->fc_dev, FC_SRAM_DEST_MEDIA | 466 FC_SRAM_DEST_NET | FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, 467 FC_SRAM_DEST_TARGET_WAN_USB); 468 flexcop_wan_set_speed(fc_usb->fc_dev, FC_WAN_SPEED_8MBITS); 469 flexcop_sram_ctrl(fc_usb->fc_dev, 1, 1, 1); 470 return 0; 471 472urb_error: 473 flexcop_usb_transfer_exit(fc_usb); 474 return ret; 475} 476 477static int flexcop_usb_init(struct flexcop_usb *fc_usb) 478{ 479 /* use the alternate setting with the larges buffer */ 480 usb_set_interface(fc_usb->udev,0,1); 481 switch (fc_usb->udev->speed) { 482 case USB_SPEED_LOW: 483 err("cannot handle USB speed because it is too slow."); 484 return -ENODEV; 485 break; 486 case USB_SPEED_FULL: 487 info("running at FULL speed."); 488 break; 489 case USB_SPEED_HIGH: 490 info("running at HIGH speed."); 491 break; 492 case USB_SPEED_UNKNOWN: /* fall through */ 493 default: 494 err("cannot handle USB speed because it is unknown."); 495 return -ENODEV; 496 } 497 usb_set_intfdata(fc_usb->uintf, fc_usb); 498 return 0; 499} 500 501static void flexcop_usb_exit(struct flexcop_usb *fc_usb) 502{ 503 usb_set_intfdata(fc_usb->uintf, NULL); 504} 505 506static int flexcop_usb_probe(struct usb_interface *intf, 507 const struct usb_device_id *id) 508{ 509 struct usb_device *udev = interface_to_usbdev(intf); 510 struct flexcop_usb *fc_usb = NULL; 511 struct flexcop_device *fc = NULL; 512 int ret; 513 514 if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) { 515 err("out of memory\n"); 516 return -ENOMEM; 517 } 518 519 /* general flexcop init */ 520 fc_usb = fc->bus_specific; 521 fc_usb->fc_dev = fc; 522 523 fc->read_ibi_reg = flexcop_usb_read_ibi_reg; 524 fc->write_ibi_reg = flexcop_usb_write_ibi_reg; 525 fc->i2c_request = flexcop_usb_i2c_request; 526 fc->get_mac_addr = flexcop_usb_get_mac_addr; 527 528 fc->stream_control = flexcop_usb_stream_control; 529 530 fc->pid_filtering = 1; 531 fc->bus_type = FC_USB; 532 533 fc->dev = &udev->dev; 534 fc->owner = THIS_MODULE; 535 536 /* bus specific part */ 537 fc_usb->udev = udev; 538 fc_usb->uintf = intf; 539 if ((ret = flexcop_usb_init(fc_usb)) != 0) 540 goto err_kfree; 541 542 /* init flexcop */ 543 if ((ret = flexcop_device_initialize(fc)) != 0) 544 goto err_usb_exit; 545 546 /* xfer init */ 547 if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0) 548 goto err_fc_exit; 549 550 info("%s successfully initialized and connected.", DRIVER_NAME); 551 return 0; 552 553err_fc_exit: 554 flexcop_device_exit(fc); 555err_usb_exit: 556 flexcop_usb_exit(fc_usb); 557err_kfree: 558 flexcop_device_kfree(fc); 559 return ret; 560} 561 562static void flexcop_usb_disconnect(struct usb_interface *intf) 563{ 564 struct flexcop_usb *fc_usb = usb_get_intfdata(intf); 565 flexcop_usb_transfer_exit(fc_usb); 566 flexcop_device_exit(fc_usb->fc_dev); 567 flexcop_usb_exit(fc_usb); 568 flexcop_device_kfree(fc_usb->fc_dev); 569 info("%s successfully deinitialized and disconnected.", DRIVER_NAME); 570} 571 572static struct usb_device_id flexcop_usb_table [] = { 573 { USB_DEVICE(0x0af7, 0x0101) }, 574 { } 575}; 576MODULE_DEVICE_TABLE (usb, flexcop_usb_table); 577 578/* usb specific object needed to register this driver with the usb subsystem */ 579static struct usb_driver flexcop_usb_driver = { 580 .name = "b2c2_flexcop_usb", 581 .probe = flexcop_usb_probe, 582 .disconnect = flexcop_usb_disconnect, 583 .id_table = flexcop_usb_table, 584}; 585 586module_usb_driver(flexcop_usb_driver); 587 588MODULE_AUTHOR(DRIVER_AUTHOR); 589MODULE_DESCRIPTION(DRIVER_NAME); 590MODULE_LICENSE("GPL"); 591