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