blob: 844e5faacca0e81b6daaa04f6a625fd7f71abb3d [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;
238#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300239 udev->autosuspend_disabled = 0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700240#else
241 usb_enable_autosuspend(udev);
242#endif
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300243 device_init_wakeup(&intf->dev, 1);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700244#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300245 usb_autopm_disable(intf);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700246#endif
247 INIT_WORK(&psIntfAdapter->usbSuspendWork, putUsbSuspend);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300248 BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Enabling USB Auto-Suspend\n");
Randy Dunlap5fe1f1e2010-09-14 15:39:50 -0700249#endif
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300250 } else {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700251 intf->needs_remote_wakeup = 0;
252#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300253 udev->autosuspend_disabled = 1;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700254#else
255 usb_disable_autosuspend(udev);
256#endif
257 }
258 }
259
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300260 psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0x0;
261 return retval;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700262}
263
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300264static void usbbcm_disconnect(struct usb_interface *intf)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700265{
Stephen Hemminger4ea4f7a2010-11-01 14:06:24 -0400266 PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
267 PMINI_ADAPTER psAdapter;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300268 struct usb_device *udev = interface_to_usbdev(intf);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700269
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300270 if (psIntfAdapter == NULL)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700271 return;
Stephen Hemminger4ea4f7a2010-11-01 14:06:24 -0400272
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700273 psAdapter = psIntfAdapter->psAdapter;
Stephen Hemminger4ea4f7a2010-11-01 14:06:24 -0400274 netif_device_detach(psAdapter->dev);
275
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300276 if (psAdapter->bDoSuspend)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700277 intf->needs_remote_wakeup = 0;
278
279 psAdapter->device_removed = TRUE ;
280 usb_set_intfdata(intf, NULL);
281 InterfaceAdapterFree(psIntfAdapter);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700282 usb_put_dev(udev);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700283}
284
Stephen Hemminger20f48652010-10-31 23:52:36 -0400285static int AllocUsbCb(PS_INTERFACE_ADAPTER psIntfAdapter)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700286{
287 int i = 0;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300288
289 for (i = 0; i < MAXIMUM_USB_TCB; i++) {
290 if ((psIntfAdapter->asUsbTcb[i].urb =
291 usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
292 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 -0700293 return -ENOMEM;
294 }
295 }
296
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300297 for (i = 0; i < MAXIMUM_USB_RCB; i++) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700298 if ((psIntfAdapter->asUsbRcb[i].urb =
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300299 usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
300 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 -0700301 return -ENOMEM;
302 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300303 if ((psIntfAdapter->asUsbRcb[i].urb->transfer_buffer =
304 kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL)) == NULL) {
305 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 -0700306 return -ENOMEM;
307 }
308 psIntfAdapter->asUsbRcb[i].urb->transfer_buffer_length = MAX_DATA_BUFFER_SIZE;
309 }
310 return 0;
311}
312
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700313static int device_run(PS_INTERFACE_ADAPTER psIntfAdapter)
314{
Dan Carpenter2a3147422010-12-06 10:01:41 +0300315 int value = 0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700316 UINT status = STATUS_SUCCESS;
317
318 status = InitCardAndDownloadFirmware(psIntfAdapter->psAdapter);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300319 if (status != STATUS_SUCCESS) {
Stephen Hemminger2d087482010-11-01 12:14:01 -0400320 pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700321 return status;
322 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300323 if (TRUE == psIntfAdapter->psAdapter->fw_download_done) {
324 if (StartInterruptUrb(psIntfAdapter)) {
325 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 -0700326 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700327
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300328 /*
329 * now register the cntrl interface.
330 * after downloading the f/w waiting for 5 sec to get the mailbox interrupt.
331 */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700332 psIntfAdapter->psAdapter->waiting_to_fw_download_done = FALSE;
333 value = wait_event_timeout(psIntfAdapter->psAdapter->ioctl_fw_dnld_wait_queue,
334 psIntfAdapter->psAdapter->waiting_to_fw_download_done, 5*HZ);
335
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300336 if (value == 0)
Stephen Hemminger2d087482010-11-01 12:14:01 -0400337 pr_err(DRV_NAME ": Mailbox Interrupt has not reached to Driver..\n");
338
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300339 if (register_control_device_interface(psIntfAdapter->psAdapter) < 0) {
Stephen Hemminger2d087482010-11-01 12:14:01 -0400340 pr_err(DRV_NAME ": Register Control Device failed...\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700341 return -EIO;
342 }
343 }
344 return 0;
345}
346
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700347
348static inline int bcm_usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
349{
350 return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
351}
352
353static inline int bcm_usb_endpoint_type(const struct usb_endpoint_descriptor *epd)
354{
355 return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
356}
357
358static inline int bcm_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
359{
360 return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
361}
362
363static inline int bcm_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
364{
365 return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
366}
367
368static inline int bcm_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
369{
370 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
371 USB_ENDPOINT_XFER_BULK);
372}
373
374static inline int bcm_usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd)
375{
376 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
377 USB_ENDPOINT_XFER_CONTROL);
378}
379
380static inline int bcm_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
381{
382 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
383 USB_ENDPOINT_XFER_INT);
384}
385
386static inline int bcm_usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
387{
388 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
389 USB_ENDPOINT_XFER_ISOC);
390}
391
392static inline int bcm_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
393{
394 return (bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_in(epd));
395}
396
397static inline int bcm_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
398{
399 return (bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_out(epd));
400}
401
402static inline int bcm_usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
403{
404 return (bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_in(epd));
405}
406
407static inline int bcm_usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
408{
409 return (bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_out(epd));
410}
411
412static inline int bcm_usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd)
413{
414 return (bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_in(epd));
415}
416
417static inline int bcm_usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd)
418{
419 return (bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_out(epd));
420}
421
Dan Carpenter2a3147422010-12-06 10:01:41 +0300422static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700423{
424 struct usb_host_interface *iface_desc;
425 struct usb_endpoint_descriptor *endpoint;
426 size_t buffer_size;
Dan Carpenter2a3147422010-12-06 10:01:41 +0300427 unsigned long value;
428 int retval = 0;
429 int usedIntOutForBulkTransfer = 0 ;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700430 BOOLEAN bBcm16 = FALSE;
431 UINT uiData = 0;
432
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700433 /* Store the usb dev into interface adapter */
Stephen Hemminger2d087482010-11-01 12:14:01 -0400434 psIntfAdapter->udev = usb_get_dev(interface_to_usbdev(psIntfAdapter->interface));
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700435
Stephen Hemminger2d087482010-11-01 12:14:01 -0400436 psIntfAdapter->bHighSpeedDevice = (psIntfAdapter->udev->speed == USB_SPEED_HIGH);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700437 psIntfAdapter->psAdapter->interface_rdm = BcmRDM;
438 psIntfAdapter->psAdapter->interface_wrm = BcmWRM;
439
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300440 if (rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG, (PUINT)&(psIntfAdapter->psAdapter->chip_id), sizeof(UINT)) < 0) {
441 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "CHIP ID Read Failed\n");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700442 return STATUS_FAILURE;
443 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700444
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300445 if (0xbece3200 == (psIntfAdapter->psAdapter->chip_id & ~(0xF0)))
Stephen Hemminger2d087482010-11-01 12:14:01 -0400446 psIntfAdapter->psAdapter->chip_id &= ~0xF0;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700447
Stephen Hemminger2d087482010-11-01 12:14:01 -0400448 dev_info(&psIntfAdapter->udev->dev, "RDM Chip ID 0x%lx\n",
449 psIntfAdapter->psAdapter->chip_id);
450
451 iface_desc = psIntfAdapter->interface->cur_altsetting;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700452
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300453 if (psIntfAdapter->psAdapter->chip_id == T3B) {
454 /* T3B device will have EEPROM, check if EEPROM is proper and BCM16 can be done or not. */
455 BeceemEEPROMBulkRead(psIntfAdapter->psAdapter, &uiData, 0x0, 4);
456 if (uiData == BECM)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700457 bBcm16 = TRUE;
Stephen Hemminger2d087482010-11-01 12:14:01 -0400458
459 dev_info(&psIntfAdapter->udev->dev, "number of alternate setting %d\n",
460 psIntfAdapter->interface->num_altsetting);
461
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300462 if (bBcm16 == TRUE) {
463 /* selecting alternate setting one as a default setting for High Speed modem. */
464 if (psIntfAdapter->bHighSpeedDevice)
465 retval= usb_set_interface(psIntfAdapter->udev, DEFAULT_SETTING_0, ALTERNATE_SETTING_1);
466 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "BCM16 is Applicable on this dongle");
467 if (retval || (psIntfAdapter->bHighSpeedDevice == FALSE)) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700468 usedIntOutForBulkTransfer = EP2 ;
469 endpoint = &iface_desc->endpoint[EP2].desc;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300470 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 -0700471 /*
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300472 * If Modem is high speed device EP2 should be INT OUT End point
473 * If Mode is FS then EP2 should be bulk end point
474 */
475 if (((psIntfAdapter->bHighSpeedDevice == TRUE) && (bcm_usb_endpoint_is_int_out(endpoint) == FALSE))
476 || ((psIntfAdapter->bHighSpeedDevice == FALSE) && (bcm_usb_endpoint_is_bulk_out(endpoint) == FALSE))) {
477 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Configuring the EEPROM ");
478 /* change the EP2, EP4 to INT OUT end point */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700479 ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter);
480
481 /*
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300482 * It resets the device and if any thing gets changed
483 * in USB descriptor it will show fail and re-enumerate
484 * the device
485 */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700486 retval = usb_reset_device(psIntfAdapter->udev);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300487 if (retval) {
488 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 -0700489 return retval ;
490 }
491
492 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300493 if ((psIntfAdapter->bHighSpeedDevice == FALSE) && bcm_usb_endpoint_is_bulk_out(endpoint)) {
494 /* Once BULK is selected in FS mode. Revert it back to INT. Else USB_IF will fail. */
Arnd Bergmann44a17eff2010-09-30 10:24:12 +0200495 UINT _uiData = ntohl(EP2_CFG_INT);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300496 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Reverting Bulk to INT as it is FS MODE");
497 BeceemEEPROMBulkWrite(psIntfAdapter->psAdapter, (PUCHAR)&_uiData, 0x136, 4, TRUE);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700498 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300499 } else {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700500 usedIntOutForBulkTransfer = EP4 ;
501 endpoint = &iface_desc->endpoint[EP4].desc;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300502 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Choosing AltSetting as a default setting");
503 if (bcm_usb_endpoint_is_int_out(endpoint) == FALSE) {
504 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, " Dongle does not have BCM16 Fix");
505 /* change the EP2, EP4 to INT OUT end point and use EP4 in altsetting */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700506 ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter);
507
508 /*
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300509 * It resets the device and if any thing gets changed in
510 * USB descriptor it will show fail and re-enumerate the
511 * device
512 */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700513 retval = usb_reset_device(psIntfAdapter->udev);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300514 if (retval) {
515 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "reset got failed. hence Re-enumerating the device \n");
516 return retval;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700517 }
518
519 }
520 }
521 }
522 }
523
524 iface_desc = psIntfAdapter->interface->cur_altsetting;
Stephen Hemminger2d087482010-11-01 12:14:01 -0400525
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300526 for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value) {
Stephen Hemminger2d087482010-11-01 12:14:01 -0400527 endpoint = &iface_desc->endpoint[value].desc;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700528
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300529 if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && bcm_usb_endpoint_is_bulk_in(endpoint)) {
530 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
531 psIntfAdapter->sBulkIn.bulk_in_size = buffer_size;
532 psIntfAdapter->sBulkIn.bulk_in_endpointAddr = endpoint->bEndpointAddress;
533 psIntfAdapter->sBulkIn.bulk_in_pipe =
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700534 usb_rcvbulkpipe(psIntfAdapter->udev,
535 psIntfAdapter->sBulkIn.bulk_in_endpointAddr);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300536 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700537
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300538 if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && bcm_usb_endpoint_is_bulk_out(endpoint)) {
539 psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress;
540 psIntfAdapter->sBulkOut.bulk_out_pipe =
541 usb_sndbulkpipe(psIntfAdapter->udev,
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700542 psIntfAdapter->sBulkOut.bulk_out_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->sIntrIn.int_in_endpointAddr && bcm_usb_endpoint_is_int_in(endpoint)) {
546 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
547 psIntfAdapter->sIntrIn.int_in_size = buffer_size;
548 psIntfAdapter->sIntrIn.int_in_endpointAddr = endpoint->bEndpointAddress;
549 psIntfAdapter->sIntrIn.int_in_interval = endpoint->bInterval;
550 psIntfAdapter->sIntrIn.int_in_buffer =
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700551 kmalloc(buffer_size, GFP_KERNEL);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300552 if (!psIntfAdapter->sIntrIn.int_in_buffer) {
Stephen Hemminger2d087482010-11-01 12:14:01 -0400553 dev_err(&psIntfAdapter->udev->dev,
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300554 "could not allocate interrupt_in_buffer\n");
555 return -EINVAL;
Stephen Hemminger2d087482010-11-01 12:14:01 -0400556 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300557 }
558
559 if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && bcm_usb_endpoint_is_int_out(endpoint)) {
560 if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr &&
561 (psIntfAdapter->psAdapter->chip_id == T3B) && (value == usedIntOutForBulkTransfer)) {
562 /* use first intout end point as a bulk out end point */
563 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
564 psIntfAdapter->sBulkOut.bulk_out_size = buffer_size;
565 psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress;
566 psIntfAdapter->sBulkOut.bulk_out_pipe = usb_sndintpipe(psIntfAdapter->udev,
567 psIntfAdapter->sBulkOut.bulk_out_endpointAddr);
568 psIntfAdapter->sBulkOut.int_out_interval = endpoint->bInterval;
569 } else if (value == EP6) {
570 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
571 psIntfAdapter->sIntrOut.int_out_size = buffer_size;
572 psIntfAdapter->sIntrOut.int_out_endpointAddr = endpoint->bEndpointAddress;
573 psIntfAdapter->sIntrOut.int_out_interval = endpoint->bInterval;
574 psIntfAdapter->sIntrOut.int_out_buffer= kmalloc(buffer_size, GFP_KERNEL);
575 if (!psIntfAdapter->sIntrOut.int_out_buffer) {
576 dev_err(&psIntfAdapter->udev->dev,
577 "could not allocate interrupt_out_buffer\n");
578 return -EINVAL;
579 }
580 }
581 }
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700582 }
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300583
584 usb_set_intfdata(psIntfAdapter->interface, psIntfAdapter);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700585
586 psIntfAdapter->psAdapter->bcm_file_download = InterfaceFileDownload;
587 psIntfAdapter->psAdapter->bcm_file_readback_from_chip =
588 InterfaceFileReadbackFromChip;
589 psIntfAdapter->psAdapter->interface_transmit = InterfaceTransmitPacket;
590
591 retval = CreateInterruptUrb(psIntfAdapter);
592
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300593 if (retval) {
594 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Cannot create interrupt urb");
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700595 return retval;
596 }
597
598 retval = AllocUsbCb(psIntfAdapter);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300599 if (retval) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700600 return retval;
601 }
602
Stephen Hemminger032100f2010-11-01 10:03:29 -0400603 return device_run(psIntfAdapter);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700604}
Arnd Bergmann44a17eff2010-09-30 10:24:12 +0200605
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300606static int InterfaceSuspend(struct usb_interface *intf, pm_message_t message)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700607{
608 PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
Stephen Hemminger2d087482010-11-01 12:14:01 -0400609
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700610 psIntfAdapter->bSuspended = TRUE;
611
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300612 if (TRUE == psIntfAdapter->bPreparingForBusSuspend) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700613 psIntfAdapter->bPreparingForBusSuspend = FALSE;
614
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300615 if (psIntfAdapter->psAdapter->LinkStatus == LINKUP_DONE) {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700616 psIntfAdapter->psAdapter->IdleMode = TRUE ;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300617 BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Host Entered in PMU Idle Mode..");
618 } else {
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700619 psIntfAdapter->psAdapter->bShutStatus = TRUE;
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300620 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 -0700621 }
622 }
623 psIntfAdapter->psAdapter->bPreparingForLowPowerMode = FALSE;
624
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300625 /* Signaling the control pkt path */
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700626 wake_up(&psIntfAdapter->psAdapter->lowpower_mode_wait_queue);
627
628 return 0;
629}
Arnd Bergmann44a17eff2010-09-30 10:24:12 +0200630
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300631static int InterfaceResume(struct usb_interface *intf)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700632{
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300633 PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700634 printk("=================================\n");
635 mdelay(100);
636#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300637 intf->pm_usage_cnt =1 ;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700638#endif
639 psIntfAdapter->bSuspended = FALSE;
640
641 StartInterruptUrb(psIntfAdapter);
642 InterfaceRx(psIntfAdapter);
643 return 0;
644}
Arnd Bergmann44a17eff2010-09-30 10:24:12 +0200645
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700646static struct usb_driver usbbcm_driver = {
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300647 .name = "usbbcm",
648 .probe = usbbcm_device_probe,
649 .disconnect = usbbcm_disconnect,
650 .suspend = InterfaceSuspend,
651 .resume = InterfaceResume,
652 .id_table = InterfaceUsbtable,
653 .supports_autosuspend = 1,
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700654};
655
Stephen Hemminger9e0a3162010-11-01 10:17:54 -0400656struct class *bcm_class;
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700657
Stephen Hemminger2d087482010-11-01 12:14:01 -0400658static __init int bcm_init(void)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700659{
Stephen Hemminger2d087482010-11-01 12:14:01 -0400660 printk(KERN_INFO "%s: %s, %s\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION);
661 printk(KERN_INFO "%s\n", DRV_COPYRIGHT);
662
Stephen Hemminger9e0a3162010-11-01 10:17:54 -0400663 bcm_class = class_create(THIS_MODULE, DRV_NAME);
664 if (IS_ERR(bcm_class)) {
665 printk(KERN_ERR DRV_NAME ": could not create class\n");
666 return PTR_ERR(bcm_class);
667 }
Stephen Hemminger2d087482010-11-01 12:14:01 -0400668
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700669 return usb_register(&usbbcm_driver);
670}
671
Stephen Hemminger2d087482010-11-01 12:14:01 -0400672static __exit void bcm_exit(void)
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700673{
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300674 class_destroy(bcm_class);
Stephen Hemminger2d087482010-11-01 12:14:01 -0400675
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700676 usb_deregister(&usbbcm_driver);
Stephen Hemmingerf8942e02010-09-08 14:46:36 -0700677}
Stephen Hemminger2d087482010-11-01 12:14:01 -0400678
679module_init(bcm_init);
680module_exit(bcm_exit);
681
682MODULE_DESCRIPTION(DRV_DESCRIPTION);
683MODULE_VERSION(DRV_VERSION);
Dan Carpenterc2a0b162010-12-06 10:02:11 +0300684MODULE_LICENSE("GPL");