cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

flexcop-usb.c (16848B)


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