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("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 347static 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 } 373 usb_submit_urb(urb,GFP_ATOMIC); 374} 375 376static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff) 377{ 378 /* submit/kill iso packets */ 379 return 0; 380} 381 382static 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) 393 usb_free_coherent(fc_usb->udev, 394 fc_usb->buffer_size, fc_usb->iso_buffer, 395 fc_usb->dma_addr); 396} 397 398static 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 410 fc_usb->iso_buffer = usb_alloc_coherent(fc_usb->udev, 411 bufsize, GFP_KERNEL, &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++) { 420 fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO, 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 */ 462 flexcop_sram_set_dest(fc_usb->fc_dev, FC_SRAM_DEST_MEDIA | 463 FC_SRAM_DEST_NET | FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, 464 FC_SRAM_DEST_TARGET_WAN_USB); 465 flexcop_wan_set_speed(fc_usb->fc_dev, FC_WAN_SPEED_8MBITS); 466 flexcop_sram_ctrl(fc_usb->fc_dev, 1, 1, 1); 467 return 0; 468 469urb_error: 470 flexcop_usb_transfer_exit(fc_usb); 471 return ret; 472} 473 474static 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 498static void flexcop_usb_exit(struct flexcop_usb *fc_usb) 499{ 500 usb_set_intfdata(fc_usb->uintf, NULL); 501} 502 503static 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 550err_fc_exit: 551 flexcop_device_exit(fc); 552err_usb_exit: 553 flexcop_usb_exit(fc_usb); 554err_kfree: 555 flexcop_device_kfree(fc); 556 return ret; 557} 558 559static 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 569static struct usb_device_id flexcop_usb_table [] = { 570 { USB_DEVICE(0x0af7, 0x0101) }, 571 { } 572}; 573MODULE_DEVICE_TABLE (usb, flexcop_usb_table); 574 575/* usb specific object needed to register this driver with the usb subsystem */ 576static 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 583module_usb_driver(flexcop_usb_driver); 584 585MODULE_AUTHOR(DRIVER_AUTHOR); 586MODULE_DESCRIPTION(DRIVER_NAME); 587MODULE_LICENSE("GPL"); 588