12add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach/*
291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla * flexcop-usb.c - covers the USB part
491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla * see flexcop.c for copyright information
52add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach */
62add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#define FC_LOG_PREFIX "flexcop_usb"
72add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#include "flexcop-usb.h"
82add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#include "flexcop-common.h"
92add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
102add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach/* Version information */
112add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#define DRIVER_VERSION "0.1"
122add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV USB Driver"
132add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de>"
142add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
152add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach/* debug */
162add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
172add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#define dprintk(level,args...) \
1891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	do { if ((debug & level)) printk(args); } while (0)
1991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla
2091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla#define debug_dump(b, l, method) do {\
212add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	int i; \
2291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	for (i = 0; i < l; i++) \
2391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		method("%02x ", b[i]); \
2491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	method("\n"); \
2591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla} while (0)
262add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
272add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#define DEBSTATUS ""
282add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#else
2991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla#define dprintk(level, args...)
3091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla#define debug_dump(b, l, method)
312add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#define DEBSTATUS " (debugging is not enabled)"
322add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#endif
332add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
342add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachstatic int debug;
352add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachmodule_param(debug, int, 0644);
3691b94366260fc4d960713c2e76e0fc874ff76992Uwe BuglaMODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,"
3791b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		"ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS);
382add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#undef DEBSTATUS
392add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
4091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla#define deb_info(args...) dprintk(0x01, args)
4191b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla#define deb_ts(args...) dprintk(0x02, args)
4291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla#define deb_ctrl(args...) dprintk(0x04, args)
4391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla#define deb_i2c(args...) dprintk(0x08, args)
4491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla#define deb_v8(args...) dprintk(0x10, args)
452add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
462add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach/* JLP 111700: we will include the 1 bit gap between the upper and lower 3 bits
472add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach * in the IBI address, to make the V8 code simpler.
4891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla * PCI ADDRESS FORMAT: 0x71C -> 0000 0111 0001 1100 (the six bits used)
492add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach *                  in general: 0000 0HHH 000L LL00
502add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach * IBI ADDRESS FORMAT:                    RHHH BLLL
512add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach *
522add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach * where R is the read(1)/write(0) bit, B is the busy bit
532add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach * and HHH and LLL are the two sets of three bits from the PCI address.
542add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach */
5591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla#define B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(usPCI) (u8) \
5691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	(((usPCI >> 2) & 0x07) + ((usPCI >> 4) & 0x70))
5791b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla#define B2C2_FLEX_INTERNALADDR_TO_PCIOFFSET(ucAddr) (u16) \
5891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	(((ucAddr & 0x07) << 2) + ((ucAddr & 0x70) << 4))
592add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
602add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach/*
612add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach * DKT 020228
622add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach * - forget about this VENDOR_BUFFER_SIZE, read and write register
632add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach *   deal with DWORD or 4 bytes, that should be should from now on
642add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach * - from now on, we don't support anything older than firm 1.00
652add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach *   I eliminated the write register as a 2 trip of writing hi word and lo word
662add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach *   and force this to write only 4 bytes at a time.
672add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach *   NOTE: this should work with all the firmware from 1.00 and newer
682add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach */
692add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachstatic int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, u32 *val, u8 read)
702add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
712add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	struct flexcop_usb *fc_usb = fc->bus_specific;
722add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	u8 request = read ? B2C2_USB_READ_REG : B2C2_USB_WRITE_REG;
732add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	u8 request_type = (read ? USB_DIR_IN : USB_DIR_OUT) | USB_TYPE_VENDOR;
7491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	u8 wAddress = B2C2_FLEX_PCIOFFSET_TO_INTERNALADDR(wRegOffsPCI) |
7591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		(read ? 0x80 : 0);
762add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
772add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	int len = usb_control_msg(fc_usb->udev,
782add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			read ? B2C2_USB_CTRL_PIPE_IN : B2C2_USB_CTRL_PIPE_OUT,
792add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			request,
8091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			request_type, /* 0xc0 read or 0x40 write */
812add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			wAddress,
822add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			0,
832add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			val,
842add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			sizeof(u32),
852add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			B2C2_WAIT_FOR_OPERATION_RDW * HZ);
862add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
872add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	if (len != sizeof(u32)) {
8891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		err("error while %s dword from %d (%d).", read ? "reading" :
8991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				"writing", wAddress, wRegOffsPCI);
902add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		return -EIO;
912add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	}
922add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	return 0;
932add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
942add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach/*
952add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach * DKT 010817 - add support for V8 memory read/write and flash update
962add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach */
972add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachstatic int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb,
982add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		flexcop_usb_request_t req, u8 page, u16 wAddress,
9991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		u8 *pbBuffer, u32 buflen)
1002add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
1012add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	u8 request_type = USB_TYPE_VENDOR;
1022add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	u16 wIndex;
10391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	int nWaitTime, pipe, len;
1042add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	wIndex = page << 8;
1052add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
1062add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	switch (req) {
10791b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case B2C2_USB_READ_V8_MEM:
10891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		nWaitTime = B2C2_WAIT_FOR_OPERATION_V8READ;
10991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		request_type |= USB_DIR_IN;
11091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		pipe = B2C2_USB_CTRL_PIPE_IN;
1112add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		break;
11291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case B2C2_USB_WRITE_V8_MEM:
11391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		wIndex |= pbBuffer[0];
11491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		request_type |= USB_DIR_OUT;
11591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		nWaitTime = B2C2_WAIT_FOR_OPERATION_V8WRITE;
11691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		pipe = B2C2_USB_CTRL_PIPE_OUT;
1172add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		break;
11891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case B2C2_USB_FLASH_BLOCK:
11991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		request_type |= USB_DIR_OUT;
12091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		nWaitTime = B2C2_WAIT_FOR_OPERATION_V8FLASH;
12191b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		pipe = B2C2_USB_CTRL_PIPE_OUT;
1222add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		break;
12391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	default:
12491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		deb_info("unsupported request for v8_mem_req %x.\n", req);
1252add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		return -EINVAL;
1262add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	}
12791b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	deb_v8("v8mem: %02x %02x %04x %04x, len: %d\n", request_type, req,
12891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			wAddress, wIndex, buflen);
1292add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
13091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	len = usb_control_msg(fc_usb->udev, pipe,
1312add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			req,
1322add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			request_type,
1332add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			wAddress,
1342add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			wIndex,
1352add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			pbBuffer,
1362add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			buflen,
1372add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			nWaitTime * HZ);
1382add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
13991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	debug_dump(pbBuffer, len, deb_v8);
1402add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	return len == buflen ? 0 : -EIO;
1412add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
1422add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
1432add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#define bytes_left_to_read_on_page(paddr,buflen) \
14491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \
14591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	 ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)))
1462add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
14791b94366260fc4d960713c2e76e0fc874ff76992Uwe Buglastatic int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
14891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start,
14991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		u32 addr, int extended, u8 *buf, u32 len)
1502add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
1512add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	int i,ret = 0;
1522add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	u16 wMax;
1532add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	u32 pagechunk = 0;
1542add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
1552add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	switch(req) {
15691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case B2C2_USB_READ_V8_MEM:
15791b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		wMax = USB_MEM_READ_MAX;
15891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		break;
15991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case B2C2_USB_WRITE_V8_MEM:
16091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		wMax = USB_MEM_WRITE_MAX;
16191b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		break;
16291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case B2C2_USB_FLASH_BLOCK:
16391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		wMax = USB_FLASH_MAX;
16491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		break;
16591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	default:
16691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		return -EINVAL;
1672add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		break;
1682add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	}
1692add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	for (i = 0; i < len;) {
17091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		pagechunk =
17191b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			wMax < bytes_left_to_read_on_page(addr, len) ?
17291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				wMax :
17391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				bytes_left_to_read_on_page(addr, len);
17491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		deb_info("%x\n",
17591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			(addr & V8_MEMORY_PAGE_MASK) |
17691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				(V8_MEMORY_EXTENDED*extended));
17791b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla
17891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		ret = flexcop_usb_v8_memory_req(fc_usb, req,
17991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			page_start + (addr / V8_MEMORY_PAGE_SIZE),
18091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			(addr & V8_MEMORY_PAGE_MASK) |
18191b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				(V8_MEMORY_EXTENDED*extended),
18291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			&buf[i], pagechunk);
18391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla
18491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		if (ret < 0)
1852add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			return ret;
1862add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		addr += pagechunk;
1872add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		len -= pagechunk;
1882add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	}
1892add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	return 0;
1902add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
1912add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
1922add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachstatic int flexcop_usb_get_mac_addr(struct flexcop_device *fc, int extended)
1932add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
19491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	return flexcop_usb_memory_req(fc->bus_specific, B2C2_USB_READ_V8_MEM,
19591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		V8_MEMORY_PAGE_FLASH, 0x1f010, 1,
19691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		fc->dvb_adapter.proposed_mac, 6);
1972add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
1982add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
1992add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#if 0
2002add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachstatic int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set,
2012add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		flexcop_usb_utility_function_t func, u8 extra, u16 wIndex,
2022add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		u16 buflen, u8 *pvBuffer)
2032add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
2042add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	u16 wValue;
2052add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	u8 request_type = (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR;
2062add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	int nWaitTime = 2,
20791b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	    pipe = set ? B2C2_USB_CTRL_PIPE_OUT : B2C2_USB_CTRL_PIPE_IN, len;
2082add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	wValue = (func << 8) | extra;
2092add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
2102add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	len = usb_control_msg(fc_usb->udev,pipe,
2112add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			B2C2_USB_UTILITY,
2122add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			request_type,
2132add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			wValue,
2142add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			wIndex,
2152add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			pvBuffer,
2162add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			buflen,
2172add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			nWaitTime * HZ);
2182add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	return len == buflen ? 0 : -EIO;
2192add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
2202add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach#endif
2212add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
2222add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach/* usb i2c stuff */
2236394cf53abc0b3a2db9e8b947ef5c77b16861ec8Patrick Boettcherstatic int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
2242add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		flexcop_usb_request_t req, flexcop_usb_i2c_function_t func,
2256394cf53abc0b3a2db9e8b947ef5c77b16861ec8Patrick Boettcher		u8 chipaddr, u8 addr, u8 *buf, u8 buflen)
2262add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
2276394cf53abc0b3a2db9e8b947ef5c77b16861ec8Patrick Boettcher	struct flexcop_usb *fc_usb = i2c->fc->bus_specific;
2282add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	u16 wValue, wIndex;
2292add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	int nWaitTime,pipe,len;
2302add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	u8 request_type = USB_TYPE_VENDOR;
2312add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
2322add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	switch (func) {
23391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case USB_FUNC_I2C_WRITE:
23491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case USB_FUNC_I2C_MULTIWRITE:
23591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case USB_FUNC_I2C_REPEATWRITE:
2362add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		/* DKT 020208 - add this to support special case of DiSEqC */
23791b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case USB_FUNC_I2C_CHECKWRITE:
23891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		pipe = B2C2_USB_CTRL_PIPE_OUT;
23991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		nWaitTime = 2;
24091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		request_type |= USB_DIR_OUT;
2412add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		break;
24291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case USB_FUNC_I2C_READ:
24391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case USB_FUNC_I2C_REPEATREAD:
24491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		pipe = B2C2_USB_CTRL_PIPE_IN;
24591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		nWaitTime = 2;
24691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		request_type |= USB_DIR_IN;
2472add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		break;
24891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	default:
24991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		deb_info("unsupported function for i2c_req %x\n", func);
25091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		return -EINVAL;
2512add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	}
2526394cf53abc0b3a2db9e8b947ef5c77b16861ec8Patrick Boettcher	wValue = (func << 8) | (i2c->port << 4);
2532add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	wIndex = (chipaddr << 8 ) | addr;
2542add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
25591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",
25691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			func, request_type, req,
25791b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			wValue & 0xff, wValue >> 8,
25891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			wIndex & 0xff, wIndex >> 8);
2592add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
2602add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	len = usb_control_msg(fc_usb->udev,pipe,
2612add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			req,
2622add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			request_type,
2632add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			wValue,
2642add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			wIndex,
2652add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			buf,
2662add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			buflen,
2672add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			nWaitTime * HZ);
2682add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	return len == buflen ? 0 : -EREMOTEIO;
2692add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
2702add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
27191b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla/* actual bus specific access functions,
27291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla   make sure prototype are/will be equal to pci */
27391b94366260fc4d960713c2e76e0fc874ff76992Uwe Buglastatic flexcop_ibi_value flexcop_usb_read_ibi_reg(struct flexcop_device *fc,
27491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	flexcop_ibi_register reg)
2752add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
2762add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	flexcop_ibi_value val;
2772add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	val.raw = 0;
27891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	flexcop_usb_readwrite_dw(fc, reg, &val.raw, 1);
2792add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	return val;
2802add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
2812add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
28291b94366260fc4d960713c2e76e0fc874ff76992Uwe Buglastatic int flexcop_usb_write_ibi_reg(struct flexcop_device *fc,
28391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		flexcop_ibi_register reg, flexcop_ibi_value val)
2842add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
28591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	return flexcop_usb_readwrite_dw(fc, reg, &val.raw, 0);
2862add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
2872add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
2886394cf53abc0b3a2db9e8b947ef5c77b16861ec8Patrick Boettcherstatic int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c,
28991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
2902add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
2912add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	if (op == FC_READ)
2926394cf53abc0b3a2db9e8b947ef5c77b16861ec8Patrick Boettcher		return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
29391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				USB_FUNC_I2C_READ, chipaddr, addr, buf, len);
2942add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	else
2956394cf53abc0b3a2db9e8b947ef5c77b16861ec8Patrick Boettcher		return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
29691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len);
2972add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
2982add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
29991b94366260fc4d960713c2e76e0fc874ff76992Uwe Buglastatic void flexcop_usb_process_frame(struct flexcop_usb *fc_usb,
30091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	u8 *buffer, int buffer_length)
3017635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach{
3027635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach	u8 *b;
3037635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach	int l;
3047635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach
30591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	deb_ts("tmp_buffer_length=%d, buffer_length=%d\n",
30691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		fc_usb->tmp_buffer_length, buffer_length);
3077635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach
3087635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach	if (fc_usb->tmp_buffer_length > 0) {
30991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		memcpy(fc_usb->tmp_buffer+fc_usb->tmp_buffer_length, buffer,
31091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				buffer_length);
3117635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach		fc_usb->tmp_buffer_length += buffer_length;
3127635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach		b = fc_usb->tmp_buffer;
3137635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach		l = fc_usb->tmp_buffer_length;
3147635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach	} else {
3157635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach		b=buffer;
3167635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach		l=buffer_length;
3177635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach	}
3187635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach
3197635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach	while (l >= 190) {
32091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		if (*b == 0xff) {
3217635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach			switch (*(b+1) & 0x03) {
32291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			case 0x01: /* media packet */
32391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				if (*(b+2) == 0x47)
32491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla					flexcop_pass_dmx_packets(
32591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla							fc_usb->fc_dev, b+2, 1);
32691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				else
32791b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla					deb_ts(
32891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla					"not ts packet %02x %02x %02x %02x \n",
32991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla						*(b+2), *(b+3),
33091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla						*(b+4), *(b+5));
33191b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				b += 190;
33291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				l -= 190;
3337635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach				break;
33491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			default:
33591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				deb_ts("wrong packet type\n");
33691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				l = 0;
3377635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach				break;
3387635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach			}
33991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		} else {
3407635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach			deb_ts("wrong header\n");
3417635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach			l = 0;
3427635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach		}
3437635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach	}
3447635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach
3457635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach	if (l>0)
3467635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach		memcpy(fc_usb->tmp_buffer, b, l);
3477635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach	fc_usb->tmp_buffer_length = l;
3487635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach}
3497635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach
3507d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void flexcop_usb_urb_complete(struct urb *urb)
3512add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
3522add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	struct flexcop_usb *fc_usb = urb->context;
3532add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	int i;
3542add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
3552add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	if (urb->actual_length > 0)
35691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		deb_ts("urb completed, bufsize: %d actlen; %d\n",
35791b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			urb->transfer_buffer_length, urb->actual_length);
3582add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
3592add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	for (i = 0; i < urb->number_of_packets; i++) {
3602add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		if (urb->iso_frame_desc[i].status < 0) {
36191b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			err("iso frame descriptor %d has an error: %d\n", i,
36291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				urb->iso_frame_desc[i].status);
3632add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		} else
3642add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			if (urb->iso_frame_desc[i].actual_length > 0) {
36591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla				deb_ts("passed %d bytes to the demux\n",
36691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla					urb->iso_frame_desc[i].actual_length);
3672add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
3687635acd2d927578495c692056d0e7dabd06afc89Johannes Stezenbach				flexcop_usb_process_frame(fc_usb,
36991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla					urb->transfer_buffer +
37091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla						urb->iso_frame_desc[i].offset,
3712add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach					urb->iso_frame_desc[i].actual_length);
37291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			}
3732add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		urb->iso_frame_desc[i].status = 0;
3742add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		urb->iso_frame_desc[i].actual_length = 0;
3752add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	}
3762add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	usb_submit_urb(urb,GFP_ATOMIC);
3772add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
3782add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
3792add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachstatic int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff)
3802add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
3812add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	/* submit/kill iso packets */
3822add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	return 0;
3832add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
3842add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
3852add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachstatic void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
3862add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
3872add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	int i;
3882add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++)
3892add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		if (fc_usb->iso_urb[i] != NULL) {
3902add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			deb_ts("unlinking/killing urb no. %d\n",i);
3912add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			usb_kill_urb(fc_usb->iso_urb[i]);
3922add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			usb_free_urb(fc_usb->iso_urb[i]);
3932add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		}
3942add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
3952add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	if (fc_usb->iso_buffer != NULL)
39691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		pci_free_consistent(NULL,
39791b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			fc_usb->buffer_size, fc_usb->iso_buffer,
39891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			fc_usb->dma_addr);
3992add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
4002add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
4012add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachstatic int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
4022add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
40391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	u16 frame_size = le16_to_cpu(
40491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		fc_usb->uintf->cur_altsetting->endpoint[0].desc.wMaxPacketSize);
40591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	int bufsize = B2C2_USB_NUM_ISO_URB * B2C2_USB_FRAMES_PER_ISO *
40691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		frame_size, i, j, ret;
4072add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	int buffer_offset = 0;
4082add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
40991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	deb_ts("creating %d iso-urbs with %d frames "
41091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			"each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB,
41191b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize);
4122add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
41391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	fc_usb->iso_buffer = pci_alloc_consistent(NULL,
41491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			bufsize, &fc_usb->dma_addr);
4152add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	if (fc_usb->iso_buffer == NULL)
4162add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		return -ENOMEM;
41791b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla
4182add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	memset(fc_usb->iso_buffer, 0, bufsize);
4192add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	fc_usb->buffer_size = bufsize;
4202add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
4212add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	/* creating iso urbs */
42291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
42391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		fc_usb->iso_urb[i] = usb_alloc_urb(B2C2_USB_FRAMES_PER_ISO,
42491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			GFP_ATOMIC);
42591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		if (fc_usb->iso_urb[i] == NULL) {
4262add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			ret = -ENOMEM;
4272add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			goto urb_error;
4282add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		}
42991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	}
43091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla
4312add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	/* initialising and submitting iso urbs */
4322add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) {
4332add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		int frame_offset = 0;
4342add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		struct urb *urb = fc_usb->iso_urb[i];
43591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		deb_ts("initializing and submitting urb no. %d "
43691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			"(buf_offset: %d).\n", i, buffer_offset);
4372add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
4382add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		urb->dev = fc_usb->udev;
4392add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		urb->context = fc_usb;
4402add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		urb->complete = flexcop_usb_urb_complete;
4412add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		urb->pipe = B2C2_USB_DATA_PIPE;
4422add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		urb->transfer_flags = URB_ISO_ASAP;
4432add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		urb->interval = 1;
4442add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		urb->number_of_packets = B2C2_USB_FRAMES_PER_ISO;
4452add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		urb->transfer_buffer_length = frame_size * B2C2_USB_FRAMES_PER_ISO;
4462add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		urb->transfer_buffer = fc_usb->iso_buffer + buffer_offset;
4472add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
4482add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		buffer_offset += frame_size * B2C2_USB_FRAMES_PER_ISO;
4492add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		for (j = 0; j < B2C2_USB_FRAMES_PER_ISO; j++) {
45091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			deb_ts("urb no: %d, frame: %d, frame_offset: %d\n",
45191b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla					i, j, frame_offset);
4522add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			urb->iso_frame_desc[j].offset = frame_offset;
4532add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			urb->iso_frame_desc[j].length = frame_size;
4542add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			frame_offset += frame_size;
4552add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		}
4562add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
4572add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		if ((ret = usb_submit_urb(fc_usb->iso_urb[i],GFP_ATOMIC))) {
45891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			err("submitting urb %d failed with %d.", i, ret);
4592add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach			goto urb_error;
4602add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		}
4612add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		deb_ts("submitted urb no. %d.\n",i);
4622add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	}
4632add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
46491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	/* SRAM */
46591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	flexcop_sram_set_dest(fc_usb->fc_dev, FC_SRAM_DEST_MEDIA |
46691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			FC_SRAM_DEST_NET | FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI,
46791b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla			FC_SRAM_DEST_TARGET_WAN_USB);
46891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	flexcop_wan_set_speed(fc_usb->fc_dev, FC_WAN_SPEED_8MBITS);
46991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	flexcop_sram_ctrl(fc_usb->fc_dev, 1, 1, 1);
4708397703ee0cc9ca27df5c058f60c4d4f1dc69595Trent Piepho	return 0;
4718397703ee0cc9ca27df5c058f60c4d4f1dc69595Trent Piepho
4722add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachurb_error:
4732add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	flexcop_usb_transfer_exit(fc_usb);
4742add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	return ret;
4752add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
4762add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
4772add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachstatic int flexcop_usb_init(struct flexcop_usb *fc_usb)
4782add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
4792add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	/* use the alternate setting with the larges buffer */
4802add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	usb_set_interface(fc_usb->udev,0,1);
4812add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	switch (fc_usb->udev->speed) {
48291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case USB_SPEED_LOW:
48391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		err("cannot handle USB speed because it is too slow.");
48491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		return -ENODEV;
48591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		break;
48691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case USB_SPEED_FULL:
48791b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		info("running at FULL speed.");
48891b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		break;
48991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case USB_SPEED_HIGH:
49091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		info("running at HIGH speed.");
49191b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		break;
49291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	case USB_SPEED_UNKNOWN: /* fall through */
49391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	default:
49491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		err("cannot handle USB speed because it is unknown.");
49591b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla		return -ENODEV;
4962add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	}
4972add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	usb_set_intfdata(fc_usb->uintf, fc_usb);
4982add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	return 0;
4992add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
5002add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
5012add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachstatic void flexcop_usb_exit(struct flexcop_usb *fc_usb)
5022add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
5032add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	usb_set_intfdata(fc_usb->uintf, NULL);
5042add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
5052add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
5062add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachstatic int flexcop_usb_probe(struct usb_interface *intf,
5072add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		const struct usb_device_id *id)
5082add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
5092add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	struct usb_device *udev = interface_to_usbdev(intf);
5102add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	struct flexcop_usb *fc_usb = NULL;
5112add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	struct flexcop_device *fc = NULL;
5122add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	int ret;
5132add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
5142add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) {
5152add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		err("out of memory\n");
5162add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		return -ENOMEM;
5172add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	}
5182add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
51991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	/* general flexcop init */
5202add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	fc_usb = fc->bus_specific;
5212add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	fc_usb->fc_dev = fc;
5222add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
5232add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	fc->read_ibi_reg  = flexcop_usb_read_ibi_reg;
5242add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	fc->write_ibi_reg = flexcop_usb_write_ibi_reg;
5252add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	fc->i2c_request = flexcop_usb_i2c_request;
5262add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	fc->get_mac_addr = flexcop_usb_get_mac_addr;
5272add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
5282add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	fc->stream_control = flexcop_usb_stream_control;
5292add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
5302add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	fc->pid_filtering = 1;
5312add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	fc->bus_type = FC_USB;
5322add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
5332add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	fc->dev = &udev->dev;
53459a7ad6c1ed3a058d375d2e679d73805e4f851acJohannes Stezenbach	fc->owner = THIS_MODULE;
5352add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
53691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	/* bus specific part */
5372add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	fc_usb->udev = udev;
5382add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	fc_usb->uintf = intf;
5392add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	if ((ret = flexcop_usb_init(fc_usb)) != 0)
5402add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		goto err_kfree;
5412add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
54291b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	/* init flexcop */
5432add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	if ((ret = flexcop_device_initialize(fc)) != 0)
5442add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		goto err_usb_exit;
5452add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
54691b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	/* xfer init */
5472add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	if ((ret = flexcop_usb_transfer_init(fc_usb)) != 0)
5482add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach		goto err_fc_exit;
5492add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
55091b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	info("%s successfully initialized and connected.", DRIVER_NAME);
5518397703ee0cc9ca27df5c058f60c4d4f1dc69595Trent Piepho	return 0;
5528397703ee0cc9ca27df5c058f60c4d4f1dc69595Trent Piepho
5532add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbacherr_fc_exit:
5542add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	flexcop_device_exit(fc);
5552add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbacherr_usb_exit:
5562add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	flexcop_usb_exit(fc_usb);
5572add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbacherr_kfree:
5582add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	flexcop_device_kfree(fc);
5592add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	return ret;
5602add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
5612add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
5622add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachstatic void flexcop_usb_disconnect(struct usb_interface *intf)
5632add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach{
5642add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	struct flexcop_usb *fc_usb = usb_get_intfdata(intf);
5652add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	flexcop_usb_transfer_exit(fc_usb);
5662add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	flexcop_device_exit(fc_usb->fc_dev);
5672add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	flexcop_usb_exit(fc_usb);
5682add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	flexcop_device_kfree(fc_usb->fc_dev);
56991b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	info("%s successfully deinitialized and disconnected.", DRIVER_NAME);
5702add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach}
5712add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
5722add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachstatic struct usb_device_id flexcop_usb_table [] = {
57391b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	{ USB_DEVICE(0x0af7, 0x0101) },
57491b94366260fc4d960713c2e76e0fc874ff76992Uwe Bugla	{ }
5752add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach};
5766637e6fd2a930567f1878e4585d70b444a9cb3b3Patrick BoettcherMODULE_DEVICE_TABLE (usb, flexcop_usb_table);
5772add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
5782add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach/* usb specific object needed to register this driver with the usb subsystem */
5792add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbachstatic struct usb_driver flexcop_usb_driver = {
58063b5c1c47fd6c5ae26d279756e8a050c721ea379Patrick Boettcher	.name		= "b2c2_flexcop_usb",
5812add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	.probe		= flexcop_usb_probe,
5822add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	.disconnect = flexcop_usb_disconnect,
5832add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach	.id_table	= flexcop_usb_table,
5842add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach};
5852add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
586ecb3b2b35db49778b6d89e3ffd0c400776c20735Greg Kroah-Hartmanmodule_usb_driver(flexcop_usb_driver);
5872add87a95068d6457d4e5824d0417d39007665a4Johannes Stezenbach
5882add87a95068d6457d4e5824d0417d39007665a4Johannes StezenbachMODULE_AUTHOR(DRIVER_AUTHOR);
5892add87a95068d6457d4e5824d0417d39007665a4Johannes StezenbachMODULE_DESCRIPTION(DRIVER_NAME);
5902add87a95068d6457d4e5824d0417d39007665a4Johannes StezenbachMODULE_LICENSE("GPL");
591