xref: /linux/drivers/media/usb/b2c2/flexcop-usb.c (revision 99e44da7928d4abb3028258ac3cd23a48495cd61)
13785bc17SMauro Carvalho Chehab /*
23785bc17SMauro Carvalho Chehab  * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
33785bc17SMauro Carvalho Chehab  * flexcop-usb.c - covers the USB part
43785bc17SMauro Carvalho Chehab  * see flexcop.c for copyright information
53785bc17SMauro Carvalho Chehab  */
63785bc17SMauro Carvalho Chehab #define FC_LOG_PREFIX "flexcop_usb"
73785bc17SMauro Carvalho Chehab #include "flexcop-usb.h"
83785bc17SMauro Carvalho Chehab #include "flexcop-common.h"
93785bc17SMauro Carvalho Chehab 
103785bc17SMauro Carvalho Chehab /* Version information */
113785bc17SMauro Carvalho Chehab #define DRIVER_VERSION "0.1"
123785bc17SMauro Carvalho Chehab #define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver"
13*99e44da7SPatrick Boettcher #define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@posteo.de>"
143785bc17SMauro Carvalho Chehab 
153785bc17SMauro Carvalho Chehab /* debug */
163785bc17SMauro Carvalho Chehab #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
173785bc17SMauro Carvalho Chehab #define dprintk(level,args...) \
183785bc17SMauro Carvalho Chehab 	do { if ((debug & level)) printk(args); } while (0)
193785bc17SMauro Carvalho Chehab 
203785bc17SMauro Carvalho Chehab #define debug_dump(b, l, method) do {\
213785bc17SMauro Carvalho Chehab 	int i; \
223785bc17SMauro Carvalho Chehab 	for (i = 0; i < l; i++) \
233785bc17SMauro Carvalho Chehab 		method("%02x ", b[i]); \
243785bc17SMauro Carvalho Chehab 	method("\n"); \
253785bc17SMauro Carvalho Chehab } while (0)
263785bc17SMauro Carvalho Chehab 
273785bc17SMauro Carvalho Chehab #define DEBSTATUS ""
283785bc17SMauro Carvalho Chehab #else
293785bc17SMauro Carvalho Chehab #define dprintk(level, args...)
303785bc17SMauro Carvalho Chehab #define debug_dump(b, l, method)
313785bc17SMauro Carvalho Chehab #define DEBSTATUS " (debugging is not enabled)"
323785bc17SMauro Carvalho Chehab #endif
333785bc17SMauro Carvalho Chehab 
343785bc17SMauro Carvalho Chehab static int debug;
353785bc17SMauro Carvalho Chehab module_param(debug, int, 0644);
363785bc17SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,"
373785bc17SMauro Carvalho Chehab 		"ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
383785bc17SMauro Carvalho Chehab #undef DEBSTATUS
393785bc17SMauro Carvalho Chehab 
403785bc17SMauro Carvalho Chehab #define deb_info(args...) dprintk(0x01, args)
413785bc17SMauro Carvalho Chehab #define deb_ts(args...) dprintk(0x02, args)
423785bc17SMauro Carvalho Chehab #define deb_ctrl(args...) dprintk(0x04, args)
433785bc17SMauro Carvalho Chehab #define deb_i2c(args...) dprintk(0x08, args)
443785bc17SMauro Carvalho Chehab #define deb_v8(args...) dprintk(0x10, args)
453785bc17SMauro Carvalho Chehab 
463785bc17SMauro Carvalho Chehab /* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
473785bc17SMauro Carvalho Chehab  * in the IBI address, to make the V8 code simpler.
483785bc17SMauro Carvalho Chehab  * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (the six bits used)
493785bc17SMauro Carvalho Chehab  *                  in general: 0000 0HHH 000L LL00
503785bc17SMauro Carvalho Chehab  * IBI ADDRESS FORMAT:                    RHHH BLLL
513785bc17SMauro Carvalho Chehab  *
523785bc17SMauro Carvalho Chehab  * where R is the read(1)/write(0) bit, B is the busy bit
533785bc17SMauro Carvalho Chehab  * and HHH and LLL are the two sets of three bits from the PCI address.
543785bc17SMauro Carvalho Chehab  */
553785bc17SMauro Carvalho Chehab #define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) \
563785bc17SMauro Carvalho Chehab 	(((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
573785bc17SMauro Carvalho Chehab #define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) \
583785bc17SMauro Carvalho Chehab 	(((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
593785bc17SMauro Carvalho Chehab 
603785bc17SMauro Carvalho Chehab /*
613785bc17SMauro Carvalho Chehab  * DKT 020228
623785bc17SMauro Carvalho Chehab  * - forget about this VENDOR_BUFFER_SIZE, read and write register
633785bc17SMauro Carvalho Chehab  *   deal with DWORD or 4 bytes, that should be should from now on
643785bc17SMauro Carvalho Chehab  * - from now on, we don't support anything older than firm 1.00
653785bc17SMauro Carvalho Chehab  *   I eliminated the write register as a 2 trip of writing hi word and lo word
663785bc17SMauro Carvalho Chehab  *   and force this to write only 4 bytes at a time.
673785bc17SMauro Carvalho Chehab  *   NOTE: this should work with all the firmware from 1.00 and newer
683785bc17SMauro Carvalho Chehab  */
693785bc17SMauro Carvalho Chehab static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read)
703785bc17SMauro Carvalho Chehab {
713785bc17SMauro Carvalho Chehab 	struct flexcop_usb *fc_usb = fc->bus_specific;
723785bc17SMauro Carvalho Chehab 	u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG;
733785bc17SMauro Carvalho Chehab 	u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR;
743785bc17SMauro Carvalho Chehab 	u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) |
753785bc17SMauro Carvalho Chehab 		(read ? 0x80 : 0);
763785bc17SMauro Carvalho Chehab 
773785bc17SMauro Carvalho Chehab 	int len = usb_control_msg(fc_usb->udev,
783785bc17SMauro Carvalho Chehab 			read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT,
793785bc17SMauro Carvalho Chehab 			request,
803785bc17SMauro Carvalho Chehab 			request_type, /* 0xc0 read or 0x40 write */
813785bc17SMauro Carvalho Chehab 			wAddress,
823785bc17SMauro Carvalho Chehab 			0,
833785bc17SMauro Carvalho Chehab 			val,
843785bc17SMauro Carvalho Chehab 			sizeof(u32),
853785bc17SMauro Carvalho Chehab 			B2C2_WAIT_FOR_OPERATION_RDW * HZ);
863785bc17SMauro Carvalho Chehab 
873785bc17SMauro Carvalho Chehab 	if (len != sizeof(u32)) {
883785bc17SMauro Carvalho Chehab 		err("error while %s dword from %d (%d).", read ? "reading" :
893785bc17SMauro Carvalho Chehab 				"writing", wAddress, wRegOffsPCI);
903785bc17SMauro Carvalho Chehab 		return -EIO;
913785bc17SMauro Carvalho Chehab 	}
923785bc17SMauro Carvalho Chehab 	return 0;
933785bc17SMauro Carvalho Chehab }
943785bc17SMauro Carvalho Chehab /*
953785bc17SMauro Carvalho Chehab  * DKT 010817 - add support for V8 memory read/write and flash update
963785bc17SMauro Carvalho Chehab  */
973785bc17SMauro Carvalho Chehab static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
983785bc17SMauro Carvalho Chehab 		flexcop_usb_request_t req, u8 page, u16 wAddress,
993785bc17SMauro Carvalho Chehab 		u8 *pbBuffer, u32 buflen)
1003785bc17SMauro Carvalho Chehab {
1013785bc17SMauro Carvalho Chehab 	u8 request_type = USB_TYPE_VENDOR;
1023785bc17SMauro Carvalho Chehab 	u16 wIndex;
1033785bc17SMauro Carvalho Chehab 	int nWaitTime, pipe, len;
1043785bc17SMauro Carvalho Chehab 	wIndex = page << 8;
1053785bc17SMauro Carvalho Chehab 
1063785bc17SMauro Carvalho Chehab 	switch (req) {
1073785bc17SMauro Carvalho Chehab 	case B2C2_USB_READ_V8_MEM:
1083785bc17SMauro Carvalho Chehab 		nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
1093785bc17SMauro Carvalho Chehab 		request_type |= USB_DIR_IN;
1103785bc17SMauro Carvalho Chehab 		pipe = B2C2_USB_CTRL_PIPE_IN;
1113785bc17SMauro Carvalho Chehab 		break;
1123785bc17SMauro Carvalho Chehab 	case B2C2_USB_WRITE_V8_MEM:
1133785bc17SMauro Carvalho Chehab 		wIndex |= pbBuffer[0];
1143785bc17SMauro Carvalho Chehab 		request_type |= USB_DIR_OUT;
1153785bc17SMauro Carvalho Chehab 		nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
1163785bc17SMauro Carvalho Chehab 		pipe = B2C2_USB_CTRL_PIPE_OUT;
1173785bc17SMauro Carvalho Chehab 		break;
1183785bc17SMauro Carvalho Chehab 	case B2C2_USB_FLASH_BLOCK:
1193785bc17SMauro Carvalho Chehab 		request_type |= USB_DIR_OUT;
1203785bc17SMauro Carvalho Chehab 		nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
1213785bc17SMauro Carvalho Chehab 		pipe = B2C2_USB_CTRL_PIPE_OUT;
1223785bc17SMauro Carvalho Chehab 		break;
1233785bc17SMauro Carvalho Chehab 	default:
1243785bc17SMauro Carvalho Chehab 		deb_info("unsupported request for v8_mem_req %x.\n", req);
1253785bc17SMauro Carvalho Chehab 		return -EINVAL;
1263785bc17SMauro Carvalho Chehab 	}
1273785bc17SMauro Carvalho Chehab 	deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n", request_type, req,
1283785bc17SMauro Carvalho Chehab 			wAddress, wIndex, buflen);
1293785bc17SMauro Carvalho Chehab 
1303785bc17SMauro Carvalho Chehab 	len = usb_control_msg(fc_usb->udev, pipe,
1313785bc17SMauro Carvalho Chehab 			req,
1323785bc17SMauro Carvalho Chehab 			request_type,
1333785bc17SMauro Carvalho Chehab 			wAddress,
1343785bc17SMauro Carvalho Chehab 			wIndex,
1353785bc17SMauro Carvalho Chehab 			pbBuffer,
1363785bc17SMauro Carvalho Chehab 			buflen,
1373785bc17SMauro Carvalho Chehab 			nWaitTime * HZ);
1383785bc17SMauro Carvalho Chehab 
1393785bc17SMauro Carvalho Chehab 	debug_dump(pbBuffer, len, deb_v8);
1403785bc17SMauro Carvalho Chehab 	return len == buflen ? 0 : -EIO;
1413785bc17SMauro Carvalho Chehab }
1423785bc17SMauro Carvalho Chehab 
1433785bc17SMauro Carvalho Chehab #define bytes_left_to_read_on_page(paddr,buflen) \
1443785bc17SMauro Carvalho Chehab 	((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \
1453785bc17SMauro Carvalho Chehab 	 ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)))
1463785bc17SMauro Carvalho Chehab 
1473785bc17SMauro Carvalho Chehab static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
1483785bc17SMauro Carvalho Chehab 		flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start,
1493785bc17SMauro Carvalho Chehab 		u32 addr, int extended, u8 *buf, u32 len)
1503785bc17SMauro Carvalho Chehab {
1513785bc17SMauro Carvalho Chehab 	int i,ret = 0;
1523785bc17SMauro Carvalho Chehab 	u16 wMax;
1533785bc17SMauro Carvalho Chehab 	u32 pagechunk = 0;
1543785bc17SMauro Carvalho Chehab 
1553785bc17SMauro Carvalho Chehab 	switch(req) {
1563785bc17SMauro Carvalho Chehab 	case B2C2_USB_READ_V8_MEM:
1573785bc17SMauro Carvalho Chehab 		wMax = USB_MEM_READ_MAX;
1583785bc17SMauro Carvalho Chehab 		break;
1593785bc17SMauro Carvalho Chehab 	case B2C2_USB_WRITE_V8_MEM:
1603785bc17SMauro Carvalho Chehab 		wMax = USB_MEM_WRITE_MAX;
1613785bc17SMauro Carvalho Chehab 		break;
1623785bc17SMauro Carvalho Chehab 	case B2C2_USB_FLASH_BLOCK:
1633785bc17SMauro Carvalho Chehab 		wMax = USB_FLASH_MAX;
1643785bc17SMauro Carvalho Chehab 		break;
1653785bc17SMauro Carvalho Chehab 	default:
1663785bc17SMauro Carvalho Chehab 		return -EINVAL;
1673785bc17SMauro Carvalho Chehab 		break;
1683785bc17SMauro Carvalho Chehab 	}
1693785bc17SMauro Carvalho Chehab 	for (i = 0; i < len;) {
1703785bc17SMauro Carvalho Chehab 		pagechunk =
1713785bc17SMauro Carvalho Chehab 			wMax < bytes_left_to_read_on_page(addr, len) ?
1723785bc17SMauro Carvalho Chehab 				wMax :
1733785bc17SMauro Carvalho Chehab 				bytes_left_to_read_on_page(addr, len);
1743785bc17SMauro Carvalho Chehab 		deb_info("%x\n",
1753785bc17SMauro Carvalho Chehab 			(addr & V8_MEMORY_PAGE_MASK) |
1763785bc17SMauro Carvalho Chehab 				(V8_MEMORY_EXTENDED*extended));
1773785bc17SMauro Carvalho Chehab 
1783785bc17SMauro Carvalho Chehab 		ret = flexcop_usb_v8_memory_req(fc_usb, req,
1793785bc17SMauro Carvalho Chehab 			page_start + (addr / V8_MEMORY_PAGE_SIZE),
1803785bc17SMauro Carvalho Chehab 			(addr & V8_MEMORY_PAGE_MASK) |
1813785bc17SMauro Carvalho Chehab 				(V8_MEMORY_EXTENDED*extended),
1823785bc17SMauro Carvalho Chehab 			&buf[i], pagechunk);
1833785bc17SMauro Carvalho Chehab 
1843785bc17SMauro Carvalho Chehab 		if (ret < 0)
1853785bc17SMauro Carvalho Chehab 			return ret;
1863785bc17SMauro Carvalho Chehab 		addr += pagechunk;
1873785bc17SMauro Carvalho Chehab 		len -= pagechunk;
1883785bc17SMauro Carvalho Chehab 	}
1893785bc17SMauro Carvalho Chehab 	return 0;
1903785bc17SMauro Carvalho Chehab }
1913785bc17SMauro Carvalho Chehab 
1923785bc17SMauro Carvalho Chehab static int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended)
1933785bc17SMauro Carvalho Chehab {
1943785bc17SMauro Carvalho Chehab 	return flexcop_usb_memory_req(fc->bus_specific, B2C2_USB_READ_V8_MEM,
1953785bc17SMauro Carvalho Chehab 		V8_MEMORY_PAGE_FLASH, 0x1f010, 1,
1963785bc17SMauro Carvalho Chehab 		fc->dvb_adapter.proposed_mac, 6);
1973785bc17SMauro Carvalho Chehab }
1983785bc17SMauro Carvalho Chehab 
1993785bc17SMauro Carvalho Chehab #if 0
2003785bc17SMauro Carvalho Chehab static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set,
2013785bc17SMauro Carvalho Chehab 		flexcop_usb_utility_function_t func, u8 extra, u16 wIndex,
2023785bc17SMauro Carvalho Chehab 		u16 buflen, u8 *pvBuffer)
2033785bc17SMauro Carvalho Chehab {
2043785bc17SMauro Carvalho Chehab 	u16 wValue;
2053785bc17SMauro Carvalho Chehab 	u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR;
2063785bc17SMauro Carvalho Chehab 	int nWaitTime = 2,
2073785bc17SMauro Carvalho Chehab 	    pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, len;
2083785bc17SMauro Carvalho Chehab 	wValue = (func << 8) | extra;
2093785bc17SMauro Carvalho Chehab 
2103785bc17SMauro Carvalho Chehab 	len = usb_control_msg(fc_usb->udev,pipe,
2113785bc17SMauro Carvalho Chehab 			B2C2_USB_UTILITY,
2123785bc17SMauro Carvalho Chehab 			request_type,
2133785bc17SMauro Carvalho Chehab 			wValue,
2143785bc17SMauro Carvalho Chehab 			wIndex,
2153785bc17SMauro Carvalho Chehab 			pvBuffer,
2163785bc17SMauro Carvalho Chehab 			buflen,
2173785bc17SMauro Carvalho Chehab 			nWaitTime * HZ);
2183785bc17SMauro Carvalho Chehab 	return len == buflen ? 0 : -EIO;
2193785bc17SMauro Carvalho Chehab }
2203785bc17SMauro Carvalho Chehab #endif
2213785bc17SMauro Carvalho Chehab 
2223785bc17SMauro Carvalho Chehab /* usb i2c stuff */
2233785bc17SMauro Carvalho Chehab static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
2243785bc17SMauro Carvalho Chehab 		flexcop_usb_request_t req, flexcop_usb_i2c_function_t func,
2253785bc17SMauro Carvalho Chehab 		u8 chipaddr, u8 addr, u8 *buf, u8 buflen)
2263785bc17SMauro Carvalho Chehab {
2273785bc17SMauro Carvalho Chehab 	struct flexcop_usb *fc_usb = i2c->fc->bus_specific;
2283785bc17SMauro Carvalho Chehab 	u16 wValue, wIndex;
2293785bc17SMauro Carvalho Chehab 	int nWaitTime,pipe,len;
2303785bc17SMauro Carvalho Chehab 	u8 request_type = USB_TYPE_VENDOR;
2313785bc17SMauro Carvalho Chehab 
2323785bc17SMauro Carvalho Chehab 	switch (func) {
2333785bc17SMauro Carvalho Chehab 	case USB_FUNC_I2C_WRITE:
2343785bc17SMauro Carvalho Chehab 	case USB_FUNC_I2C_MULTIWRITE:
2353785bc17SMauro Carvalho Chehab 	case USB_FUNC_I2C_REPEATWRITE:
2363785bc17SMauro Carvalho Chehab 		/* DKT 020208 - add this to support special case of DiSEqC */
2373785bc17SMauro Carvalho Chehab 	case USB_FUNC_I2C_CHECKWRITE:
2383785bc17SMauro Carvalho Chehab 		pipe = B2C2_USB_CTRL_PIPE_OUT;
2393785bc17SMauro Carvalho Chehab 		nWaitTime = 2;
2403785bc17SMauro Carvalho Chehab 		request_type |= USB_DIR_OUT;
2413785bc17SMauro Carvalho Chehab 		break;
2423785bc17SMauro Carvalho Chehab 	case USB_FUNC_I2C_READ:
2433785bc17SMauro Carvalho Chehab 	case USB_FUNC_I2C_REPEATREAD:
2443785bc17SMauro Carvalho Chehab 		pipe = B2C2_USB_CTRL_PIPE_IN;
2453785bc17SMauro Carvalho Chehab 		nWaitTime = 2;
2463785bc17SMauro Carvalho Chehab 		request_type |= USB_DIR_IN;
2473785bc17SMauro Carvalho Chehab 		break;
2483785bc17SMauro Carvalho Chehab 	default:
2493785bc17SMauro Carvalho Chehab 		deb_info("unsupported function for i2c_req %x\n", func);
2503785bc17SMauro Carvalho Chehab 		return -EINVAL;
2513785bc17SMauro Carvalho Chehab 	}
2523785bc17SMauro Carvalho Chehab 	wValue = (func << 8) | (i2c->port << 4);
2533785bc17SMauro Carvalho Chehab 	wIndex = (chipaddr << 8 ) | addr;
2543785bc17SMauro Carvalho Chehab 
2553785bc17SMauro Carvalho Chehab 	deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",
2563785bc17SMauro Carvalho Chehab 			func, request_type, req,
2573785bc17SMauro Carvalho Chehab 			wValue & 0xff, wValue >> 8,
2583785bc17SMauro Carvalho Chehab 			wIndex & 0xff, wIndex >> 8);
2593785bc17SMauro Carvalho Chehab 
2603785bc17SMauro Carvalho Chehab 	len = usb_control_msg(fc_usb->udev,pipe,
2613785bc17SMauro Carvalho Chehab 			req,
2623785bc17SMauro Carvalho Chehab 			request_type,
2633785bc17SMauro Carvalho Chehab 			wValue,
2643785bc17SMauro Carvalho Chehab 			wIndex,
2653785bc17SMauro Carvalho Chehab 			buf,
2663785bc17SMauro Carvalho Chehab 			buflen,
2673785bc17SMauro Carvalho Chehab 			nWaitTime * HZ);
2683785bc17SMauro Carvalho Chehab 	return len == buflen ? 0 : -EREMOTEIO;
2693785bc17SMauro Carvalho Chehab }
2703785bc17SMauro Carvalho Chehab 
2713785bc17SMauro Carvalho Chehab /* actual bus specific access functions,
2723785bc17SMauro Carvalho Chehab    make sure prototype are/will be equal to pci */
2733785bc17SMauro Carvalho Chehab static flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc,
2743785bc17SMauro Carvalho Chehab 	flexcop_ibi_register reg)
2753785bc17SMauro Carvalho Chehab {
2763785bc17SMauro Carvalho Chehab 	flexcop_ibi_value val;
2773785bc17SMauro Carvalho Chehab 	val.raw = 0;
2783785bc17SMauro Carvalho Chehab 	flexcop_usb_readwrite_dw(fc, reg, &val.raw, 1);
2793785bc17SMauro Carvalho Chehab 	return val;
2803785bc17SMauro Carvalho Chehab }
2813785bc17SMauro Carvalho Chehab 
2823785bc17SMauro Carvalho Chehab static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc,
2833785bc17SMauro Carvalho Chehab 		flexcop_ibi_register reg, flexcop_ibi_value val)
2843785bc17SMauro Carvalho Chehab {
2853785bc17SMauro Carvalho Chehab 	return flexcop_usb_readwrite_dw(fc, reg, &val.raw, 0);
2863785bc17SMauro Carvalho Chehab }
2873785bc17SMauro Carvalho Chehab 
2883785bc17SMauro Carvalho Chehab static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c,
2893785bc17SMauro Carvalho Chehab 		flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
2903785bc17SMauro Carvalho Chehab {
2913785bc17SMauro Carvalho Chehab 	if (op == FC_READ)
2923785bc17SMauro Carvalho Chehab 		return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
2933785bc17SMauro Carvalho Chehab 				USB_FUNC_I2C_READ, chipaddr, addr, buf, len);
2943785bc17SMauro Carvalho Chehab 	else
2953785bc17SMauro Carvalho Chehab 		return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
2963785bc17SMauro Carvalho Chehab 				USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len);
2973785bc17SMauro Carvalho Chehab }
2983785bc17SMauro Carvalho Chehab 
2993785bc17SMauro Carvalho Chehab static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb,
3003785bc17SMauro Carvalho Chehab 	u8 *buffer, int buffer_length)
3013785bc17SMauro Carvalho Chehab {
3023785bc17SMauro Carvalho Chehab 	u8 *b;
3033785bc17SMauro Carvalho Chehab 	int l;
3043785bc17SMauro Carvalho Chehab 
3053785bc17SMauro Carvalho Chehab 	deb_ts("tmp_buffer_length=%d, buffer_length=%d\n",
3063785bc17SMauro Carvalho Chehab 		fc_usb->tmp_buffer_length, buffer_length);
3073785bc17SMauro Carvalho Chehab 
3083785bc17SMauro Carvalho Chehab 	if (fc_usb->tmp_buffer_length > 0) {
3093785bc17SMauro Carvalho Chehab 		memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer,
3103785bc17SMauro Carvalho Chehab 				buffer_length);
3113785bc17SMauro Carvalho Chehab 		fc_usb->tmp_buffer_length += buffer_length;
3123785bc17SMauro Carvalho Chehab 		b = fc_usb->tmp_buffer;
3133785bc17SMauro Carvalho Chehab 		l = fc_usb->tmp_buffer_length;
3143785bc17SMauro Carvalho Chehab 	} else {
3153785bc17SMauro Carvalho Chehab 		b=buffer;
3163785bc17SMauro Carvalho Chehab 		l=buffer_length;
3173785bc17SMauro Carvalho Chehab 	}
3183785bc17SMauro Carvalho Chehab 
3193785bc17SMauro Carvalho Chehab 	while (l >= 190) {
3203785bc17SMauro Carvalho Chehab 		if (*b == 0xff) {
3213785bc17SMauro Carvalho Chehab 			switch (*(b+1) & 0x03) {
3223785bc17SMauro Carvalho Chehab 			case 0x01: /* media packet */
3233785bc17SMauro Carvalho Chehab 				if (*(b+2) == 0x47)
3243785bc17SMauro Carvalho Chehab 					flexcop_pass_dmx_packets(
3253785bc17SMauro Carvalho Chehab 							fc_usb->fc_dev, b+2, 1);
3263785bc17SMauro Carvalho Chehab 				else
3273785bc17SMauro Carvalho Chehab 					deb_ts("not ts packet %*ph\n", 4, b+2);
3283785bc17SMauro Carvalho Chehab 				b += 190;
3293785bc17SMauro Carvalho Chehab 				l -= 190;
3303785bc17SMauro Carvalho Chehab 				break;
3313785bc17SMauro Carvalho Chehab 			default:
3323785bc17SMauro Carvalho Chehab 				deb_ts("wrong packet type\n");
3333785bc17SMauro Carvalho Chehab 				l = 0;
3343785bc17SMauro Carvalho Chehab 				break;
3353785bc17SMauro Carvalho Chehab 			}
3363785bc17SMauro Carvalho Chehab 		} else {
3373785bc17SMauro Carvalho Chehab 			deb_ts("wrong header\n");
3383785bc17SMauro Carvalho Chehab 			l = 0;
3393785bc17SMauro Carvalho Chehab 		}
3403785bc17SMauro Carvalho Chehab 	}
3413785bc17SMauro Carvalho Chehab 
3423785bc17SMauro Carvalho Chehab 	if (l>0)
3433785bc17SMauro Carvalho Chehab 		memcpy(fc_usb->tmp_buffer, b, l);
3443785bc17SMauro Carvalho Chehab 	fc_usb->tmp_buffer_length = l;
3453785bc17SMauro Carvalho Chehab }
3463785bc17SMauro Carvalho Chehab 
3473785bc17SMauro Carvalho Chehab static void flexcop_usb_urb_complete(struct urb *urb)
3483785bc17SMauro Carvalho Chehab {
3493785bc17SMauro Carvalho Chehab 	struct flexcop_usb *fc_usb = urb->context;
3503785bc17SMauro Carvalho Chehab 	int i;
3513785bc17SMauro Carvalho Chehab 
3523785bc17SMauro Carvalho Chehab 	if (urb->actual_length > 0)
3533785bc17SMauro Carvalho Chehab 		deb_ts("urb completed, bufsize: %d actlen; %d\n",
3543785bc17SMauro Carvalho Chehab 			urb->transfer_buffer_length, urb->actual_length);
3553785bc17SMauro Carvalho Chehab 
3563785bc17SMauro Carvalho Chehab 	for (i = 0; i < urb->number_of_packets; i++) {
3573785bc17SMauro Carvalho Chehab 		if (urb->iso_frame_desc[i].status < 0) {
3583785bc17SMauro Carvalho Chehab 			err("iso frame descriptor %d has an error: %d\n", i,
3593785bc17SMauro Carvalho Chehab 				urb->iso_frame_desc[i].status);
3603785bc17SMauro Carvalho Chehab 		} else
3613785bc17SMauro Carvalho Chehab 			if (urb->iso_frame_desc[i].actual_length > 0) {
3623785bc17SMauro Carvalho Chehab 				deb_ts("passed %d bytes to the demux\n",
3633785bc17SMauro Carvalho Chehab 					urb->iso_frame_desc[i].actual_length);
3643785bc17SMauro Carvalho Chehab 
3653785bc17SMauro Carvalho Chehab 				flexcop_usb_process_frame(fc_usb,
3663785bc17SMauro Carvalho Chehab 					urb->transfer_buffer +
3673785bc17SMauro Carvalho Chehab 						urb->iso_frame_desc[i].offset,
3683785bc17SMauro Carvalho Chehab 					urb->iso_frame_desc[i].actual_length);
3693785bc17SMauro Carvalho Chehab 			}
3703785bc17SMauro Carvalho Chehab 		urb->iso_frame_desc[i].status = 0;
3713785bc17SMauro Carvalho Chehab 		urb->iso_frame_desc[i].actual_length = 0;
3723785bc17SMauro Carvalho Chehab 	}
3733785bc17SMauro Carvalho Chehab 	usb_submit_urb(urb,GFP_ATOMIC);
3743785bc17SMauro Carvalho Chehab }
3753785bc17SMauro Carvalho Chehab 
3763785bc17SMauro Carvalho Chehab static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff)
3773785bc17SMauro Carvalho Chehab {
3783785bc17SMauro Carvalho Chehab 	/* submit/kill iso packets */
3793785bc17SMauro Carvalho Chehab 	return 0;
3803785bc17SMauro Carvalho Chehab }
3813785bc17SMauro Carvalho Chehab 
3823785bc17SMauro Carvalho Chehab static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
3833785bc17SMauro Carvalho Chehab {
3843785bc17SMauro Carvalho Chehab 	int i;
3853785bc17SMauro Carvalho Chehab 	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
3863785bc17SMauro Carvalho Chehab 		if (fc_usb->iso_urb[i] != NULL) {
3873785bc17SMauro Carvalho Chehab 			deb_ts("unlinking/killing urb no. %d\n",i);
3883785bc17SMauro Carvalho Chehab 			usb_kill_urb(fc_usb->iso_urb[i]);
3893785bc17SMauro Carvalho Chehab 			usb_free_urb(fc_usb->iso_urb[i]);
3903785bc17SMauro Carvalho Chehab 		}
3913785bc17SMauro Carvalho Chehab 
3923785bc17SMauro Carvalho Chehab 	if (fc_usb->iso_buffer != NULL)
3936c7e3469SChen Gang 		usb_free_coherent(fc_usb->udev,
3943785bc17SMauro Carvalho Chehab 			fc_usb->buffer_size, fc_usb->iso_buffer,
3953785bc17SMauro Carvalho Chehab 			fc_usb->dma_addr);
3963785bc17SMauro Carvalho Chehab }
3973785bc17SMauro Carvalho Chehab 
3983785bc17SMauro Carvalho Chehab static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
3993785bc17SMauro Carvalho Chehab {
4003785bc17SMauro Carvalho Chehab 	u16 frame_size = le16_to_cpu(
4013785bc17SMauro Carvalho Chehab 		fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
4023785bc17SMauro Carvalho Chehab 	int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO *
4033785bc17SMauro Carvalho Chehab 		frame_size, i, j, ret;
4043785bc17SMauro Carvalho Chehab 	int buffer_offset = 0;
4053785bc17SMauro Carvalho Chehab 
4063785bc17SMauro Carvalho Chehab 	deb_ts("creating %d iso-urbs with %d frames "
4073785bc17SMauro Carvalho Chehab 			"each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB,
4083785bc17SMauro Carvalho Chehab 			B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize);
4093785bc17SMauro Carvalho Chehab 
4106c7e3469SChen Gang 	fc_usb->iso_buffer = usb_alloc_coherent(fc_usb->udev,
4116c7e3469SChen Gang 			bufsize, GFP_KERNEL, &fc_usb->dma_addr);
4123785bc17SMauro Carvalho Chehab 	if (fc_usb->iso_buffer == NULL)
4133785bc17SMauro Carvalho Chehab 		return -ENOMEM;
4143785bc17SMauro Carvalho Chehab 
4153785bc17SMauro Carvalho Chehab 	memset(fc_usb->iso_buffer, 0, bufsize);
4163785bc17SMauro Carvalho Chehab 	fc_usb->buffer_size = bufsize;
4173785bc17SMauro Carvalho Chehab 
4183785bc17SMauro Carvalho Chehab 	/* creating iso urbs */
4193785bc17SMauro Carvalho Chehab 	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
4203785bc17SMauro Carvalho Chehab 		fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,
4213785bc17SMauro Carvalho Chehab 			GFP_ATOMIC);
4223785bc17SMauro Carvalho Chehab 		if (fc_usb->iso_urb[i] == NULL) {
4233785bc17SMauro Carvalho Chehab 			ret = -ENOMEM;
4243785bc17SMauro Carvalho Chehab 			goto urb_error;
4253785bc17SMauro Carvalho Chehab 		}
4263785bc17SMauro Carvalho Chehab 	}
4273785bc17SMauro Carvalho Chehab 
4283785bc17SMauro Carvalho Chehab 	/* initialising and submitting iso urbs */
4293785bc17SMauro Carvalho Chehab 	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
4303785bc17SMauro Carvalho Chehab 		int frame_offset = 0;
4313785bc17SMauro Carvalho Chehab 		struct urb *urb = fc_usb->iso_urb[i];
4323785bc17SMauro Carvalho Chehab 		deb_ts("initializing and submitting urb no. %d "
4333785bc17SMauro Carvalho Chehab 			"(buf_offset: %d).\n", i, buffer_offset);
4343785bc17SMauro Carvalho Chehab 
4353785bc17SMauro Carvalho Chehab 		urb->dev = fc_usb->udev;
4363785bc17SMauro Carvalho Chehab 		urb->context = fc_usb;
4373785bc17SMauro Carvalho Chehab 		urb->complete = flexcop_usb_urb_complete;
4383785bc17SMauro Carvalho Chehab 		urb->pipe = B2C2_USB_DATA_PIPE;
4393785bc17SMauro Carvalho Chehab 		urb->transfer_flags = URB_ISO_ASAP;
4403785bc17SMauro Carvalho Chehab 		urb->interval = 1;
4413785bc17SMauro Carvalho Chehab 		urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO;
4423785bc17SMauro Carvalho Chehab 		urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO;
4433785bc17SMauro Carvalho Chehab 		urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset;
4443785bc17SMauro Carvalho Chehab 
4453785bc17SMauro Carvalho Chehab 		buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
4463785bc17SMauro Carvalho Chehab 		for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
4473785bc17SMauro Carvalho Chehab 			deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",
4483785bc17SMauro Carvalho Chehab 					i, j, frame_offset);
4493785bc17SMauro Carvalho Chehab 			urb->iso_frame_desc[j].offset = frame_offset;
4503785bc17SMauro Carvalho Chehab 			urb->iso_frame_desc[j].length = frame_size;
4513785bc17SMauro Carvalho Chehab 			frame_offset += frame_size;
4523785bc17SMauro Carvalho Chehab 		}
4533785bc17SMauro Carvalho Chehab 
4543785bc17SMauro Carvalho Chehab 		if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) {
4553785bc17SMauro Carvalho Chehab 			err("submitting urb %d failed with %d.", i, ret);
4563785bc17SMauro Carvalho Chehab 			goto urb_error;
4573785bc17SMauro Carvalho Chehab 		}
4583785bc17SMauro Carvalho Chehab 		deb_ts("submitted urb no. %d.\n",i);
4593785bc17SMauro Carvalho Chehab 	}
4603785bc17SMauro Carvalho Chehab 
4613785bc17SMauro Carvalho Chehab 	/* SRAM */
4623785bc17SMauro Carvalho Chehab 	flexcop_sram_set_dest(fc_usb->fc_dev, FC_SRAM_DEST_MEDIA |
4633785bc17SMauro Carvalho Chehab 			FC_SRAM_DEST_NET | FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI,
4643785bc17SMauro Carvalho Chehab 			FC_SRAM_DEST_TARGET_WAN_USB);
4653785bc17SMauro Carvalho Chehab 	flexcop_wan_set_speed(fc_usb->fc_dev, FC_WAN_SPEED_8MBITS);
4663785bc17SMauro Carvalho Chehab 	flexcop_sram_ctrl(fc_usb->fc_dev, 1, 1, 1);
4673785bc17SMauro Carvalho Chehab 	return 0;
4683785bc17SMauro Carvalho Chehab 
4693785bc17SMauro Carvalho Chehab urb_error:
4703785bc17SMauro Carvalho Chehab 	flexcop_usb_transfer_exit(fc_usb);
4713785bc17SMauro Carvalho Chehab 	return ret;
4723785bc17SMauro Carvalho Chehab }
4733785bc17SMauro Carvalho Chehab 
4743785bc17SMauro Carvalho Chehab static int flexcop_usb_init(struct flexcop_usb *fc_usb)
4753785bc17SMauro Carvalho Chehab {
4763785bc17SMauro Carvalho Chehab 	/* use the alternate setting with the larges buffer */
4773785bc17SMauro Carvalho Chehab 	usb_set_interface(fc_usb->udev,0,1);
4783785bc17SMauro Carvalho Chehab 	switch (fc_usb->udev->speed) {
4793785bc17SMauro Carvalho Chehab 	case USB_SPEED_LOW:
4803785bc17SMauro Carvalho Chehab 		err("cannot handle USB speed because it is too slow.");
4813785bc17SMauro Carvalho Chehab 		return -ENODEV;
4823785bc17SMauro Carvalho Chehab 		break;
4833785bc17SMauro Carvalho Chehab 	case USB_SPEED_FULL:
4843785bc17SMauro Carvalho Chehab 		info("running at FULL speed.");
4853785bc17SMauro Carvalho Chehab 		break;
4863785bc17SMauro Carvalho Chehab 	case USB_SPEED_HIGH:
4873785bc17SMauro Carvalho Chehab 		info("running at HIGH speed.");
4883785bc17SMauro Carvalho Chehab 		break;
4893785bc17SMauro Carvalho Chehab 	case USB_SPEED_UNKNOWN: /* fall through */
4903785bc17SMauro Carvalho Chehab 	default:
4913785bc17SMauro Carvalho Chehab 		err("cannot handle USB speed because it is unknown.");
4923785bc17SMauro Carvalho Chehab 		return -ENODEV;
4933785bc17SMauro Carvalho Chehab 	}
4943785bc17SMauro Carvalho Chehab 	usb_set_intfdata(fc_usb->uintf, fc_usb);
4953785bc17SMauro Carvalho Chehab 	return 0;
4963785bc17SMauro Carvalho Chehab }
4973785bc17SMauro Carvalho Chehab 
4983785bc17SMauro Carvalho Chehab static void flexcop_usb_exit(struct flexcop_usb *fc_usb)
4993785bc17SMauro Carvalho Chehab {
5003785bc17SMauro Carvalho Chehab 	usb_set_intfdata(fc_usb->uintf, NULL);
5013785bc17SMauro Carvalho Chehab }
5023785bc17SMauro Carvalho Chehab 
5033785bc17SMauro Carvalho Chehab static int flexcop_usb_probe(struct usb_interface *intf,
5043785bc17SMauro Carvalho Chehab 		const struct usb_device_id *id)
5053785bc17SMauro Carvalho Chehab {
5063785bc17SMauro Carvalho Chehab 	struct usb_device *udev = interface_to_usbdev(intf);
5073785bc17SMauro Carvalho Chehab 	struct flexcop_usb *fc_usb = NULL;
5083785bc17SMauro Carvalho Chehab 	struct flexcop_device *fc = NULL;
5093785bc17SMauro Carvalho Chehab 	int ret;
5103785bc17SMauro Carvalho Chehab 
5113785bc17SMauro Carvalho Chehab 	if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) {
5123785bc17SMauro Carvalho Chehab 		err("out of memory\n");
5133785bc17SMauro Carvalho Chehab 		return -ENOMEM;
5143785bc17SMauro Carvalho Chehab 	}
5153785bc17SMauro Carvalho Chehab 
5163785bc17SMauro Carvalho Chehab 	/* general flexcop init */
5173785bc17SMauro Carvalho Chehab 	fc_usb = fc->bus_specific;
5183785bc17SMauro Carvalho Chehab 	fc_usb->fc_dev = fc;
5193785bc17SMauro Carvalho Chehab 
5203785bc17SMauro Carvalho Chehab 	fc->read_ibi_reg  = flexcop_usb_read_ibi_reg;
5213785bc17SMauro Carvalho Chehab 	fc->write_ibi_reg = flexcop_usb_write_ibi_reg;
5223785bc17SMauro Carvalho Chehab 	fc->i2c_request = flexcop_usb_i2c_request;
5233785bc17SMauro Carvalho Chehab 	fc->get_mac_addr = flexcop_usb_get_mac_addr;
5243785bc17SMauro Carvalho Chehab 
5253785bc17SMauro Carvalho Chehab 	fc->stream_control = flexcop_usb_stream_control;
5263785bc17SMauro Carvalho Chehab 
5273785bc17SMauro Carvalho Chehab 	fc->pid_filtering = 1;
5283785bc17SMauro Carvalho Chehab 	fc->bus_type = FC_USB;
5293785bc17SMauro Carvalho Chehab 
5303785bc17SMauro Carvalho Chehab 	fc->dev = &udev->dev;
5313785bc17SMauro Carvalho Chehab 	fc->owner = THIS_MODULE;
5323785bc17SMauro Carvalho Chehab 
5333785bc17SMauro Carvalho Chehab 	/* bus specific part */
5343785bc17SMauro Carvalho Chehab 	fc_usb->udev = udev;
5353785bc17SMauro Carvalho Chehab 	fc_usb->uintf = intf;
5363785bc17SMauro Carvalho Chehab 	if ((ret = flexcop_usb_init(fc_usb)) != 0)
5373785bc17SMauro Carvalho Chehab 		goto err_kfree;
5383785bc17SMauro Carvalho Chehab 
5393785bc17SMauro Carvalho Chehab 	/* init flexcop */
5403785bc17SMauro Carvalho Chehab 	if ((ret = flexcop_device_initialize(fc)) != 0)
5413785bc17SMauro Carvalho Chehab 		goto err_usb_exit;
5423785bc17SMauro Carvalho Chehab 
5433785bc17SMauro Carvalho Chehab 	/* xfer init */
5443785bc17SMauro Carvalho Chehab 	if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0)
5453785bc17SMauro Carvalho Chehab 		goto err_fc_exit;
5463785bc17SMauro Carvalho Chehab 
5473785bc17SMauro Carvalho Chehab 	info("%s successfully initialized and connected.", DRIVER_NAME);
5483785bc17SMauro Carvalho Chehab 	return 0;
5493785bc17SMauro Carvalho Chehab 
5503785bc17SMauro Carvalho Chehab err_fc_exit:
5513785bc17SMauro Carvalho Chehab 	flexcop_device_exit(fc);
5523785bc17SMauro Carvalho Chehab err_usb_exit:
5533785bc17SMauro Carvalho Chehab 	flexcop_usb_exit(fc_usb);
5543785bc17SMauro Carvalho Chehab err_kfree:
5553785bc17SMauro Carvalho Chehab 	flexcop_device_kfree(fc);
5563785bc17SMauro Carvalho Chehab 	return ret;
5573785bc17SMauro Carvalho Chehab }
5583785bc17SMauro Carvalho Chehab 
5593785bc17SMauro Carvalho Chehab static void flexcop_usb_disconnect(struct usb_interface *intf)
5603785bc17SMauro Carvalho Chehab {
5613785bc17SMauro Carvalho Chehab 	struct flexcop_usb *fc_usb = usb_get_intfdata(intf);
5623785bc17SMauro Carvalho Chehab 	flexcop_usb_transfer_exit(fc_usb);
5633785bc17SMauro Carvalho Chehab 	flexcop_device_exit(fc_usb->fc_dev);
5643785bc17SMauro Carvalho Chehab 	flexcop_usb_exit(fc_usb);
5653785bc17SMauro Carvalho Chehab 	flexcop_device_kfree(fc_usb->fc_dev);
5663785bc17SMauro Carvalho Chehab 	info("%s successfully deinitialized and disconnected.", DRIVER_NAME);
5673785bc17SMauro Carvalho Chehab }
5683785bc17SMauro Carvalho Chehab 
5693785bc17SMauro Carvalho Chehab static struct usb_device_id flexcop_usb_table [] = {
5703785bc17SMauro Carvalho Chehab 	{ USB_DEVICE(0x0af7, 0x0101) },
5713785bc17SMauro Carvalho Chehab 	{ }
5723785bc17SMauro Carvalho Chehab };
5733785bc17SMauro Carvalho Chehab MODULE_DEVICE_TABLE (usb, flexcop_usb_table);
5743785bc17SMauro Carvalho Chehab 
5753785bc17SMauro Carvalho Chehab /* usb specific object needed to register this driver with the usb subsystem */
5763785bc17SMauro Carvalho Chehab static struct usb_driver flexcop_usb_driver = {
5773785bc17SMauro Carvalho Chehab 	.name		= "b2c2_flexcop_usb",
5783785bc17SMauro Carvalho Chehab 	.probe		= flexcop_usb_probe,
5793785bc17SMauro Carvalho Chehab 	.disconnect = flexcop_usb_disconnect,
5803785bc17SMauro Carvalho Chehab 	.id_table	= flexcop_usb_table,
5813785bc17SMauro Carvalho Chehab };
5823785bc17SMauro Carvalho Chehab 
5833785bc17SMauro Carvalho Chehab module_usb_driver(flexcop_usb_driver);
5843785bc17SMauro Carvalho Chehab 
5853785bc17SMauro Carvalho Chehab MODULE_AUTHOR(DRIVER_AUTHOR);
5863785bc17SMauro Carvalho Chehab MODULE_DESCRIPTION(DRIVER_NAME);
5873785bc17SMauro Carvalho Chehab MODULE_LICENSE("GPL");
588