blob: dd829409a8c848618dafcea91ae89d0afab99fc7 [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) },
5 { 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) },
7 { 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) },
9 { USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) },
10 { 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,
43 "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; */
48 if (psIntfAdapter->psInterruptUrb) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070049 usb_free_urb(psIntfAdapter->psInterruptUrb);
50 }
51
52 /* Free transmit URBs */
Dan Carpenterc2a0b162010-12-06 10:02:11 +030053 for (i = 0; i < MAXIMUM_USB_TCB; i++) {
54 if (psIntfAdapter->asUsbTcb[i].urb != NULL) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070055 usb_free_urb(psIntfAdapter->asUsbTcb[i].urb);
56 psIntfAdapter->asUsbTcb[i].urb = NULL;
57 }
58 }
59 /* Free receive URB and buffers */
Dan Carpenterc2a0b162010-12-06 10:02:11 +030060 for (i = 0; i < MAXIMUM_USB_RCB; i++) {
61 if (psIntfAdapter->asUsbRcb[i].urb != NULL) {
Stephen Hemminger082e8892010-11-01 09:35:21 -040062 kfree(psIntfAdapter->asUsbRcb[i].urb->transfer_buffer);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070063 usb_free_urb(psIntfAdapter->asUsbRcb[i].urb);
64 psIntfAdapter->asUsbRcb[i].urb = NULL;
65 }
66 }
67 AdapterFree(psIntfAdapter->psAdapter);
68}
69
Dan Carpenter2a3147422010-12-06 10:01:41 +030070static void ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070071{
Dan Carpenter2a3147422010-12-06 10:01:41 +030072 unsigned long ulReg = 0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070073
Dan Carpenterc2a0b162010-12-06 10:02:11 +030074 /* Program EP2 MAX_PKT_SIZE */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070075 ulReg = ntohl(EP2_MPS_REG);
Dan Carpenterc2a0b162010-12-06 10:02:11 +030076 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x128, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070077 ulReg = ntohl(EP2_MPS);
Dan Carpenterc2a0b162010-12-06 10:02:11 +030078 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x12C, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070079
80 ulReg = ntohl(EP2_CFG_REG);
Dan Carpenterc2a0b162010-12-06 10:02:11 +030081 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x132, 4, TRUE);
82 if (((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter))->bHighSpeedDevice == TRUE) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070083 ulReg = ntohl(EP2_CFG_INT);
Dan Carpenterc2a0b162010-12-06 10:02:11 +030084 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE);
85 } else {
86 /* USE BULK EP as TX in FS mode. */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070087 ulReg = ntohl(EP2_CFG_BULK);
Dan Carpenterc2a0b162010-12-06 10:02:11 +030088 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070089 }
90
Dan Carpenterc2a0b162010-12-06 10:02:11 +030091 /* Program EP4 MAX_PKT_SIZE. */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070092 ulReg = ntohl(EP4_MPS_REG);
Dan Carpenterc2a0b162010-12-06 10:02:11 +030093 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x13C, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070094 ulReg = ntohl(EP4_MPS);
Dan Carpenterc2a0b162010-12-06 10:02:11 +030095 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x140, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -070096
Dan Carpenterc2a0b162010-12-06 10:02:11 +030097 /* Program TX EP as interrupt(Alternate Setting) */
98 if (rdmalt(Adapter, 0x0F0110F8, (PUINT)&ulReg, 4)) {
99 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reading of Tx EP is failing");
100 return;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700101 }
102 ulReg |= 0x6;
103
104 ulReg = ntohl(ulReg);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300105 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1CC, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700106
107 ulReg = ntohl(EP4_CFG_REG);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300108 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C8, 4, TRUE);
109 /* Program ISOCHRONOUS EP size to zero. */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700110 ulReg = ntohl(ISO_MPS_REG);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300111 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D2, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700112 ulReg = ntohl(ISO_MPS);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300113 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D6, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700114
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300115 /*
116 * Update EEPROM Version.
117 * Read 4 bytes from 508 and modify 511 and 510.
118 */
119 ReadBeceemEEPROM(Adapter, 0x1FC, (PUINT)&ulReg);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700120 ulReg &= 0x0101FFFF;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300121 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1FC, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700122
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300123 /* Update length field if required. Also make the string NULL terminated. */
124
125 ReadBeceemEEPROM(Adapter, 0xA8, (PUINT)&ulReg);
126 if ((ulReg&0x00FF0000)>>16 > 0x30) {
127 ulReg = (ulReg&0xFF00FFFF)|(0x30<<16);
128 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0xA8, 4, TRUE);
129 }
130 ReadBeceemEEPROM(Adapter, 0x148, (PUINT)&ulReg);
131 if ((ulReg&0x00FF0000)>>16 > 0x30) {
132 ulReg = (ulReg&0xFF00FFFF)|(0x30<<16);
133 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x148, 4, TRUE);
134 }
135 ulReg = 0;
136 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x122, 4, TRUE);
137 ulReg = 0;
138 BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C2, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700139}
140
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700141static int
142usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id)
143{
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);
158
159 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 Carpenterc2a0b162010-12-06 10:02:11 +0300205 BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "psIntfAdapter 0x%p", psIntfAdapter);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700206 retval = InterfaceAdapterInit(psIntfAdapter);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300207 if (retval) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700208 /* If the Firmware/Cfg File is not present
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300209 * then return success, let the application
210 * download the files.
211 */
212 if (-ENOENT == retval) {
213 BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "File Not Found, Use App to Download\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700214 return STATUS_SUCCESS;
215 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300216 BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "InterfaceAdapterInit Failed \n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700217 usb_set_intfdata(intf, NULL);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300218 udev = interface_to_usbdev(intf);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700219 usb_put_dev(udev);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700220 InterfaceAdapterFree(psIntfAdapter);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300221 return retval;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700222 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300223 if (psAdapter->chip_id > T3) {
224 uint32_t uiNackZeroLengthInt = 4;
225
226 if (wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT, &uiNackZeroLengthInt, sizeof(uiNackZeroLengthInt))) {
Joe Perches859171c2010-11-14 19:04:48 -0800227 return -EIO;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700228 }
229 }
230
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700231 /* Check whether the USB-Device Supports remote Wake-Up */
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300232 if (USB_CONFIG_ATT_WAKEUP & udev->actconfig->desc.bmAttributes) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700233 /* If Suspend then only support dynamic suspend */
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300234 if (psAdapter->bDoSuspend) {
Randy Dunlap5fe1f1e2010-09-14 15:39:50 -0700235#ifdef CONFIG_PM
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700236 udev->autosuspend_delay = 0;
237 intf->needs_remote_wakeup = 1;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700238 usb_enable_autosuspend(udev);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300239 device_init_wakeup(&intf->dev, 1);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700240 INIT_WORK(&psIntfAdapter->usbSuspendWork, putUsbSuspend);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300241 BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Enabling USB Auto-Suspend\n");
Randy Dunlap5fe1f1e2010-09-14 15:39:50 -0700242#endif
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300243 } else {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700244 intf->needs_remote_wakeup = 0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700245 usb_disable_autosuspend(udev);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700246 }
247 }
248
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300249 psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0x0;
250 return retval;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700251}
252
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300253static void usbbcm_disconnect(struct usb_interface *intf)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700254{
Stephen Hemminger4ea4f7a2010-11-01 14:06:24 -0400255 PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
256 PMINI_ADAPTER psAdapter;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300257 struct usb_device *udev = interface_to_usbdev(intf);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700258
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300259 if (psIntfAdapter == NULL)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700260 return;
Stephen Hemminger4ea4f7a2010-11-01 14:06:24 -0400261
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700262 psAdapter = psIntfAdapter->psAdapter;
Stephen Hemminger4ea4f7a2010-11-01 14:06:24 -0400263 netif_device_detach(psAdapter->dev);
264
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300265 if (psAdapter->bDoSuspend)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700266 intf->needs_remote_wakeup = 0;
267
268 psAdapter->device_removed = TRUE ;
269 usb_set_intfdata(intf, NULL);
270 InterfaceAdapterFree(psIntfAdapter);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700271 usb_put_dev(udev);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700272}
273
Stephen Hemminger20f48652010-10-31 23:52:36 -0400274static int AllocUsbCb(PS_INTERFACE_ADAPTER psIntfAdapter)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700275{
276 int i = 0;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300277
278 for (i = 0; i < MAXIMUM_USB_TCB; i++) {
279 if ((psIntfAdapter->asUsbTcb[i].urb =
280 usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
281 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Cant allocate Tx urb for index %d", i);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700282 return -ENOMEM;
283 }
284 }
285
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300286 for (i = 0; i < MAXIMUM_USB_RCB; i++) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700287 if ((psIntfAdapter->asUsbRcb[i].urb =
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300288 usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
289 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Cant allocate Rx urb for index %d", i);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700290 return -ENOMEM;
291 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300292 if ((psIntfAdapter->asUsbRcb[i].urb->transfer_buffer =
293 kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL)) == NULL) {
294 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Cant allocate Rx buffer for index %d", i);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700295 return -ENOMEM;
296 }
297 psIntfAdapter->asUsbRcb[i].urb->transfer_buffer_length = MAX_DATA_BUFFER_SIZE;
298 }
299 return 0;
300}
301
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700302static int device_run(PS_INTERFACE_ADAPTER psIntfAdapter)
303{
Dan Carpenter2a3147422010-12-06 10:01:41 +0300304 int value = 0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700305 UINT status = STATUS_SUCCESS;
306
307 status = InitCardAndDownloadFirmware(psIntfAdapter->psAdapter);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300308 if (status != STATUS_SUCCESS) {
Stephen Hemminger2d087482010-11-01 12:14:01 -0400309 pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700310 return status;
311 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300312 if (TRUE == psIntfAdapter->psAdapter->fw_download_done) {
313 if (StartInterruptUrb(psIntfAdapter)) {
314 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Cannot send interrupt in URB");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700315 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700316
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300317 /*
318 * now register the cntrl interface.
319 * after downloading the f/w waiting for 5 sec to get the mailbox interrupt.
320 */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700321 psIntfAdapter->psAdapter->waiting_to_fw_download_done = FALSE;
322 value = wait_event_timeout(psIntfAdapter->psAdapter->ioctl_fw_dnld_wait_queue,
323 psIntfAdapter->psAdapter->waiting_to_fw_download_done, 5*HZ);
324
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300325 if (value == 0)
Stephen Hemminger2d087482010-11-01 12:14:01 -0400326 pr_err(DRV_NAME ": Mailbox Interrupt has not reached to Driver..\n");
327
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300328 if (register_control_device_interface(psIntfAdapter->psAdapter) < 0) {
Stephen Hemminger2d087482010-11-01 12:14:01 -0400329 pr_err(DRV_NAME ": Register Control Device failed...\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700330 return -EIO;
331 }
332 }
333 return 0;
334}
335
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700336
337static inline int bcm_usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
338{
339 return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
340}
341
342static inline int bcm_usb_endpoint_type(const struct usb_endpoint_descriptor *epd)
343{
344 return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
345}
346
347static inline int bcm_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
348{
349 return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
350}
351
352static inline int bcm_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
353{
354 return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
355}
356
357static inline int bcm_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
358{
359 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
360 USB_ENDPOINT_XFER_BULK);
361}
362
363static inline int bcm_usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd)
364{
365 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
366 USB_ENDPOINT_XFER_CONTROL);
367}
368
369static inline int bcm_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
370{
371 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
372 USB_ENDPOINT_XFER_INT);
373}
374
375static inline int bcm_usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
376{
377 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
378 USB_ENDPOINT_XFER_ISOC);
379}
380
381static inline int bcm_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
382{
383 return (bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_in(epd));
384}
385
386static inline int bcm_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
387{
388 return (bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_out(epd));
389}
390
391static inline int bcm_usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
392{
393 return (bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_in(epd));
394}
395
396static inline int bcm_usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
397{
398 return (bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_out(epd));
399}
400
401static inline int bcm_usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd)
402{
403 return (bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_in(epd));
404}
405
406static inline int bcm_usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd)
407{
408 return (bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_out(epd));
409}
410
Dan Carpenter2a3147422010-12-06 10:01:41 +0300411static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700412{
413 struct usb_host_interface *iface_desc;
414 struct usb_endpoint_descriptor *endpoint;
415 size_t buffer_size;
Dan Carpenter2a3147422010-12-06 10:01:41 +0300416 unsigned long value;
417 int retval = 0;
418 int usedIntOutForBulkTransfer = 0 ;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700419 BOOLEAN bBcm16 = FALSE;
420 UINT uiData = 0;
421
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700422 /* Store the usb dev into interface adapter */
Stephen Hemminger2d087482010-11-01 12:14:01 -0400423 psIntfAdapter->udev = usb_get_dev(interface_to_usbdev(psIntfAdapter->interface));
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700424
Stephen Hemminger2d087482010-11-01 12:14:01 -0400425 psIntfAdapter->bHighSpeedDevice = (psIntfAdapter->udev->speed == USB_SPEED_HIGH);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700426 psIntfAdapter->psAdapter->interface_rdm = BcmRDM;
427 psIntfAdapter->psAdapter->interface_wrm = BcmWRM;
428
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300429 if (rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG, (PUINT)&(psIntfAdapter->psAdapter->chip_id), sizeof(UINT)) < 0) {
430 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "CHIP ID Read Failed\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700431 return STATUS_FAILURE;
432 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700433
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300434 if (0xbece3200 == (psIntfAdapter->psAdapter->chip_id & ~(0xF0)))
Stephen Hemminger2d087482010-11-01 12:14:01 -0400435 psIntfAdapter->psAdapter->chip_id &= ~0xF0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700436
Stephen Hemminger2d087482010-11-01 12:14:01 -0400437 dev_info(&psIntfAdapter->udev->dev, "RDM Chip ID 0x%lx\n",
438 psIntfAdapter->psAdapter->chip_id);
439
440 iface_desc = psIntfAdapter->interface->cur_altsetting;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700441
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300442 if (psIntfAdapter->psAdapter->chip_id == T3B) {
443 /* T3B device will have EEPROM, check if EEPROM is proper and BCM16 can be done or not. */
444 BeceemEEPROMBulkRead(psIntfAdapter->psAdapter, &uiData, 0x0, 4);
445 if (uiData == BECM)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700446 bBcm16 = TRUE;
Stephen Hemminger2d087482010-11-01 12:14:01 -0400447
448 dev_info(&psIntfAdapter->udev->dev, "number of alternate setting %d\n",
449 psIntfAdapter->interface->num_altsetting);
450
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300451 if (bBcm16 == TRUE) {
452 /* selecting alternate setting one as a default setting for High Speed modem. */
453 if (psIntfAdapter->bHighSpeedDevice)
454 retval= usb_set_interface(psIntfAdapter->udev, DEFAULT_SETTING_0, ALTERNATE_SETTING_1);
455 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "BCM16 is Applicable on this dongle");
456 if (retval || (psIntfAdapter->bHighSpeedDevice == FALSE)) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700457 usedIntOutForBulkTransfer = EP2 ;
458 endpoint = &iface_desc->endpoint[EP2].desc;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300459 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Interface altsetting got failed or Moemd is configured to FS.hence will work on default setting 0 \n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700460 /*
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300461 * If Modem is high speed device EP2 should be INT OUT End point
462 * If Mode is FS then EP2 should be bulk end point
463 */
464 if (((psIntfAdapter->bHighSpeedDevice == TRUE) && (bcm_usb_endpoint_is_int_out(endpoint) == FALSE))
465 || ((psIntfAdapter->bHighSpeedDevice == FALSE) && (bcm_usb_endpoint_is_bulk_out(endpoint) == FALSE))) {
466 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Configuring the EEPROM ");
467 /* change the EP2, EP4 to INT OUT end point */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700468 ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter);
469
470 /*
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300471 * It resets the device and if any thing gets changed
472 * in USB descriptor it will show fail and re-enumerate
473 * the device
474 */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700475 retval = usb_reset_device(psIntfAdapter->udev);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300476 if (retval) {
477 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reset got failed. hence Re-enumerating the device \n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700478 return retval ;
479 }
480
481 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300482 if ((psIntfAdapter->bHighSpeedDevice == FALSE) && bcm_usb_endpoint_is_bulk_out(endpoint)) {
483 /* Once BULK is selected in FS mode. Revert it back to INT. Else USB_IF will fail. */
Arnd Bergmann44a17eff2010-09-30 10:24:12 +0200484 UINT _uiData = ntohl(EP2_CFG_INT);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300485 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Reverting Bulk to INT as it is FS MODE");
486 BeceemEEPROMBulkWrite(psIntfAdapter->psAdapter, (PUCHAR)&_uiData, 0x136, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700487 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300488 } else {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700489 usedIntOutForBulkTransfer = EP4 ;
490 endpoint = &iface_desc->endpoint[EP4].desc;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300491 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Choosing AltSetting as a default setting");
492 if (bcm_usb_endpoint_is_int_out(endpoint) == FALSE) {
493 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, " Dongle does not have BCM16 Fix");
494 /* change the EP2, EP4 to INT OUT end point and use EP4 in altsetting */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700495 ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter);
496
497 /*
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300498 * It resets the device and if any thing gets changed in
499 * USB descriptor it will show fail and re-enumerate the
500 * device
501 */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700502 retval = usb_reset_device(psIntfAdapter->udev);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300503 if (retval) {
504 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reset got failed. hence Re-enumerating the device \n");
505 return retval;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700506 }
507
508 }
509 }
510 }
511 }
512
513 iface_desc = psIntfAdapter->interface->cur_altsetting;
Stephen Hemminger2d087482010-11-01 12:14:01 -0400514
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300515 for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value) {
Stephen Hemminger2d087482010-11-01 12:14:01 -0400516 endpoint = &iface_desc->endpoint[value].desc;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700517
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300518 if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && bcm_usb_endpoint_is_bulk_in(endpoint)) {
519 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
520 psIntfAdapter->sBulkIn.bulk_in_size = buffer_size;
521 psIntfAdapter->sBulkIn.bulk_in_endpointAddr = endpoint->bEndpointAddress;
522 psIntfAdapter->sBulkIn.bulk_in_pipe =
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700523 usb_rcvbulkpipe(psIntfAdapter->udev,
524 psIntfAdapter->sBulkIn.bulk_in_endpointAddr);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300525 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700526
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300527 if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && bcm_usb_endpoint_is_bulk_out(endpoint)) {
528 psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress;
529 psIntfAdapter->sBulkOut.bulk_out_pipe =
530 usb_sndbulkpipe(psIntfAdapter->udev,
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700531 psIntfAdapter->sBulkOut.bulk_out_endpointAddr);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300532 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700533
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300534 if (!psIntfAdapter->sIntrIn.int_in_endpointAddr && bcm_usb_endpoint_is_int_in(endpoint)) {
535 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
536 psIntfAdapter->sIntrIn.int_in_size = buffer_size;
537 psIntfAdapter->sIntrIn.int_in_endpointAddr = endpoint->bEndpointAddress;
538 psIntfAdapter->sIntrIn.int_in_interval = endpoint->bInterval;
539 psIntfAdapter->sIntrIn.int_in_buffer =
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700540 kmalloc(buffer_size, GFP_KERNEL);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300541 if (!psIntfAdapter->sIntrIn.int_in_buffer) {
Stephen Hemminger2d087482010-11-01 12:14:01 -0400542 dev_err(&psIntfAdapter->udev->dev,
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300543 "could not allocate interrupt_in_buffer\n");
544 return -EINVAL;
Stephen Hemminger2d087482010-11-01 12:14:01 -0400545 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300546 }
547
548 if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && bcm_usb_endpoint_is_int_out(endpoint)) {
549 if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr &&
550 (psIntfAdapter->psAdapter->chip_id == T3B) && (value == usedIntOutForBulkTransfer)) {
551 /* use first intout end point as a bulk out end point */
552 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
553 psIntfAdapter->sBulkOut.bulk_out_size = buffer_size;
554 psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress;
555 psIntfAdapter->sBulkOut.bulk_out_pipe = usb_sndintpipe(psIntfAdapter->udev,
556 psIntfAdapter->sBulkOut.bulk_out_endpointAddr);
557 psIntfAdapter->sBulkOut.int_out_interval = endpoint->bInterval;
558 } else if (value == EP6) {
559 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
560 psIntfAdapter->sIntrOut.int_out_size = buffer_size;
561 psIntfAdapter->sIntrOut.int_out_endpointAddr = endpoint->bEndpointAddress;
562 psIntfAdapter->sIntrOut.int_out_interval = endpoint->bInterval;
563 psIntfAdapter->sIntrOut.int_out_buffer= kmalloc(buffer_size, GFP_KERNEL);
564 if (!psIntfAdapter->sIntrOut.int_out_buffer) {
565 dev_err(&psIntfAdapter->udev->dev,
566 "could not allocate interrupt_out_buffer\n");
567 return -EINVAL;
568 }
569 }
570 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700571 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300572
573 usb_set_intfdata(psIntfAdapter->interface, psIntfAdapter);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700574
575 psIntfAdapter->psAdapter->bcm_file_download = InterfaceFileDownload;
576 psIntfAdapter->psAdapter->bcm_file_readback_from_chip =
577 InterfaceFileReadbackFromChip;
578 psIntfAdapter->psAdapter->interface_transmit = InterfaceTransmitPacket;
579
580 retval = CreateInterruptUrb(psIntfAdapter);
581
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300582 if (retval) {
583 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Cannot create interrupt urb");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700584 return retval;
585 }
586
587 retval = AllocUsbCb(psIntfAdapter);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300588 if (retval) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700589 return retval;
590 }
591
Stephen Hemminger032100f2010-11-01 10:03:29 -0400592 return device_run(psIntfAdapter);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700593}
Arnd Bergmann44a17eff2010-09-30 10:24:12 +0200594
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300595static int InterfaceSuspend(struct usb_interface *intf, pm_message_t message)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700596{
597 PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
Stephen Hemminger2d087482010-11-01 12:14:01 -0400598
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700599 psIntfAdapter->bSuspended = TRUE;
600
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300601 if (TRUE == psIntfAdapter->bPreparingForBusSuspend) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700602 psIntfAdapter->bPreparingForBusSuspend = FALSE;
603
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300604 if (psIntfAdapter->psAdapter->LinkStatus == LINKUP_DONE) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700605 psIntfAdapter->psAdapter->IdleMode = TRUE ;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300606 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Host Entered in PMU Idle Mode..");
607 } else {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700608 psIntfAdapter->psAdapter->bShutStatus = TRUE;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300609 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Host Entered in PMU Shutdown Mode..");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700610 }
611 }
612 psIntfAdapter->psAdapter->bPreparingForLowPowerMode = FALSE;
613
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300614 /* Signaling the control pkt path */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700615 wake_up(&psIntfAdapter->psAdapter->lowpower_mode_wait_queue);
616
617 return 0;
618}
Arnd Bergmann44a17eff2010-09-30 10:24:12 +0200619
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300620static int InterfaceResume(struct usb_interface *intf)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700621{
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300622 PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700623 printk("=================================\n");
624 mdelay(100);
Dan Carpentercd0b0eb2010-12-06 10:02:36 +0300625
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700626 psIntfAdapter->bSuspended = FALSE;
627
628 StartInterruptUrb(psIntfAdapter);
629 InterfaceRx(psIntfAdapter);
630 return 0;
631}
Arnd Bergmann44a17eff2010-09-30 10:24:12 +0200632
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700633static struct usb_driver usbbcm_driver = {
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300634 .name = "usbbcm",
635 .probe = usbbcm_device_probe,
636 .disconnect = usbbcm_disconnect,
637 .suspend = InterfaceSuspend,
638 .resume = InterfaceResume,
639 .id_table = InterfaceUsbtable,
640 .supports_autosuspend = 1,
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700641};
642
Stephen Hemminger9e0a3162010-11-01 10:17:54 -0400643struct class *bcm_class;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700644
Stephen Hemminger2d087482010-11-01 12:14:01 -0400645static __init int bcm_init(void)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700646{
Stephen Hemminger2d087482010-11-01 12:14:01 -0400647 printk(KERN_INFO "%s: %s, %s\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION);
648 printk(KERN_INFO "%s\n", DRV_COPYRIGHT);
649
Stephen Hemminger9e0a3162010-11-01 10:17:54 -0400650 bcm_class = class_create(THIS_MODULE, DRV_NAME);
651 if (IS_ERR(bcm_class)) {
652 printk(KERN_ERR DRV_NAME ": could not create class\n");
653 return PTR_ERR(bcm_class);
654 }
Stephen Hemminger2d087482010-11-01 12:14:01 -0400655
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700656 return usb_register(&usbbcm_driver);
657}
658
Stephen Hemminger2d087482010-11-01 12:14:01 -0400659static __exit void bcm_exit(void)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700660{
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300661 class_destroy(bcm_class);
Stephen Hemminger2d087482010-11-01 12:14:01 -0400662
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700663 usb_deregister(&usbbcm_driver);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700664}
Stephen Hemminger2d087482010-11-01 12:14:01 -0400665
666module_init(bcm_init);
667module_exit(bcm_exit);
668
669MODULE_DESCRIPTION(DRV_DESCRIPTION);
670MODULE_VERSION(DRV_VERSION);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300671MODULE_LICENSE("GPL");