[go: nahoru, domu]

1f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger#include "headers.h"
2a6eb9af980746db1628c17b0fa134dbd04c1e91eHimangi Saraogi#include <linux/usb/ch9.h>
3f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemmingerstatic struct usb_device_id InterfaceUsbtable[] = {
4c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) },
5f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) },
6f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) },
74f29ef050848245f7c180b95ccf67dfcd76b1fd8Kevin McKinney	{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_SYM) },
8c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) },
9f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	{ USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) },
10c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_TU25) },
11e66fc1fba248738d32f3b64508f9ef1176d9e767Kevin McKinney	{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_226) },
124f29ef050848245f7c180b95ccf67dfcd76b1fd8Kevin McKinney	{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_326) },
13c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	{ }
14f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger};
152e44f765dfd3a8592c2d6b6005be061eccdee137Stephen HemmingerMODULE_DEVICE_TABLE(usb, InterfaceUsbtable);
16f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
174ea4f7a0d3d7a9961bf77f0860df8dd4a213b8a3Stephen Hemmingerstatic int debug = -1;
184ea4f7a0d3d7a9961bf77f0860df8dd4a213b8a3Stephen Hemmingermodule_param(debug, uint, 0600);
194ea4f7a0d3d7a9961bf77f0860df8dd4a213b8a3Stephen HemmingerMODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
204ea4f7a0d3d7a9961bf77f0860df8dd4a213b8a3Stephen Hemminger
214ea4f7a0d3d7a9961bf77f0860df8dd4a213b8a3Stephen Hemmingerstatic const u32 default_msg =
22c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
23c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	| NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR
24c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	| NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
254ea4f7a0d3d7a9961bf77f0860df8dd4a213b8a3Stephen Hemminger
26d6861cfef2e42fecd5f0d51554493e45df6612a6Kevin McKinneystatic int InterfaceAdapterInit(struct bcm_interface_adapter *Adapter);
279dd47ee7dd535649a2c32d509631c7a3d793f2e1Stephen Hemminger
28d6861cfef2e42fecd5f0d51554493e45df6612a6Kevin McKinneystatic void InterfaceAdapterFree(struct bcm_interface_adapter *psIntfAdapter)
29f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger{
302a314742d300edc2010d50a006c77ceb04c75119Dan Carpenter	int i = 0;
313b068e54695c56882d0796c757127325b61ff61cMatthias Beyer	struct bcm_mini_adapter *ps_ad = psIntfAdapter->psAdapter;
32c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter
33c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	/* Wake up the wait_queue... */
343b068e54695c56882d0796c757127325b61ff61cMatthias Beyer	if (ps_ad->LEDInfo.led_thread_running &
35529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			BCM_LED_THREAD_RUNNING_ACTIVELY) {
363b068e54695c56882d0796c757127325b61ff61cMatthias Beyer		ps_ad->DriverState = DRIVER_HALT;
373b068e54695c56882d0796c757127325b61ff61cMatthias Beyer		wake_up(&ps_ad->LEDInfo.notify_led_event);
38f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
393b068e54695c56882d0796c757127325b61ff61cMatthias Beyer	reset_card_proc(ps_ad);
40f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
41c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	/*
42529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey	 * worst case time taken by the RDM/WRM will be 5 sec. will check after
43529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey	 * every 100 ms to accertain the device is not being accessed. After
44529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey	 * this No RDM/WRM should be made.
45c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	 */
463b068e54695c56882d0796c757127325b61ff61cMatthias Beyer	while (ps_ad->DeviceAccess) {
47cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer		BCM_DEBUG_PRINT(ps_ad, DBG_TYPE_INITEXIT, DRV_ENTRY,
48cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer				DBG_LVL_ALL, "Device is being accessed.\n");
49f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		msleep(100);
50f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
51f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	/* Free interrupt URB */
523b068e54695c56882d0796c757127325b61ff61cMatthias Beyer	/* ps_ad->device_removed = TRUE; */
5337db526463a5ad1c96cd803d49fddbf069bbf9b9Dan Carpenter	usb_free_urb(psIntfAdapter->psInterruptUrb);
54f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
55f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	/* Free transmit URBs */
56c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	for (i = 0; i < MAXIMUM_USB_TCB; i++) {
57c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		if (psIntfAdapter->asUsbTcb[i].urb  != NULL) {
58f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			usb_free_urb(psIntfAdapter->asUsbTcb[i].urb);
59f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			psIntfAdapter->asUsbTcb[i].urb = NULL;
60f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		}
61f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
62f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	/* Free receive URB and buffers */
63c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	for (i = 0; i < MAXIMUM_USB_RCB; i++) {
64c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		if (psIntfAdapter->asUsbRcb[i].urb != NULL) {
65082e889b475c46e71be6e779f15ab095f888e03fStephen Hemminger			kfree(psIntfAdapter->asUsbRcb[i].urb->transfer_buffer);
66f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			usb_free_urb(psIntfAdapter->asUsbRcb[i].urb);
67f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			psIntfAdapter->asUsbRcb[i].urb = NULL;
68f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		}
69f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
703b068e54695c56882d0796c757127325b61ff61cMatthias Beyer	AdapterFree(ps_ad);
71f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger}
72f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
73d3842d5633508da302597a8608b15a16c5991261Matthias Beyerstatic void ConfigureEndPointTypesThroughEEPROM(
74d3842d5633508da302597a8608b15a16c5991261Matthias Beyer		struct bcm_mini_adapter *Adapter)
75f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger{
769fe526e145e281f0fe0447bbef58444bddb5de2bDan Carpenter	u32 ulReg;
7741c7b7c0fa2f68afb1154e88597ff6b9b97334cfKevin McKinney	int bytes;
789b14459654299163eba6ac53c8f616fd8c2fd17aJade Bilkey	struct bcm_interface_adapter *interfaceAdapter;
79f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
80c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	/* Program EP2 MAX_PKT_SIZE */
81f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	ulReg = ntohl(EP2_MPS_REG);
82c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x128, 4, TRUE);
83f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	ulReg = ntohl(EP2_MPS);
84c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x12C, 4, TRUE);
85f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
86f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	ulReg = ntohl(EP2_CFG_REG);
87c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x132, 4, TRUE);
889b14459654299163eba6ac53c8f616fd8c2fd17aJade Bilkey	interfaceAdapter =
899b14459654299163eba6ac53c8f616fd8c2fd17aJade Bilkey		(struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter);
909b14459654299163eba6ac53c8f616fd8c2fd17aJade Bilkey	if (interfaceAdapter->bHighSpeedDevice) {
91f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		ulReg = ntohl(EP2_CFG_INT);
92c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE);
93c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	} else {
94c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		/* USE BULK EP as TX in FS mode. */
95f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		ulReg = ntohl(EP2_CFG_BULK);
96c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE);
97f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
98f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
99c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	/* Program EP4 MAX_PKT_SIZE. */
100f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	ulReg = ntohl(EP4_MPS_REG);
101c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x13C, 4, TRUE);
102f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	ulReg = ntohl(EP4_MPS);
103c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x140, 4, TRUE);
104f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
105c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	/* Program TX EP as interrupt(Alternate Setting) */
1069fe526e145e281f0fe0447bbef58444bddb5de2bDan Carpenter	bytes = rdmalt(Adapter, 0x0F0110F8, &ulReg, sizeof(u32));
10741c7b7c0fa2f68afb1154e88597ff6b9b97334cfKevin McKinney	if (bytes < 0) {
108529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY,
109529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				DBG_LVL_ALL, "reading of Tx EP failed\n");
110c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		return;
111f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
112f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	ulReg |= 0x6;
113f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
114f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	ulReg = ntohl(ulReg);
115c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1CC, 4, TRUE);
116f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
117f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	ulReg = ntohl(EP4_CFG_REG);
118c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C8, 4, TRUE);
119c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	/* Program ISOCHRONOUS EP size to zero. */
120f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	ulReg = ntohl(ISO_MPS_REG);
121c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D2, 4, TRUE);
122f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	ulReg = ntohl(ISO_MPS);
123c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D6, 4, TRUE);
124f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
125c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	/*
126c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	 * Update EEPROM Version.
127c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	 * Read 4 bytes from 508 and modify 511 and 510.
128c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	 */
1299fe526e145e281f0fe0447bbef58444bddb5de2bDan Carpenter	ReadBeceemEEPROM(Adapter, 0x1FC, &ulReg);
130f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	ulReg &= 0x0101FFFF;
131c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1FC, 4, TRUE);
132c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter
133cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer	/*
134cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer	 * Update length field if required.
135cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer	 * Also make the string NULL terminated.
136cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer	 */
137c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter
1389fe526e145e281f0fe0447bbef58444bddb5de2bDan Carpenter	ReadBeceemEEPROM(Adapter, 0xA8, &ulReg);
139c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	if ((ulReg&0x00FF0000)>>16 > 0x30) {
140f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		ulReg = (ulReg&0xFF00FFFF)|(0x30<<16);
141c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0xA8, 4, TRUE);
142f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
1439fe526e145e281f0fe0447bbef58444bddb5de2bDan Carpenter	ReadBeceemEEPROM(Adapter, 0x148, &ulReg);
144c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	if ((ulReg&0x00FF0000)>>16 > 0x30) {
145f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		ulReg = (ulReg&0xFF00FFFF)|(0x30<<16);
146c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x148, 4, TRUE);
147f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
148f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	ulReg = 0;
149c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x122, 4, TRUE);
150f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	ulReg = 0;
151c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C2, 4, TRUE);
152f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger}
153f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
154d3842d5633508da302597a8608b15a16c5991261Matthias Beyerstatic int usbbcm_device_probe(struct usb_interface *intf,
155d3842d5633508da302597a8608b15a16c5991261Matthias Beyer			       const struct usb_device_id *id)
156f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger{
157c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	struct usb_device *udev = interface_to_usbdev(intf);
158e614e28eac1afcdc3d1275f3e1478aa3e5acc500Stephen Hemminger	int retval;
1592979460d7aba1dac3452edcacd7b8c4cfcf06067Kevin McKinney	struct bcm_mini_adapter *psAdapter;
160d6861cfef2e42fecd5f0d51554493e45df6612a6Kevin McKinney	struct bcm_interface_adapter *psIntfAdapter;
161e614e28eac1afcdc3d1275f3e1478aa3e5acc500Stephen Hemminger	struct net_device *ndev;
162f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
1630980f2e8144ea0021a09be41176b736d76ca3db7Stephen Hemminger	/* Reserve one extra queue for the bit-bucket */
164529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey	ndev = alloc_etherdev_mq(sizeof(struct bcm_mini_adapter),
165529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			NO_OF_QUEUES + 1);
166c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	if (ndev == NULL) {
167e614e28eac1afcdc3d1275f3e1478aa3e5acc500Stephen Hemminger		dev_err(&udev->dev, DRV_NAME ": no memory for device\n");
168f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		return -ENOMEM;
169f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
170f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
171e614e28eac1afcdc3d1275f3e1478aa3e5acc500Stephen Hemminger	SET_NETDEV_DEV(ndev, &intf->dev);
172f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
173e614e28eac1afcdc3d1275f3e1478aa3e5acc500Stephen Hemminger	psAdapter = netdev_priv(ndev);
174e614e28eac1afcdc3d1275f3e1478aa3e5acc500Stephen Hemminger	psAdapter->dev = ndev;
1754ea4f7a0d3d7a9961bf77f0860df8dd4a213b8a3Stephen Hemminger	psAdapter->msg_enable = netif_msg_init(debug, default_msg);
176e614e28eac1afcdc3d1275f3e1478aa3e5acc500Stephen Hemminger
177c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	/* Init default driver debug state */
178f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
1794fd64dd0c1b9317ffe6fdaf3de788e14df880d8dStephen Hemminger	psAdapter->stDebugState.debug_level = DBG_LVL_CURR;
180f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	psAdapter->stDebugState.type = DBG_TYPE_INITEXIT;
181f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
182c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	/*
183c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	 * Technically, one can start using BCM_DEBUG_PRINT after this point.
184529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey	 * However, realize that by default the Type/Subtype bitmaps are all
185529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey	 * zero now; so no prints will actually appear until the TestApp turns
186529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey	 * on debug paths via the ioctl(); so practically speaking, in early
187529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey	 * init, no logging happens.
188f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	 *
189529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey	 * A solution (used below): we explicitly set the bitmaps to 1 for
190529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey	 * Type=DBG_TYPE_INITEXIT and ALL subtype's of the same. Now all bcm
191529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey	 * debug statements get logged, enabling debug during early init.
192f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	 * Further, we turn this OFF once init_module() completes.
193f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	 */
194f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
195c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0xff;
196f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	BCM_SHOW_DEBUG_BITMAP(psAdapter);
197f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
198f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	retval = InitAdapter(psAdapter);
199c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	if (retval) {
200e614e28eac1afcdc3d1275f3e1478aa3e5acc500Stephen Hemminger		dev_err(&udev->dev, DRV_NAME ": InitAdapter Failed\n");
201f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		AdapterFree(psAdapter);
202f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		return retval;
203f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
204f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
205f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	/* Allocate interface adapter structure */
20678110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches	psIntfAdapter = kzalloc(sizeof(struct bcm_interface_adapter),
207529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			GFP_KERNEL);
208c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	if (psIntfAdapter == NULL) {
209c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		AdapterFree(psAdapter);
210f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		return -ENOMEM;
211f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
212f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
213e614e28eac1afcdc3d1275f3e1478aa3e5acc500Stephen Hemminger	psAdapter->pvInterfaceAdapter = psIntfAdapter;
214f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	psIntfAdapter->psAdapter = psAdapter;
215f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
216f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	/* Store usb interface in Interface Adapter */
217f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	psIntfAdapter->interface = intf;
218f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	usb_set_intfdata(intf, psIntfAdapter);
219f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
22007a7f68800a490bc1140de778e196f66ef4596d9Dan Carpenter	BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
221529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			"psIntfAdapter 0x%p\n", psIntfAdapter);
222f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	retval = InterfaceAdapterInit(psIntfAdapter);
223c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	if (retval) {
224f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		/* If the Firmware/Cfg File is not present
225c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		 * then return success, let the application
226c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		 * download the files.
227c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		 */
228c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		if (-ENOENT == retval) {
229529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY,
230529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					DBG_LVL_ALL,
231529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					"File Not Found.  Use app to download.\n");
232f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			return STATUS_SUCCESS;
233f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		}
234529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY,
235529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				DBG_LVL_ALL, "InterfaceAdapterInit failed.\n");
236f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		usb_set_intfdata(intf, NULL);
237c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		udev = interface_to_usbdev(intf);
238f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		usb_put_dev(udev);
239f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		InterfaceAdapterFree(psIntfAdapter);
240c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		return retval;
241f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
242c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	if (psAdapter->chip_id > T3) {
243c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		uint32_t uiNackZeroLengthInt = 4;
244c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter
245529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		retval =
246529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT,
247529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					&uiNackZeroLengthInt,
248529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					sizeof(uiNackZeroLengthInt));
24937db526463a5ad1c96cd803d49fddbf069bbf9b9Dan Carpenter		if (retval)
25037db526463a5ad1c96cd803d49fddbf069bbf9b9Dan Carpenter			return retval;
251f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
252f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
253f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	/* Check whether the USB-Device Supports remote Wake-Up */
254c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	if (USB_CONFIG_ATT_WAKEUP & udev->actconfig->desc.bmAttributes) {
255f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		/* If Suspend then only support dynamic suspend */
256c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		if (psAdapter->bDoSuspend) {
2575fe1f1edb916aa4f573563449ceccd1b468aeddaRandy Dunlap#ifdef CONFIG_PM
2582f15744c1d90ee2e82f8ae5724b44b1cdf31715cAlan Stern			pm_runtime_set_autosuspend_delay(&udev->dev, 0);
259f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			intf->needs_remote_wakeup = 1;
260f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			usb_enable_autosuspend(udev);
261c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter			device_init_wakeup(&intf->dev, 1);
262529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			INIT_WORK(&psIntfAdapter->usbSuspendWork,
263529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					putUsbSuspend);
264529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY,
265529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					DBG_LVL_ALL,
266529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					"Enabling USB Auto-Suspend\n");
2675fe1f1edb916aa4f573563449ceccd1b468aeddaRandy Dunlap#endif
268c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		} else {
269f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			intf->needs_remote_wakeup = 0;
270f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			usb_disable_autosuspend(udev);
271f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		}
272f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
273f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
274c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0x0;
275c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	return retval;
276f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger}
277f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
278c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenterstatic void usbbcm_disconnect(struct usb_interface *intf)
279f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger{
280d6861cfef2e42fecd5f0d51554493e45df6612a6Kevin McKinney	struct bcm_interface_adapter *psIntfAdapter = usb_get_intfdata(intf);
2812979460d7aba1dac3452edcacd7b8c4cfcf06067Kevin McKinney	struct bcm_mini_adapter *psAdapter;
282c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	struct usb_device  *udev = interface_to_usbdev(intf);
283f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
284c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	if (psIntfAdapter == NULL)
285f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		return;
2864ea4f7a0d3d7a9961bf77f0860df8dd4a213b8a3Stephen Hemminger
287f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	psAdapter = psIntfAdapter->psAdapter;
2884ea4f7a0d3d7a9961bf77f0860df8dd4a213b8a3Stephen Hemminger	netif_device_detach(psAdapter->dev);
2894ea4f7a0d3d7a9961bf77f0860df8dd4a213b8a3Stephen Hemminger
290c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	if (psAdapter->bDoSuspend)
291f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		intf->needs_remote_wakeup = 0;
292f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
2936246432f73211e1c5fc5383d3922540f9f9bb9efJade Bilkey	psAdapter->device_removed = TRUE;
294f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	usb_set_intfdata(intf, NULL);
295f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	InterfaceAdapterFree(psIntfAdapter);
296f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	usb_put_dev(udev);
297f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger}
298f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
299d6861cfef2e42fecd5f0d51554493e45df6612a6Kevin McKinneystatic int AllocUsbCb(struct bcm_interface_adapter *psIntfAdapter)
300f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger{
301f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	int i = 0;
302c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter
303c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	for (i = 0; i < MAXIMUM_USB_TCB; i++) {
304ca45e70029b3d96923953992c05a2515dd3d9f24Kevin McKinney		psIntfAdapter->asUsbTcb[i].urb = usb_alloc_urb(0, GFP_KERNEL);
305ca45e70029b3d96923953992c05a2515dd3d9f24Kevin McKinney
306ca45e70029b3d96923953992c05a2515dd3d9f24Kevin McKinney		if (psIntfAdapter->asUsbTcb[i].urb == NULL) {
307529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
308529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					DBG_TYPE_PRINTK, 0, 0,
309529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					"Can't allocate Tx urb for index %d\n",
310529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					i);
311f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			return -ENOMEM;
312f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		}
313f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
314f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
315c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	for (i = 0; i < MAXIMUM_USB_RCB; i++) {
316ca45e70029b3d96923953992c05a2515dd3d9f24Kevin McKinney		psIntfAdapter->asUsbRcb[i].urb = usb_alloc_urb(0, GFP_KERNEL);
317ca45e70029b3d96923953992c05a2515dd3d9f24Kevin McKinney
318ca45e70029b3d96923953992c05a2515dd3d9f24Kevin McKinney		if (psIntfAdapter->asUsbRcb[i].urb == NULL) {
319529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
320529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					DBG_TYPE_PRINTK, 0, 0,
321529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					"Can't allocate Rx urb for index %d\n",
322529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					i);
323f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			return -ENOMEM;
324f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		}
325ca45e70029b3d96923953992c05a2515dd3d9f24Kevin McKinney
326529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		psIntfAdapter->asUsbRcb[i].urb->transfer_buffer =
327529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL);
328ca45e70029b3d96923953992c05a2515dd3d9f24Kevin McKinney
329ca45e70029b3d96923953992c05a2515dd3d9f24Kevin McKinney		if (psIntfAdapter->asUsbRcb[i].urb->transfer_buffer == NULL) {
330529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
331529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					DBG_TYPE_PRINTK, 0, 0,
332529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					"Can't allocate Rx buffer for index %d\n",
333529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					i);
334f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			return -ENOMEM;
335f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		}
336529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		psIntfAdapter->asUsbRcb[i].urb->transfer_buffer_length =
337529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			MAX_DATA_BUFFER_SIZE;
338f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
339f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	return 0;
340f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger}
341f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
342d6861cfef2e42fecd5f0d51554493e45df6612a6Kevin McKinneystatic int device_run(struct bcm_interface_adapter *psIntfAdapter)
343f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger{
3442a314742d300edc2010d50a006c77ceb04c75119Dan Carpenter	int value = 0;
345f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	UINT status = STATUS_SUCCESS;
3469e58842f7654653b973007ee5894a5aa4b98f3d3Matthias Beyer	struct bcm_mini_adapter *psAd = psIntfAdapter->psAdapter;
347f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
3489e58842f7654653b973007ee5894a5aa4b98f3d3Matthias Beyer	status = InitCardAndDownloadFirmware(psAd);
349c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	if (status != STATUS_SUCCESS) {
3502d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemminger		pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n");
351f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		return status;
352f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
3539e58842f7654653b973007ee5894a5aa4b98f3d3Matthias Beyer	if (psAd->fw_download_done) {
354c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		if (StartInterruptUrb(psIntfAdapter)) {
3559e58842f7654653b973007ee5894a5aa4b98f3d3Matthias Beyer			BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,
356529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					DBG_LVL_ALL,
357529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					"Cannot send interrupt in URB\n");
358f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		}
359f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
360c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		/*
361529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		 * now register the cntrl interface.  after downloading the f/w
362529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		 * waiting for 5 sec to get the mailbox interrupt.
363c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		 */
3649e58842f7654653b973007ee5894a5aa4b98f3d3Matthias Beyer		psAd->waiting_to_fw_download_done = false;
3659e58842f7654653b973007ee5894a5aa4b98f3d3Matthias Beyer		value = wait_event_timeout(psAd->ioctl_fw_dnld_wait_queue,
3669e58842f7654653b973007ee5894a5aa4b98f3d3Matthias Beyer					   psAd->waiting_to_fw_download_done,
3679e58842f7654653b973007ee5894a5aa4b98f3d3Matthias Beyer					   5 * HZ);
368f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
369c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		if (value == 0)
37007a7f68800a490bc1140de778e196f66ef4596d9Dan Carpenter			pr_err(DRV_NAME ": Timeout waiting for mailbox interrupt.\n");
3712d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemminger
3729e58842f7654653b973007ee5894a5aa4b98f3d3Matthias Beyer		if (register_control_device_interface(psAd) < 0) {
37307a7f68800a490bc1140de778e196f66ef4596d9Dan Carpenter			pr_err(DRV_NAME ": Register Control Device failed.\n");
374f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			return -EIO;
375f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		}
376f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
377f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	return 0;
378f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger}
379f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
380b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyerstatic int select_alternate_setting_for_highspeed_modem(
381b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		struct bcm_interface_adapter *psIntfAdapter,
382b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		struct usb_endpoint_descriptor **endpoint,
383b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		const struct usb_host_interface *iface_desc,
384b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		int *usedIntOutForBulkTransfer)
385b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer{
386b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer	int retval = 0;
387b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer	struct bcm_mini_adapter *psAd = psIntfAdapter->psAdapter;
388b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer
389b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer	/* selecting alternate setting one as a default setting
390b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer	 * for High Speed  modem. */
391b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer	if (psIntfAdapter->bHighSpeedDevice)
392b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		retval = usb_set_interface(psIntfAdapter->udev,
393b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer					   DEFAULT_SETTING_0,
394b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer					   ALTERNATE_SETTING_1);
395269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer	BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
396b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			"BCM16 is applicable on this dongle\n");
397b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer	if (retval || !psIntfAdapter->bHighSpeedDevice) {
398b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		*usedIntOutForBulkTransfer = EP2;
399b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		*endpoint = &iface_desc->endpoint[EP2].desc;
400269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer		BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
401b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer				"Interface altsetting failed or modem is configured to Full Speed, hence will work on default setting 0\n");
402b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		/*
403b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		 * If Modem is high speed device EP2 should be
404b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		 * INT OUT End point
405b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		 *
406b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		 * If Mode is FS then EP2 should be bulk end
407b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		 * point
408b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		 */
409b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		if ((psIntfAdapter->bHighSpeedDevice &&
410b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer					!usb_endpoint_is_int_out(*endpoint)) ||
411b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer				(!psIntfAdapter->bHighSpeedDevice &&
412b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer				 !usb_endpoint_is_bulk_out(*endpoint))) {
413269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer			BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,
414269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer					DBG_LVL_ALL,
415b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer					"Configuring the EEPROM\n");
416b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			/* change the EP2, EP4 to INT OUT end point */
417b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			ConfigureEndPointTypesThroughEEPROM(
418b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer					psAd);
419b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer
420b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			/*
421b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			 * It resets the device and if any thing
422b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			 * gets changed in USB descriptor it
423b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			 * will show fail and re-enumerate the
424b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			 * device
425b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			 */
426269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer			retval = usb_reset_device(psIntfAdapter->udev);
427b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			if (retval) {
428269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer				BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT,
429269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer						DRV_ENTRY, DBG_LVL_ALL,
430b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer						"reset failed.  Re-enumerating the device.\n");
431b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer				return retval;
432b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			}
433b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer
434b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		}
435b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		if (!psIntfAdapter->bHighSpeedDevice &&
436b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		    usb_endpoint_is_bulk_out(*endpoint)) {
437cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer			/*
438cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer			 * Once BULK is selected in FS mode.
439cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer			 * Revert it back to INT.
440cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer			 * Else USB_IF will fail.
441cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer			 */
442b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			UINT _uiData = ntohl(EP2_CFG_INT);
44389fa037b82bd63b687b97e9613786ca90c9ddcf8Pawel Lebioda
444269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer			BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,
445269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer					DBG_LVL_ALL,
446b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer					"Reverting Bulk to INT as it is in Full Speed mode.\n");
447269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer			BeceemEEPROMBulkWrite(psAd, (PUCHAR) & _uiData, 0x136,
448269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer					      4, TRUE);
449b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		}
450b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer	} else {
451b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		*usedIntOutForBulkTransfer = EP4;
452b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		*endpoint = &iface_desc->endpoint[EP4].desc;
453269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer		BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
454b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer				"Choosing AltSetting as a default setting.\n");
455b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		if (!usb_endpoint_is_int_out(*endpoint)) {
456269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer			BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,
457269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer					DBG_LVL_ALL,
458b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer					"Dongle does not have BCM16 Fix.\n");
459cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer			/*
460cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer			 * change the EP2, EP4 to INT OUT end point and use EP4
461cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer			 * in altsetting
462cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer			 */
463269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer			ConfigureEndPointTypesThroughEEPROM(psAd);
464b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer
465b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			/*
466b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			 * It resets the device and if any thing
467b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			 * gets changed in USB descriptor it
468b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			 * will show fail and re-enumerate the
469b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			 * device
470b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			 */
471269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer			retval = usb_reset_device(psIntfAdapter->udev);
472b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			if (retval) {
473269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer				BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT,
474269027e95fd2a65a894e49c7c70a490b90ef85f6Matthias Beyer						DRV_ENTRY, DBG_LVL_ALL,
475b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer						"reset failed.  Re-enumerating the device.\n");
476b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer				return retval;
477b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			}
478b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer		}
479b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer	}
480b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer
481b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer	return 0;
482b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer}
483b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer
484d6861cfef2e42fecd5f0d51554493e45df6612a6Kevin McKinneystatic int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter)
485f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger{
486f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	struct usb_host_interface *iface_desc;
487f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	struct usb_endpoint_descriptor *endpoint;
488f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	size_t buffer_size;
4892a314742d300edc2010d50a006c77ceb04c75119Dan Carpenter	unsigned long value;
4902a314742d300edc2010d50a006c77ceb04c75119Dan Carpenter	int retval = 0;
4916246432f73211e1c5fc5383d3922540f9f9bb9efJade Bilkey	int usedIntOutForBulkTransfer = 0;
492f70c8a91cd0e743d0531a158d939bbdb6c0874dcLisa Nguyen	bool bBcm16 = false;
493f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	UINT uiData = 0;
49441c7b7c0fa2f68afb1154e88597ff6b9b97334cfKevin McKinney	int bytes;
495a02b67b6e7888e94403689f112cbf172f91fec6eMatthias Beyer	struct bcm_mini_adapter *psAd = psIntfAdapter->psAdapter;
496f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
497f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	/* Store the usb dev into interface adapter */
498529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey	psIntfAdapter->udev =
499529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		usb_get_dev(interface_to_usbdev(psIntfAdapter->interface));
500f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
501529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey	psIntfAdapter->bHighSpeedDevice =
502529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		(psIntfAdapter->udev->speed == USB_SPEED_HIGH);
503a02b67b6e7888e94403689f112cbf172f91fec6eMatthias Beyer	psAd->interface_rdm = BcmRDM;
504a02b67b6e7888e94403689f112cbf172f91fec6eMatthias Beyer	psAd->interface_wrm = BcmWRM;
505f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
506b4ad0f04907f40a873c49e86afb034cafab16d5dMatthias Beyer	bytes = rdmalt(psAd, CHIP_ID_REG, (u32 *) &(psAd->chip_id),
507b4ad0f04907f40a873c49e86afb034cafab16d5dMatthias Beyer		       sizeof(u32));
50841c7b7c0fa2f68afb1154e88597ff6b9b97334cfKevin McKinney	if (bytes < 0) {
50941c7b7c0fa2f68afb1154e88597ff6b9b97334cfKevin McKinney		retval = bytes;
510a02b67b6e7888e94403689f112cbf172f91fec6eMatthias Beyer		BCM_DEBUG_PRINT(psAd, DBG_TYPE_PRINTK, 0, 0,
511529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				"CHIP ID Read Failed\n");
51237db526463a5ad1c96cd803d49fddbf069bbf9b9Dan Carpenter		return retval;
513f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
514f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
515a02b67b6e7888e94403689f112cbf172f91fec6eMatthias Beyer	if (0xbece3200 == (psAd->chip_id & ~(0xF0)))
516a02b67b6e7888e94403689f112cbf172f91fec6eMatthias Beyer		psAd->chip_id &= ~0xF0;
517f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
5182d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemminger	dev_info(&psIntfAdapter->udev->dev, "RDM Chip ID 0x%lx\n",
519b4ad0f04907f40a873c49e86afb034cafab16d5dMatthias Beyer		 psAd->chip_id);
520f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
5212d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemminger	iface_desc = psIntfAdapter->interface->cur_altsetting;
522f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
523a02b67b6e7888e94403689f112cbf172f91fec6eMatthias Beyer	if (psAd->chip_id == T3B) {
524529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		/* T3B device will have EEPROM, check if EEPROM is proper and
525529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		 * BCM16 can be done or not. */
526a02b67b6e7888e94403689f112cbf172f91fec6eMatthias Beyer		BeceemEEPROMBulkRead(psAd, &uiData, 0x0, 4);
527c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		if (uiData == BECM)
528f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			bBcm16 = TRUE;
5292d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemminger
530529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		dev_info(&psIntfAdapter->udev->dev,
531b4ad0f04907f40a873c49e86afb034cafab16d5dMatthias Beyer			 "number of alternate setting %d\n",
532b4ad0f04907f40a873c49e86afb034cafab16d5dMatthias Beyer			 psIntfAdapter->interface->num_altsetting);
5332d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemminger
534c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		if (bBcm16 == TRUE) {
535b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			retval = select_alternate_setting_for_highspeed_modem(
536b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer					psIntfAdapter, &endpoint, iface_desc,
537b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer					&usedIntOutForBulkTransfer);
538b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer			if (retval)
539b3110cd8cf8d2cff9f39e3e6fe8fb88ed7642105Matthias Beyer				return retval;
540f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		}
541f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
542f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
543f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	iface_desc = psIntfAdapter->interface->cur_altsetting;
5442d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemminger
545c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value) {
5462d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemminger		endpoint = &iface_desc->endpoint[value].desc;
547f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
548529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr &&
549529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				usb_endpoint_is_bulk_in(endpoint)) {
550c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter			buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
551c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter			psIntfAdapter->sBulkIn.bulk_in_size = buffer_size;
552529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			psIntfAdapter->sBulkIn.bulk_in_endpointAddr =
553529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				endpoint->bEndpointAddress;
554529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			psIntfAdapter->sBulkIn.bulk_in_pipe = usb_rcvbulkpipe(
555529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					psIntfAdapter->udev,
556529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					psIntfAdapter->sBulkIn.bulk_in_endpointAddr);
557c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		}
558f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
559529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr &&
560529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				usb_endpoint_is_bulk_out(endpoint)) {
561529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			psIntfAdapter->sBulkOut.bulk_out_endpointAddr =
562529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				endpoint->bEndpointAddress;
563529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			psIntfAdapter->sBulkOut.bulk_out_pipe = usb_sndbulkpipe(
564529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					psIntfAdapter->udev,
565f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger					psIntfAdapter->sBulkOut.bulk_out_endpointAddr);
566c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		}
567f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
568529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		if (!psIntfAdapter->sIntrIn.int_in_endpointAddr &&
569529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				usb_endpoint_is_int_in(endpoint)) {
570c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter			buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
571c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter			psIntfAdapter->sIntrIn.int_in_size = buffer_size;
572529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			psIntfAdapter->sIntrIn.int_in_endpointAddr =
573529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				endpoint->bEndpointAddress;
574529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			psIntfAdapter->sIntrIn.int_in_interval =
575529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				endpoint->bInterval;
576c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter			psIntfAdapter->sIntrIn.int_in_buffer =
577529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				kmalloc(buffer_size, GFP_KERNEL);
57878110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches			if (!psIntfAdapter->sIntrIn.int_in_buffer)
579c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter				return -EINVAL;
580c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		}
581f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
582529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey		if (!psIntfAdapter->sIntrOut.int_out_endpointAddr &&
583529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				usb_endpoint_is_int_out(endpoint)) {
584c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter			if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr &&
585a02b67b6e7888e94403689f112cbf172f91fec6eMatthias Beyer					(psAd->chip_id == T3B) &&
586529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					(value == usedIntOutForBulkTransfer)) {
587cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer				/*
588cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer				 * use first intout end point as a bulk out end
589cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer				 * point
590cd77fe77613649e9ca1c8ef8792290b02f1098caMatthias Beyer				 */
591529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				buffer_size =
592529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					le16_to_cpu(endpoint->wMaxPacketSize);
593529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				psIntfAdapter->sBulkOut.bulk_out_size =
594529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					buffer_size;
595529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				psIntfAdapter->sBulkOut.bulk_out_endpointAddr =
596529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					endpoint->bEndpointAddress;
597529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				psIntfAdapter->sBulkOut.bulk_out_pipe =
598529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					usb_sndintpipe(psIntfAdapter->udev,
599529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey							psIntfAdapter->sBulkOut
600529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey							.bulk_out_endpointAddr);
601529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				psIntfAdapter->sBulkOut.int_out_interval =
602529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					endpoint->bInterval;
603c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter			} else if (value == EP6) {
604529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				buffer_size =
605529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					le16_to_cpu(endpoint->wMaxPacketSize);
606529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				psIntfAdapter->sIntrOut.int_out_size =
607529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					buffer_size;
608529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				psIntfAdapter->sIntrOut.int_out_endpointAddr =
609529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					endpoint->bEndpointAddress;
610529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				psIntfAdapter->sIntrOut.int_out_interval =
611529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					endpoint->bInterval;
612529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				psIntfAdapter->sIntrOut.int_out_buffer =
613529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					kmalloc(buffer_size, GFP_KERNEL);
61478110bb8dc4a7ff331bfa3cfe7d4e287cfb3f22bJoe Perches				if (!psIntfAdapter->sIntrOut.int_out_buffer)
6152d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemminger					return -EINVAL;
616f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			}
617c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		}
618f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
619f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
620c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	usb_set_intfdata(psIntfAdapter->interface, psIntfAdapter);
621f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
622a02b67b6e7888e94403689f112cbf172f91fec6eMatthias Beyer	psAd->bcm_file_download = InterfaceFileDownload;
623b4ad0f04907f40a873c49e86afb034cafab16d5dMatthias Beyer	psAd->bcm_file_readback_from_chip = InterfaceFileReadbackFromChip;
624a02b67b6e7888e94403689f112cbf172f91fec6eMatthias Beyer	psAd->interface_transmit = InterfaceTransmitPacket;
625f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
626f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	retval = CreateInterruptUrb(psIntfAdapter);
627f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
628c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	if (retval) {
629a02b67b6e7888e94403689f112cbf172f91fec6eMatthias Beyer		BCM_DEBUG_PRINT(psAd, DBG_TYPE_PRINTK, 0, 0,
630529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey				"Cannot create interrupt urb\n");
631f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		return retval;
632f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
633f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
634f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	retval = AllocUsbCb(psIntfAdapter);
63537db526463a5ad1c96cd803d49fddbf069bbf9b9Dan Carpenter	if (retval)
636f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		return retval;
637f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
638032100f65295d594fc0481e840efe8b6c1e398afStephen Hemminger	return device_run(psIntfAdapter);
639f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger}
64044a17eff844d92421c8b568c84df29735e1e45f9Arnd Bergmann
641c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenterstatic int InterfaceSuspend(struct usb_interface *intf, pm_message_t message)
642f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger{
643d6861cfef2e42fecd5f0d51554493e45df6612a6Kevin McKinney	struct bcm_interface_adapter *psIntfAdapter = usb_get_intfdata(intf);
6442d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemminger
645f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	psIntfAdapter->bSuspended = TRUE;
646f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
6479b14459654299163eba6ac53c8f616fd8c2fd17aJade Bilkey	if (psIntfAdapter->bPreparingForBusSuspend) {
648f70c8a91cd0e743d0531a158d939bbdb6c0874dcLisa Nguyen		psIntfAdapter->bPreparingForBusSuspend = false;
649f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
650c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		if (psIntfAdapter->psAdapter->LinkStatus == LINKUP_DONE) {
6516246432f73211e1c5fc5383d3922540f9f9bb9efJade Bilkey			psIntfAdapter->psAdapter->IdleMode = TRUE;
652529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
653529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					DBG_TYPE_INITEXIT, DRV_ENTRY,
654529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					DBG_LVL_ALL,
655529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					"Host Entered in PMU Idle Mode.\n");
656c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter		} else {
657f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger			psIntfAdapter->psAdapter->bShutStatus = TRUE;
658529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey			BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
659529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					DBG_TYPE_INITEXIT, DRV_ENTRY,
660529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					DBG_LVL_ALL,
661529d08e97da6868a9eae5b85e69b9a2b32b18434Jade Bilkey					"Host Entered in PMU Shutdown Mode.\n");
662f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger		}
663f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	}
664f70c8a91cd0e743d0531a158d939bbdb6c0874dcLisa Nguyen	psIntfAdapter->psAdapter->bPreparingForLowPowerMode = false;
665f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
666c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	/* Signaling the control pkt path */
667f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	wake_up(&psIntfAdapter->psAdapter->lowpower_mode_wait_queue);
668f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
669f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	return 0;
670f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger}
67144a17eff844d92421c8b568c84df29735e1e45f9Arnd Bergmann
672c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenterstatic int InterfaceResume(struct usb_interface *intf)
673f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger{
674d6861cfef2e42fecd5f0d51554493e45df6612a6Kevin McKinney	struct bcm_interface_adapter *psIntfAdapter = usb_get_intfdata(intf);
675cd0b0ebfbe134b9c98fa8e628732b0e41b2cb48cDan Carpenter
676f969f84ed92e55040dbf51398ba2d8f5d23bf498Kevin McKinney	mdelay(100);
677f70c8a91cd0e743d0531a158d939bbdb6c0874dcLisa Nguyen	psIntfAdapter->bSuspended = false;
678f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
679f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	StartInterruptUrb(psIntfAdapter);
680f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	InterfaceRx(psIntfAdapter);
681f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	return 0;
682f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger}
68344a17eff844d92421c8b568c84df29735e1e45f9Arnd Bergmann
684f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemmingerstatic struct usb_driver usbbcm_driver = {
685c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	.name = "usbbcm",
686c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	.probe = usbbcm_device_probe,
687c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	.disconnect = usbbcm_disconnect,
688c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	.suspend = InterfaceSuspend,
689c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	.resume = InterfaceResume,
690c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	.id_table = InterfaceUsbtable,
691c2a0b162dbce1534cf4e71914597419ae83a70d9Dan Carpenter	.supports_autosuspend = 1,
692f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger};
693f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
6949e0a3169a34ba5fd04bde058a63fa0a36f2d7ed3Stephen Hemmingerstruct class *bcm_class;
695f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
6962d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemmingerstatic __init int bcm_init(void)
697f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger{
698d7b990a035a86a07e81231caceb6e624056c258fAlexey Khoroshilov	int retval;
699d7b990a035a86a07e81231caceb6e624056c258fAlexey Khoroshilov
700c2e114db5a2c02b5b148cf8db88c4a0d7c8ffb56Alexey Khoroshilov	pr_info("%s: %s, %s\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION);
701c2e114db5a2c02b5b148cf8db88c4a0d7c8ffb56Alexey Khoroshilov	pr_info("%s\n", DRV_COPYRIGHT);
702f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
7039e0a3169a34ba5fd04bde058a63fa0a36f2d7ed3Stephen Hemminger	bcm_class = class_create(THIS_MODULE, DRV_NAME);
7049e0a3169a34ba5fd04bde058a63fa0a36f2d7ed3Stephen Hemminger	if (IS_ERR(bcm_class)) {
705c2e114db5a2c02b5b148cf8db88c4a0d7c8ffb56Alexey Khoroshilov		pr_err(DRV_NAME ": could not create class\n");
7069e0a3169a34ba5fd04bde058a63fa0a36f2d7ed3Stephen Hemminger		return PTR_ERR(bcm_class);
7079e0a3169a34ba5fd04bde058a63fa0a36f2d7ed3Stephen Hemminger	}
708f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
709d7b990a035a86a07e81231caceb6e624056c258fAlexey Khoroshilov	retval = usb_register(&usbbcm_driver);
710d7b990a035a86a07e81231caceb6e624056c258fAlexey Khoroshilov	if (retval < 0) {
711c2e114db5a2c02b5b148cf8db88c4a0d7c8ffb56Alexey Khoroshilov		pr_err(DRV_NAME ": could not register usb driver\n");
712d7b990a035a86a07e81231caceb6e624056c258fAlexey Khoroshilov		class_destroy(bcm_class);
713d7b990a035a86a07e81231caceb6e624056c258fAlexey Khoroshilov		return retval;
714d7b990a035a86a07e81231caceb6e624056c258fAlexey Khoroshilov	}
715d7b990a035a86a07e81231caceb6e624056c258fAlexey Khoroshilov	return 0;
716f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger}
717f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger
7182d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemmingerstatic __exit void bcm_exit(void)
719f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger{
720f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger	usb_deregister(&usbbcm_driver);
7216b74705e15d5c87181008f1ac984df7faaad55c9Dan Carpenter	class_destroy(bcm_class);
722f8942e07a3db9d82e8fb11d3d494876b8bae9ff9Stephen Hemminger}
7232d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemminger
7242d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemmingermodule_init(bcm_init);
7252d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemmingermodule_exit(bcm_exit);
7262d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen Hemminger
7272d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen HemmingerMODULE_DESCRIPTION(DRV_DESCRIPTION);
7282d08748ae53bf07fe6fcaf4f3d40449b471ce351Stephen HemmingerMODULE_VERSION(DRV_VERSION);
729c2a0b162dbce1534cf4e71914597419ae83a70d9Dan CarpenterMODULE_LICENSE("GPL");
730