blob: 36991f7cbf3331df97d557bb637f4e69fccc2a21 [file] [log] [blame]
Stephen Hemmingerf8942e02010-09-08 14:46:36 -07001#include "headers.h"
2
3static struct usb_device_id InterfaceUsbtable[] = {
Dan Carpenterc2a0b162010-12-06 10:02:11 +03004 { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) },
Stephen Hemmingerf8942e02010-09-08 14:46:36 -07005 { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) },
6 { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) },
Dan Carpenterc2a0b162010-12-06 10:02:11 +03007 { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_SM250) },
8 { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) },
Stephen Hemmingerf8942e02010-09-08 14:46:36 -07009 { USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) },
Dan Carpenterc2a0b162010-12-06 10:02:11 +030010 { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_TU25) },
11 { }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070012};
Stephen Hemminger2e44f762010-10-29 07:44:45 -070013MODULE_DEVICE_TABLE(usb, InterfaceUsbtable);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070014
Stephen Hemminger4ea4f7a2010-11-01 14:06:24 -040015static int debug = -1;
16module_param(debug, uint, 0600);
17MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
18
19static const u32 default_msg =
Dan Carpenterc2a0b162010-12-06 10:02:11 +030020 NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
21 | NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR
22 | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
Stephen Hemminger4ea4f7a2010-11-01 14:06:24 -040023
Dan Carpenter2a3147422010-12-06 10:01:41 +030024static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER Adapter);
Stephen Hemminger9dd47ee2010-11-01 12:24:00 -040025
Dan Carpenter2a3147422010-12-06 10:01:41 +030026static void InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070027{
Dan Carpenter2a3147422010-12-06 10:01:41 +030028 int i = 0;
Dan Carpenterc2a0b162010-12-06 10:02:11 +030029
30 /* Wake up the wait_queue... */
31 if (psIntfAdapter->psAdapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070032 psIntfAdapter->psAdapter->DriverState = DRIVER_HALT;
33 wake_up(&psIntfAdapter->psAdapter->LEDInfo.notify_led_event);
34 }
35 reset_card_proc(psIntfAdapter->psAdapter);
36
Dan Carpenterc2a0b162010-12-06 10:02:11 +030037 /*
38 * worst case time taken by the RDM/WRM will be 5 sec. will check after every 100 ms
39 * to accertain the device is not being accessed. After this No RDM/WRM should be made.
40 */
41 while (psIntfAdapter->psAdapter->DeviceAccess) {
42 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
Dan Carpenter07a7f682010-12-06 10:03:13 +030043 "Device is being accessed.\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070044 msleep(100);
45 }
46 /* Free interrupt URB */
Dan Carpenterc2a0b162010-12-06 10:02:11 +030047 /* psIntfAdapter->psAdapter->device_removed = TRUE; */
Dan Carpenter37db5262010-12-06 10:03:38 +030048 usb_free_urb(psIntfAdapter->psInterruptUrb);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070049
50 /* Free transmit URBs */
Dan Carpenterc2a0b162010-12-06 10:02:11 +030051 for (i = 0; i < MAXIMUM_USB_TCB; i++) {
52 if (psIntfAdapter->asUsbTcb[i].urb != NULL) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070053 usb_free_urb(psIntfAdapter->asUsbTcb[i].urb);
54 psIntfAdapter->asUsbTcb[i].urb = NULL;
55 }
56 }
57 /* Free receive URB and buffers */
Dan Carpenterc2a0b162010-12-06 10:02:11 +030058 for (i = 0; i < MAXIMUM_USB_RCB; i++) {
59 if (psIntfAdapter->asUsbRcb[i].urb != NULL) {
Stephen Hemminger082e8892010-11-01 09:35:21 -040060 kfree(psIntfAdapter->asUsbRcb[i].urb->transfer_buffer);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070061 usb_free_urb(psIntfAdapter->asUsbRcb[i].urb);
62 psIntfAdapter->asUsbRcb[i].urb = NULL;
63 }
64 }
65 AdapterFree(psIntfAdapter->psAdapter);
66}
67
Dan Carpenter2a3147422010-12-06 10:01:41 +030068static void ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070069{
Dan Carpenter2a3147422010-12-06 10:01:41 +030070 unsigned long ulReg = 0;
Dan Carpenter37db5262010-12-06 10:03:38 +030071 int ret;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070072
Dan Carpenterc2a0b162010-12-06 10:02:11 +030073 /* Program EP2 MAX_PKT_SIZE */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070074 ulReg = ntohl(EP2_MPS_REG);
Dan Carpenterc2a0b162010-12-06 10:02:11 +030075 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x128, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070076 ulReg = ntohl(EP2_MPS);
Dan Carpenterc2a0b162010-12-06 10:02:11 +030077 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x12C, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070078
79 ulReg = ntohl(EP2_CFG_REG);
Dan Carpenterc2a0b162010-12-06 10:02:11 +030080 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x132, 4, TRUE);
81 if (((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter))->bHighSpeedDevice == TRUE) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070082 ulReg = ntohl(EP2_CFG_INT);
Dan Carpenterc2a0b162010-12-06 10:02:11 +030083 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE);
84 } else {
85 /* USE BULK EP as TX in FS mode. */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070086 ulReg = ntohl(EP2_CFG_BULK);
Dan Carpenterc2a0b162010-12-06 10:02:11 +030087 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070088 }
89
Dan Carpenterc2a0b162010-12-06 10:02:11 +030090 /* Program EP4 MAX_PKT_SIZE. */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070091 ulReg = ntohl(EP4_MPS_REG);
Dan Carpenterc2a0b162010-12-06 10:02:11 +030092 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x13C, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070093 ulReg = ntohl(EP4_MPS);
Dan Carpenterc2a0b162010-12-06 10:02:11 +030094 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x140, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070095
Dan Carpenterc2a0b162010-12-06 10:02:11 +030096 /* Program TX EP as interrupt(Alternate Setting) */
Dan Carpenter37db5262010-12-06 10:03:38 +030097 ret = rdmalt(Adapter, 0x0F0110F8, (u32 *)&ulReg, sizeof(u32));
98 if (ret) {
Dan Carpenter07a7f682010-12-06 10:03:13 +030099 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
100 "reading of Tx EP failed\n");
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300101 return;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700102 }
103 ulReg |= 0x6;
104
105 ulReg = ntohl(ulReg);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300106 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1CC, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700107
108 ulReg = ntohl(EP4_CFG_REG);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300109 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C8, 4, TRUE);
110 /* Program ISOCHRONOUS EP size to zero. */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700111 ulReg = ntohl(ISO_MPS_REG);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300112 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D2, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700113 ulReg = ntohl(ISO_MPS);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300114 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D6, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700115
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300116 /*
117 * Update EEPROM Version.
118 * Read 4 bytes from 508 and modify 511 and 510.
119 */
120 ReadBeceemEEPROM(Adapter, 0x1FC, (PUINT)&ulReg);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700121 ulReg &= 0x0101FFFF;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300122 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1FC, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700123
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300124 /* Update length field if required. Also make the string NULL terminated. */
125
126 ReadBeceemEEPROM(Adapter, 0xA8, (PUINT)&ulReg);
127 if ((ulReg&0x00FF0000)>>16 > 0x30) {
128 ulReg = (ulReg&0xFF00FFFF)|(0x30<<16);
129 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0xA8, 4, TRUE);
130 }
131 ReadBeceemEEPROM(Adapter, 0x148, (PUINT)&ulReg);
132 if ((ulReg&0x00FF0000)>>16 > 0x30) {
133 ulReg = (ulReg&0xFF00FFFF)|(0x30<<16);
134 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x148, 4, TRUE);
135 }
136 ulReg = 0;
137 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x122, 4, TRUE);
138 ulReg = 0;
139 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C2, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700140}
141
Kevin McKinneyf969f842011-10-10 21:01:48 -0400142static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700143{
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300144 struct usb_device *udev = interface_to_usbdev(intf);
Stephen Hemmingere614e282010-11-01 09:52:14 -0400145 int retval;
146 PMINI_ADAPTER psAdapter;
147 PS_INTERFACE_ADAPTER psIntfAdapter;
148 struct net_device *ndev;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700149
Stephen Hemminger0980f2e2010-11-01 00:04:52 -0400150 /* Reserve one extra queue for the bit-bucket */
151 ndev = alloc_etherdev_mq(sizeof(MINI_ADAPTER), NO_OF_QUEUES+1);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300152 if (ndev == NULL) {
Stephen Hemmingere614e282010-11-01 09:52:14 -0400153 dev_err(&udev->dev, DRV_NAME ": no memory for device\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700154 return -ENOMEM;
155 }
156
Stephen Hemmingere614e282010-11-01 09:52:14 -0400157 SET_NETDEV_DEV(ndev, &intf->dev);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700158
Stephen Hemmingere614e282010-11-01 09:52:14 -0400159 psAdapter = netdev_priv(ndev);
160 psAdapter->dev = ndev;
Stephen Hemminger4ea4f7a2010-11-01 14:06:24 -0400161 psAdapter->msg_enable = netif_msg_init(debug, default_msg);
Stephen Hemmingere614e282010-11-01 09:52:14 -0400162
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300163 /* Init default driver debug state */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700164
Stephen Hemminger4fd64dd2010-11-01 12:12:31 -0400165 psAdapter->stDebugState.debug_level = DBG_LVL_CURR;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700166 psAdapter->stDebugState.type = DBG_TYPE_INITEXIT;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700167
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300168 /*
169 * Technically, one can start using BCM_DEBUG_PRINT after this point.
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700170 * However, realize that by default the Type/Subtype bitmaps are all zero now;
171 * so no prints will actually appear until the TestApp turns on debug paths via
172 * the ioctl(); so practically speaking, in early init, no logging happens.
173 *
174 * A solution (used below): we explicitly set the bitmaps to 1 for Type=DBG_TYPE_INITEXIT
175 * and ALL subtype's of the same. Now all bcm debug statements get logged, enabling debug
176 * during early init.
177 * Further, we turn this OFF once init_module() completes.
178 */
179
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300180 psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0xff;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700181 BCM_SHOW_DEBUG_BITMAP(psAdapter);
182
183 retval = InitAdapter(psAdapter);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300184 if (retval) {
Stephen Hemmingere614e282010-11-01 09:52:14 -0400185 dev_err(&udev->dev, DRV_NAME ": InitAdapter Failed\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700186 AdapterFree(psAdapter);
187 return retval;
188 }
189
190 /* Allocate interface adapter structure */
Stephen Hemmingere614e282010-11-01 09:52:14 -0400191 psIntfAdapter = kzalloc(sizeof(S_INTERFACE_ADAPTER), GFP_KERNEL);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300192 if (psIntfAdapter == NULL) {
Stephen Hemmingere614e282010-11-01 09:52:14 -0400193 dev_err(&udev->dev, DRV_NAME ": no memory for Interface adapter\n");
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300194 AdapterFree(psAdapter);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700195 return -ENOMEM;
196 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700197
Stephen Hemmingere614e282010-11-01 09:52:14 -0400198 psAdapter->pvInterfaceAdapter = psIntfAdapter;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700199 psIntfAdapter->psAdapter = psAdapter;
200
201 /* Store usb interface in Interface Adapter */
202 psIntfAdapter->interface = intf;
203 usb_set_intfdata(intf, psIntfAdapter);
204
Dan Carpenter07a7f682010-12-06 10:03:13 +0300205 BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
206 "psIntfAdapter 0x%p\n", psIntfAdapter);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700207 retval = InterfaceAdapterInit(psIntfAdapter);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300208 if (retval) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700209 /* If the Firmware/Cfg File is not present
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300210 * then return success, let the application
211 * download the files.
212 */
213 if (-ENOENT == retval) {
Dan Carpenter07a7f682010-12-06 10:03:13 +0300214 BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
215 "File Not Found. Use app to download.\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700216 return STATUS_SUCCESS;
217 }
Dan Carpenter07a7f682010-12-06 10:03:13 +0300218 BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
219 "InterfaceAdapterInit failed.\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700220 usb_set_intfdata(intf, NULL);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300221 udev = interface_to_usbdev(intf);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700222 usb_put_dev(udev);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700223 InterfaceAdapterFree(psIntfAdapter);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300224 return retval;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700225 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300226 if (psAdapter->chip_id > T3) {
227 uint32_t uiNackZeroLengthInt = 4;
228
Dan Carpenter37db5262010-12-06 10:03:38 +0300229 retval = wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT, &uiNackZeroLengthInt, sizeof(uiNackZeroLengthInt));
230 if (retval)
231 return retval;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700232 }
233
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700234 /* Check whether the USB-Device Supports remote Wake-Up */
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300235 if (USB_CONFIG_ATT_WAKEUP & udev->actconfig->desc.bmAttributes) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700236 /* If Suspend then only support dynamic suspend */
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300237 if (psAdapter->bDoSuspend) {
Randy Dunlap5fe1f1e2010-09-14 15:39:50 -0700238#ifdef CONFIG_PM
Alan Stern2f157442010-11-17 10:56:01 -0500239 pm_runtime_set_autosuspend_delay(&udev->dev, 0);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700240 intf->needs_remote_wakeup = 1;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700241 usb_enable_autosuspend(udev);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300242 device_init_wakeup(&intf->dev, 1);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700243 INIT_WORK(&psIntfAdapter->usbSuspendWork, putUsbSuspend);
Dan Carpenter07a7f682010-12-06 10:03:13 +0300244 BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
245 "Enabling USB Auto-Suspend\n");
Randy Dunlap5fe1f1e2010-09-14 15:39:50 -0700246#endif
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300247 } else {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700248 intf->needs_remote_wakeup = 0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700249 usb_disable_autosuspend(udev);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700250 }
251 }
252
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300253 psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0x0;
254 return retval;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700255}
256
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300257static void usbbcm_disconnect(struct usb_interface *intf)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700258{
Stephen Hemminger4ea4f7a2010-11-01 14:06:24 -0400259 PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
260 PMINI_ADAPTER psAdapter;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300261 struct usb_device *udev = interface_to_usbdev(intf);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700262
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300263 if (psIntfAdapter == NULL)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700264 return;
Stephen Hemminger4ea4f7a2010-11-01 14:06:24 -0400265
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700266 psAdapter = psIntfAdapter->psAdapter;
Stephen Hemminger4ea4f7a2010-11-01 14:06:24 -0400267 netif_device_detach(psAdapter->dev);
268
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300269 if (psAdapter->bDoSuspend)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700270 intf->needs_remote_wakeup = 0;
271
272 psAdapter->device_removed = TRUE ;
273 usb_set_intfdata(intf, NULL);
274 InterfaceAdapterFree(psIntfAdapter);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700275 usb_put_dev(udev);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700276}
277
Stephen Hemminger20f48652010-10-31 23:52:36 -0400278static int AllocUsbCb(PS_INTERFACE_ADAPTER psIntfAdapter)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700279{
280 int i = 0;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300281
282 for (i = 0; i < MAXIMUM_USB_TCB; i++) {
283 if ((psIntfAdapter->asUsbTcb[i].urb =
284 usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
Dan Carpenter07a7f682010-12-06 10:03:13 +0300285 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
286 "Can't allocate Tx urb for index %d\n", i);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700287 return -ENOMEM;
288 }
289 }
290
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300291 for (i = 0; i < MAXIMUM_USB_RCB; i++) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700292 if ((psIntfAdapter->asUsbRcb[i].urb =
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300293 usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
Dan Carpenter07a7f682010-12-06 10:03:13 +0300294 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
295 "Can't allocate Rx urb for index %d\n", i);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700296 return -ENOMEM;
297 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300298 if ((psIntfAdapter->asUsbRcb[i].urb->transfer_buffer =
299 kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL)) == NULL) {
Dan Carpenter07a7f682010-12-06 10:03:13 +0300300 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
301 "Can't allocate Rx buffer for index %d\n", i);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700302 return -ENOMEM;
303 }
304 psIntfAdapter->asUsbRcb[i].urb->transfer_buffer_length = MAX_DATA_BUFFER_SIZE;
305 }
306 return 0;
307}
308
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700309static int device_run(PS_INTERFACE_ADAPTER psIntfAdapter)
310{
Dan Carpenter2a3147422010-12-06 10:01:41 +0300311 int value = 0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700312 UINT status = STATUS_SUCCESS;
313
314 status = InitCardAndDownloadFirmware(psIntfAdapter->psAdapter);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300315 if (status != STATUS_SUCCESS) {
Stephen Hemminger2d087482010-11-01 12:14:01 -0400316 pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700317 return status;
318 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300319 if (TRUE == psIntfAdapter->psAdapter->fw_download_done) {
320 if (StartInterruptUrb(psIntfAdapter)) {
Dan Carpenter07a7f682010-12-06 10:03:13 +0300321 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
322 "Cannot send interrupt in URB\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700323 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700324
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300325 /*
326 * now register the cntrl interface.
327 * after downloading the f/w waiting for 5 sec to get the mailbox interrupt.
328 */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700329 psIntfAdapter->psAdapter->waiting_to_fw_download_done = FALSE;
330 value = wait_event_timeout(psIntfAdapter->psAdapter->ioctl_fw_dnld_wait_queue,
331 psIntfAdapter->psAdapter->waiting_to_fw_download_done, 5*HZ);
332
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300333 if (value == 0)
Dan Carpenter07a7f682010-12-06 10:03:13 +0300334 pr_err(DRV_NAME ": Timeout waiting for mailbox interrupt.\n");
Stephen Hemminger2d087482010-11-01 12:14:01 -0400335
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300336 if (register_control_device_interface(psIntfAdapter->psAdapter) < 0) {
Dan Carpenter07a7f682010-12-06 10:03:13 +0300337 pr_err(DRV_NAME ": Register Control Device failed.\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700338 return -EIO;
339 }
340 }
341 return 0;
342}
343
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700344
345static inline int bcm_usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
346{
347 return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
348}
349
350static inline int bcm_usb_endpoint_type(const struct usb_endpoint_descriptor *epd)
351{
352 return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
353}
354
355static inline int bcm_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
356{
357 return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
358}
359
360static inline int bcm_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
361{
362 return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
363}
364
365static inline int bcm_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
366{
367 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
368 USB_ENDPOINT_XFER_BULK);
369}
370
371static inline int bcm_usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd)
372{
373 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
374 USB_ENDPOINT_XFER_CONTROL);
375}
376
377static inline int bcm_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
378{
379 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
380 USB_ENDPOINT_XFER_INT);
381}
382
383static inline int bcm_usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
384{
385 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
386 USB_ENDPOINT_XFER_ISOC);
387}
388
389static inline int bcm_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
390{
Kevin McKinneyf969f842011-10-10 21:01:48 -0400391 return bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_in(epd);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700392}
393
394static inline int bcm_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
395{
Kevin McKinneyf969f842011-10-10 21:01:48 -0400396 return bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_out(epd);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700397}
398
399static inline int bcm_usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
400{
Kevin McKinneyf969f842011-10-10 21:01:48 -0400401 return bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_in(epd);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700402}
403
404static inline int bcm_usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
405{
Kevin McKinneyf969f842011-10-10 21:01:48 -0400406 return bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_out(epd);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700407}
408
409static inline int bcm_usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd)
410{
Kevin McKinneyf969f842011-10-10 21:01:48 -0400411 return bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_in(epd);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700412}
413
414static inline int bcm_usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd)
415{
Kevin McKinneyf969f842011-10-10 21:01:48 -0400416 return bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_out(epd);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700417}
418
Dan Carpenter2a3147422010-12-06 10:01:41 +0300419static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700420{
421 struct usb_host_interface *iface_desc;
422 struct usb_endpoint_descriptor *endpoint;
423 size_t buffer_size;
Dan Carpenter2a3147422010-12-06 10:01:41 +0300424 unsigned long value;
425 int retval = 0;
426 int usedIntOutForBulkTransfer = 0 ;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700427 BOOLEAN bBcm16 = FALSE;
428 UINT uiData = 0;
429
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700430 /* Store the usb dev into interface adapter */
Stephen Hemminger2d087482010-11-01 12:14:01 -0400431 psIntfAdapter->udev = usb_get_dev(interface_to_usbdev(psIntfAdapter->interface));
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700432
Stephen Hemminger2d087482010-11-01 12:14:01 -0400433 psIntfAdapter->bHighSpeedDevice = (psIntfAdapter->udev->speed == USB_SPEED_HIGH);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700434 psIntfAdapter->psAdapter->interface_rdm = BcmRDM;
435 psIntfAdapter->psAdapter->interface_wrm = BcmWRM;
436
Dan Carpenter37db5262010-12-06 10:03:38 +0300437 retval = rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG,
438 (u32 *)&(psIntfAdapter->psAdapter->chip_id), sizeof(u32));
439 if (retval) {
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300440 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "CHIP ID Read Failed\n");
Dan Carpenter37db5262010-12-06 10:03:38 +0300441 return retval;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700442 }
443
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300444 if (0xbece3200 == (psIntfAdapter->psAdapter->chip_id & ~(0xF0)))
Stephen Hemminger2d087482010-11-01 12:14:01 -0400445 psIntfAdapter->psAdapter->chip_id &= ~0xF0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700446
Stephen Hemminger2d087482010-11-01 12:14:01 -0400447 dev_info(&psIntfAdapter->udev->dev, "RDM Chip ID 0x%lx\n",
448 psIntfAdapter->psAdapter->chip_id);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700449
Stephen Hemminger2d087482010-11-01 12:14:01 -0400450 iface_desc = psIntfAdapter->interface->cur_altsetting;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700451
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300452 if (psIntfAdapter->psAdapter->chip_id == T3B) {
453 /* T3B device will have EEPROM, check if EEPROM is proper and BCM16 can be done or not. */
454 BeceemEEPROMBulkRead(psIntfAdapter->psAdapter, &uiData, 0x0, 4);
455 if (uiData == BECM)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700456 bBcm16 = TRUE;
Stephen Hemminger2d087482010-11-01 12:14:01 -0400457
458 dev_info(&psIntfAdapter->udev->dev, "number of alternate setting %d\n",
459 psIntfAdapter->interface->num_altsetting);
460
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300461 if (bBcm16 == TRUE) {
462 /* selecting alternate setting one as a default setting for High Speed modem. */
463 if (psIntfAdapter->bHighSpeedDevice)
Kevin McKinneyf969f842011-10-10 21:01:48 -0400464 retval = usb_set_interface(psIntfAdapter->udev, DEFAULT_SETTING_0, ALTERNATE_SETTING_1);
Dan Carpenter07a7f682010-12-06 10:03:13 +0300465 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
466 "BCM16 is applicable on this dongle\n");
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300467 if (retval || (psIntfAdapter->bHighSpeedDevice == FALSE)) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700468 usedIntOutForBulkTransfer = EP2 ;
469 endpoint = &iface_desc->endpoint[EP2].desc;
Dan Carpenter07a7f682010-12-06 10:03:13 +0300470 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
471 "Interface altsetting failed or modem is configured to Full Speed, hence will work on default setting 0\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700472 /*
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300473 * If Modem is high speed device EP2 should be INT OUT End point
474 * If Mode is FS then EP2 should be bulk end point
475 */
476 if (((psIntfAdapter->bHighSpeedDevice == TRUE) && (bcm_usb_endpoint_is_int_out(endpoint) == FALSE))
477 || ((psIntfAdapter->bHighSpeedDevice == FALSE) && (bcm_usb_endpoint_is_bulk_out(endpoint) == FALSE))) {
Dan Carpenter07a7f682010-12-06 10:03:13 +0300478 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
479 "Configuring the EEPROM\n");
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300480 /* change the EP2, EP4 to INT OUT end point */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700481 ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter);
482
483 /*
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300484 * It resets the device and if any thing gets changed
485 * in USB descriptor it will show fail and re-enumerate
486 * the device
487 */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700488 retval = usb_reset_device(psIntfAdapter->udev);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300489 if (retval) {
Dan Carpenter07a7f682010-12-06 10:03:13 +0300490 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
491 "reset failed. Re-enumerating the device.\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700492 return retval ;
493 }
494
495 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300496 if ((psIntfAdapter->bHighSpeedDevice == FALSE) && bcm_usb_endpoint_is_bulk_out(endpoint)) {
497 /* Once BULK is selected in FS mode. Revert it back to INT. Else USB_IF will fail. */
Arnd Bergmann44a17eff2010-09-30 10:24:12 +0200498 UINT _uiData = ntohl(EP2_CFG_INT);
Kevin McKinneyf969f842011-10-10 21:01:48 -0400499 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
Dan Carpenter07a7f682010-12-06 10:03:13 +0300500 "Reverting Bulk to INT as it is in Full Speed mode.\n");
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300501 BeceemEEPROMBulkWrite(psIntfAdapter->psAdapter, (PUCHAR)&_uiData, 0x136, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700502 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300503 } else {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700504 usedIntOutForBulkTransfer = EP4 ;
505 endpoint = &iface_desc->endpoint[EP4].desc;
Dan Carpenter07a7f682010-12-06 10:03:13 +0300506 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
507 "Choosing AltSetting as a default setting.\n");
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300508 if (bcm_usb_endpoint_is_int_out(endpoint) == FALSE) {
Dan Carpenter07a7f682010-12-06 10:03:13 +0300509 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
510 "Dongle does not have BCM16 Fix.\n");
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300511 /* change the EP2, EP4 to INT OUT end point and use EP4 in altsetting */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700512 ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter);
513
514 /*
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300515 * It resets the device and if any thing gets changed in
516 * USB descriptor it will show fail and re-enumerate the
517 * device
518 */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700519 retval = usb_reset_device(psIntfAdapter->udev);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300520 if (retval) {
Dan Carpenter07a7f682010-12-06 10:03:13 +0300521 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
522 "reset failed. Re-enumerating the device.\n");
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300523 return retval;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700524 }
525
526 }
527 }
528 }
529 }
530
531 iface_desc = psIntfAdapter->interface->cur_altsetting;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700532
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300533 for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value) {
Stephen Hemminger2d087482010-11-01 12:14:01 -0400534 endpoint = &iface_desc->endpoint[value].desc;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700535
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300536 if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && bcm_usb_endpoint_is_bulk_in(endpoint)) {
537 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
538 psIntfAdapter->sBulkIn.bulk_in_size = buffer_size;
539 psIntfAdapter->sBulkIn.bulk_in_endpointAddr = endpoint->bEndpointAddress;
540 psIntfAdapter->sBulkIn.bulk_in_pipe =
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700541 usb_rcvbulkpipe(psIntfAdapter->udev,
542 psIntfAdapter->sBulkIn.bulk_in_endpointAddr);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300543 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700544
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300545 if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && bcm_usb_endpoint_is_bulk_out(endpoint)) {
546 psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress;
547 psIntfAdapter->sBulkOut.bulk_out_pipe =
548 usb_sndbulkpipe(psIntfAdapter->udev,
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700549 psIntfAdapter->sBulkOut.bulk_out_endpointAddr);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300550 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700551
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300552 if (!psIntfAdapter->sIntrIn.int_in_endpointAddr && bcm_usb_endpoint_is_int_in(endpoint)) {
553 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
554 psIntfAdapter->sIntrIn.int_in_size = buffer_size;
555 psIntfAdapter->sIntrIn.int_in_endpointAddr = endpoint->bEndpointAddress;
556 psIntfAdapter->sIntrIn.int_in_interval = endpoint->bInterval;
557 psIntfAdapter->sIntrIn.int_in_buffer =
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700558 kmalloc(buffer_size, GFP_KERNEL);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300559 if (!psIntfAdapter->sIntrIn.int_in_buffer) {
Stephen Hemminger2d087482010-11-01 12:14:01 -0400560 dev_err(&psIntfAdapter->udev->dev,
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300561 "could not allocate interrupt_in_buffer\n");
562 return -EINVAL;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700563 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300564 }
565
566 if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && bcm_usb_endpoint_is_int_out(endpoint)) {
567 if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr &&
568 (psIntfAdapter->psAdapter->chip_id == T3B) && (value == usedIntOutForBulkTransfer)) {
569 /* use first intout end point as a bulk out end point */
570 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
571 psIntfAdapter->sBulkOut.bulk_out_size = buffer_size;
572 psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress;
573 psIntfAdapter->sBulkOut.bulk_out_pipe = usb_sndintpipe(psIntfAdapter->udev,
574 psIntfAdapter->sBulkOut.bulk_out_endpointAddr);
575 psIntfAdapter->sBulkOut.int_out_interval = endpoint->bInterval;
576 } else if (value == EP6) {
577 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
578 psIntfAdapter->sIntrOut.int_out_size = buffer_size;
579 psIntfAdapter->sIntrOut.int_out_endpointAddr = endpoint->bEndpointAddress;
580 psIntfAdapter->sIntrOut.int_out_interval = endpoint->bInterval;
Kevin McKinneyf969f842011-10-10 21:01:48 -0400581 psIntfAdapter->sIntrOut.int_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300582 if (!psIntfAdapter->sIntrOut.int_out_buffer) {
583 dev_err(&psIntfAdapter->udev->dev,
584 "could not allocate interrupt_out_buffer\n");
585 return -EINVAL;
586 }
587 }
588 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700589 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300590
591 usb_set_intfdata(psIntfAdapter->interface, psIntfAdapter);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700592
593 psIntfAdapter->psAdapter->bcm_file_download = InterfaceFileDownload;
594 psIntfAdapter->psAdapter->bcm_file_readback_from_chip =
595 InterfaceFileReadbackFromChip;
596 psIntfAdapter->psAdapter->interface_transmit = InterfaceTransmitPacket;
597
598 retval = CreateInterruptUrb(psIntfAdapter);
599
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300600 if (retval) {
Dan Carpenter07a7f682010-12-06 10:03:13 +0300601 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
602 "Cannot create interrupt urb\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700603 return retval;
604 }
605
606 retval = AllocUsbCb(psIntfAdapter);
Dan Carpenter37db5262010-12-06 10:03:38 +0300607 if (retval)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700608 return retval;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700609
Stephen Hemminger032100f2010-11-01 10:03:29 -0400610 return device_run(psIntfAdapter);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700611}
Arnd Bergmann44a17eff2010-09-30 10:24:12 +0200612
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300613static int InterfaceSuspend(struct usb_interface *intf, pm_message_t message)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700614{
615 PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
Stephen Hemminger2d087482010-11-01 12:14:01 -0400616
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700617 psIntfAdapter->bSuspended = TRUE;
618
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300619 if (TRUE == psIntfAdapter->bPreparingForBusSuspend) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700620 psIntfAdapter->bPreparingForBusSuspend = FALSE;
621
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300622 if (psIntfAdapter->psAdapter->LinkStatus == LINKUP_DONE) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700623 psIntfAdapter->psAdapter->IdleMode = TRUE ;
Dan Carpenter07a7f682010-12-06 10:03:13 +0300624 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
625 "Host Entered in PMU Idle Mode.\n");
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300626 } else {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700627 psIntfAdapter->psAdapter->bShutStatus = TRUE;
Dan Carpenter07a7f682010-12-06 10:03:13 +0300628 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
629 "Host Entered in PMU Shutdown Mode.\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700630 }
631 }
632 psIntfAdapter->psAdapter->bPreparingForLowPowerMode = FALSE;
633
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300634 /* Signaling the control pkt path */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700635 wake_up(&psIntfAdapter->psAdapter->lowpower_mode_wait_queue);
636
637 return 0;
638}
Arnd Bergmann44a17eff2010-09-30 10:24:12 +0200639
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300640static int InterfaceResume(struct usb_interface *intf)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700641{
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300642 PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
Dan Carpentercd0b0eb2010-12-06 10:02:36 +0300643
Kevin McKinneyf969f842011-10-10 21:01:48 -0400644 mdelay(100);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700645 psIntfAdapter->bSuspended = FALSE;
646
647 StartInterruptUrb(psIntfAdapter);
648 InterfaceRx(psIntfAdapter);
649 return 0;
650}
Arnd Bergmann44a17eff2010-09-30 10:24:12 +0200651
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700652static struct usb_driver usbbcm_driver = {
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300653 .name = "usbbcm",
654 .probe = usbbcm_device_probe,
655 .disconnect = usbbcm_disconnect,
656 .suspend = InterfaceSuspend,
657 .resume = InterfaceResume,
658 .id_table = InterfaceUsbtable,
659 .supports_autosuspend = 1,
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700660};
661
Stephen Hemminger9e0a3162010-11-01 10:17:54 -0400662struct class *bcm_class;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700663
Stephen Hemminger2d087482010-11-01 12:14:01 -0400664static __init int bcm_init(void)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700665{
Stephen Hemminger2d087482010-11-01 12:14:01 -0400666 printk(KERN_INFO "%s: %s, %s\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION);
667 printk(KERN_INFO "%s\n", DRV_COPYRIGHT);
668
Stephen Hemminger9e0a3162010-11-01 10:17:54 -0400669 bcm_class = class_create(THIS_MODULE, DRV_NAME);
670 if (IS_ERR(bcm_class)) {
671 printk(KERN_ERR DRV_NAME ": could not create class\n");
672 return PTR_ERR(bcm_class);
673 }
Stephen Hemminger2d087482010-11-01 12:14:01 -0400674
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700675 return usb_register(&usbbcm_driver);
676}
677
Stephen Hemminger2d087482010-11-01 12:14:01 -0400678static __exit void bcm_exit(void)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700679{
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700680 usb_deregister(&usbbcm_driver);
Dan Carpenter6b747052010-12-06 10:02:55 +0300681 class_destroy(bcm_class);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700682}
Stephen Hemminger2d087482010-11-01 12:14:01 -0400683
684module_init(bcm_init);
685module_exit(bcm_exit);
686
687MODULE_DESCRIPTION(DRV_DESCRIPTION);
688MODULE_VERSION(DRV_VERSION);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300689MODULE_LICENSE("GPL");