729 lines · 21.2 KB · C
RawDownload
#include "headers.h"#include <linux/usb/ch9.h>static struct usb_device_id InterfaceUsbtable[] = {	{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) },	{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) },	{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) },	{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_SYM) },	{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) },	{ USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) },	{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_TU25) },	{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_226) },	{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_326) },	{ }};MODULE_DEVICE_TABLE(usb, InterfaceUsbtable); static int debug = -1;module_param(debug, uint, 0600);MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); static const u32 default_msg =	NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK	| NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR	| NETIF_MSG_IFUP | NETIF_MSG_IFDOWN; static int InterfaceAdapterInit(struct bcm_interface_adapter *Adapter); static void InterfaceAdapterFree(struct bcm_interface_adapter *psIntfAdapter){	int i = 0;	struct bcm_mini_adapter *ps_ad = psIntfAdapter->psAdapter; 	/* Wake up the wait_queue... */	if (ps_ad->LEDInfo.led_thread_running &			BCM_LED_THREAD_RUNNING_ACTIVELY) {		ps_ad->DriverState = DRIVER_HALT;		wake_up(&ps_ad->LEDInfo.notify_led_event);	}	reset_card_proc(ps_ad); 	/*	 * worst case time taken by the RDM/WRM will be 5 sec. will check after	 * every 100 ms to accertain the device is not being accessed. After	 * this No RDM/WRM should be made.	 */	while (ps_ad->DeviceAccess) {		BCM_DEBUG_PRINT(ps_ad, DBG_TYPE_INITEXIT, DRV_ENTRY,				DBG_LVL_ALL, "Device is being accessed.\n");		msleep(100);	}	/* Free interrupt URB */	/* ps_ad->device_removed = TRUE; */	usb_free_urb(psIntfAdapter->psInterruptUrb); 	/* Free transmit URBs */	for (i = 0; i < MAXIMUM_USB_TCB; i++) {		if (psIntfAdapter->asUsbTcb[i].urb  != NULL) {			usb_free_urb(psIntfAdapter->asUsbTcb[i].urb);			psIntfAdapter->asUsbTcb[i].urb = NULL;		}	}	/* Free receive URB and buffers */	for (i = 0; i < MAXIMUM_USB_RCB; i++) {		if (psIntfAdapter->asUsbRcb[i].urb != NULL) {			kfree(psIntfAdapter->asUsbRcb[i].urb->transfer_buffer);			usb_free_urb(psIntfAdapter->asUsbRcb[i].urb);			psIntfAdapter->asUsbRcb[i].urb = NULL;		}	}	AdapterFree(ps_ad);} static void ConfigureEndPointTypesThroughEEPROM(		struct bcm_mini_adapter *Adapter){	u32 ulReg;	int bytes;	struct bcm_interface_adapter *interfaceAdapter; 	/* Program EP2 MAX_PKT_SIZE */	ulReg = ntohl(EP2_MPS_REG);	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x128, 4, TRUE);	ulReg = ntohl(EP2_MPS);	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x12C, 4, TRUE); 	ulReg = ntohl(EP2_CFG_REG);	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x132, 4, TRUE);	interfaceAdapter =		(struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter);	if (interfaceAdapter->bHighSpeedDevice) {		ulReg = ntohl(EP2_CFG_INT);		BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE);	} else {		/* USE BULK EP as TX in FS mode. */		ulReg = ntohl(EP2_CFG_BULK);		BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE);	} 	/* Program EP4 MAX_PKT_SIZE. */	ulReg = ntohl(EP4_MPS_REG);	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x13C, 4, TRUE);	ulReg = ntohl(EP4_MPS);	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x140, 4, TRUE); 	/* Program TX EP as interrupt(Alternate Setting) */	bytes = rdmalt(Adapter, 0x0F0110F8, &ulReg, sizeof(u32));	if (bytes < 0) {		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY,				DBG_LVL_ALL, "reading of Tx EP failed\n");		return;	}	ulReg |= 0x6; 	ulReg = ntohl(ulReg);	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1CC, 4, TRUE); 	ulReg = ntohl(EP4_CFG_REG);	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C8, 4, TRUE);	/* Program ISOCHRONOUS EP size to zero. */	ulReg = ntohl(ISO_MPS_REG);	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D2, 4, TRUE);	ulReg = ntohl(ISO_MPS);	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D6, 4, TRUE); 	/*	 * Update EEPROM Version.	 * Read 4 bytes from 508 and modify 511 and 510.	 */	ReadBeceemEEPROM(Adapter, 0x1FC, &ulReg);	ulReg &= 0x0101FFFF;	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1FC, 4, TRUE); 	/*	 * Update length field if required.	 * Also make the string NULL terminated.	 */ 	ReadBeceemEEPROM(Adapter, 0xA8, &ulReg);	if ((ulReg&0x00FF0000)>>16 > 0x30) {		ulReg = (ulReg&0xFF00FFFF)|(0x30<<16);		BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0xA8, 4, TRUE);	}	ReadBeceemEEPROM(Adapter, 0x148, &ulReg);	if ((ulReg&0x00FF0000)>>16 > 0x30) {		ulReg = (ulReg&0xFF00FFFF)|(0x30<<16);		BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x148, 4, TRUE);	}	ulReg = 0;	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x122, 4, TRUE);	ulReg = 0;	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C2, 4, TRUE);} static int usbbcm_device_probe(struct usb_interface *intf,			       const struct usb_device_id *id){	struct usb_device *udev = interface_to_usbdev(intf);	int retval;	struct bcm_mini_adapter *psAdapter;	struct bcm_interface_adapter *psIntfAdapter;	struct net_device *ndev; 	/* Reserve one extra queue for the bit-bucket */	ndev = alloc_etherdev_mq(sizeof(struct bcm_mini_adapter),			NO_OF_QUEUES + 1);	if (ndev == NULL) {		dev_err(&udev->dev, DRV_NAME ": no memory for device\n");		return -ENOMEM;	} 	SET_NETDEV_DEV(ndev, &intf->dev); 	psAdapter = netdev_priv(ndev);	psAdapter->dev = ndev;	psAdapter->msg_enable = netif_msg_init(debug, default_msg); 	/* Init default driver debug state */ 	psAdapter->stDebugState.debug_level = DBG_LVL_CURR;	psAdapter->stDebugState.type = DBG_TYPE_INITEXIT; 	/*	 * Technically, one can start using BCM_DEBUG_PRINT after this point.	 * However, realize that by default the Type/Subtype bitmaps are all	 * zero now; so no prints will actually appear until the TestApp turns	 * on debug paths via the ioctl(); so practically speaking, in early	 * init, no logging happens.	 *	 * A solution (used below): we explicitly set the bitmaps to 1 for	 * Type=DBG_TYPE_INITEXIT and ALL subtype's of the same. Now all bcm	 * debug statements get logged, enabling debug during early init.	 * Further, we turn this OFF once init_module() completes.	 */ 	psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0xff;	BCM_SHOW_DEBUG_BITMAP(psAdapter); 	retval = InitAdapter(psAdapter);	if (retval) {		dev_err(&udev->dev, DRV_NAME ": InitAdapter Failed\n");		AdapterFree(psAdapter);		return retval;	} 	/* Allocate interface adapter structure */	psIntfAdapter = kzalloc(sizeof(struct bcm_interface_adapter),			GFP_KERNEL);	if (psIntfAdapter == NULL) {		AdapterFree(psAdapter);		return -ENOMEM;	} 	psAdapter->pvInterfaceAdapter = psIntfAdapter;	psIntfAdapter->psAdapter = psAdapter; 	/* Store usb interface in Interface Adapter */	psIntfAdapter->interface = intf;	usb_set_intfdata(intf, psIntfAdapter); 	BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,			"psIntfAdapter 0x%p\n", psIntfAdapter);	retval = InterfaceAdapterInit(psIntfAdapter);	if (retval) {		/* If the Firmware/Cfg File is not present		 * then return success, let the application		 * download the files.		 */		if (-ENOENT == retval) {			BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY,					DBG_LVL_ALL,					"File Not Found.  Use app to download.\n");			return STATUS_SUCCESS;		}		BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY,				DBG_LVL_ALL, "InterfaceAdapterInit failed.\n");		usb_set_intfdata(intf, NULL);		udev = interface_to_usbdev(intf);		usb_put_dev(udev);		InterfaceAdapterFree(psIntfAdapter);		return retval;	}	if (psAdapter->chip_id > T3) {		uint32_t uiNackZeroLengthInt = 4; 		retval =			wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT,					&uiNackZeroLengthInt,					sizeof(uiNackZeroLengthInt));		if (retval)			return retval;	} 	/* Check whether the USB-Device Supports remote Wake-Up */	if (USB_CONFIG_ATT_WAKEUP & udev->actconfig->desc.bmAttributes) {		/* If Suspend then only support dynamic suspend */		if (psAdapter->bDoSuspend) {#ifdef CONFIG_PM			pm_runtime_set_autosuspend_delay(&udev->dev, 0);			intf->needs_remote_wakeup = 1;			usb_enable_autosuspend(udev);			device_init_wakeup(&intf->dev, 1);			INIT_WORK(&psIntfAdapter->usbSuspendWork,					putUsbSuspend);			BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY,					DBG_LVL_ALL,					"Enabling USB Auto-Suspend\n");#endif		} else {			intf->needs_remote_wakeup = 0;			usb_disable_autosuspend(udev);		}	} 	psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0x0;	return retval;} static void usbbcm_disconnect(struct usb_interface *intf){	struct bcm_interface_adapter *psIntfAdapter = usb_get_intfdata(intf);	struct bcm_mini_adapter *psAdapter;	struct usb_device  *udev = interface_to_usbdev(intf); 	if (psIntfAdapter == NULL)		return; 	psAdapter = psIntfAdapter->psAdapter;	netif_device_detach(psAdapter->dev); 	if (psAdapter->bDoSuspend)		intf->needs_remote_wakeup = 0; 	psAdapter->device_removed = TRUE;	usb_set_intfdata(intf, NULL);	InterfaceAdapterFree(psIntfAdapter);	usb_put_dev(udev);} static int AllocUsbCb(struct bcm_interface_adapter *psIntfAdapter){	int i = 0; 	for (i = 0; i < MAXIMUM_USB_TCB; i++) {		psIntfAdapter->asUsbTcb[i].urb = usb_alloc_urb(0, GFP_KERNEL); 		if (psIntfAdapter->asUsbTcb[i].urb == NULL) {			BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,					DBG_TYPE_PRINTK, 0, 0,					"Can't allocate Tx urb for index %d\n",					i);			return -ENOMEM;		}	} 	for (i = 0; i < MAXIMUM_USB_RCB; i++) {		psIntfAdapter->asUsbRcb[i].urb = usb_alloc_urb(0, GFP_KERNEL); 		if (psIntfAdapter->asUsbRcb[i].urb == NULL) {			BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,					DBG_TYPE_PRINTK, 0, 0,					"Can't allocate Rx urb for index %d\n",					i);			return -ENOMEM;		} 		psIntfAdapter->asUsbRcb[i].urb->transfer_buffer =			kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL); 		if (psIntfAdapter->asUsbRcb[i].urb->transfer_buffer == NULL) {			BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,					DBG_TYPE_PRINTK, 0, 0,					"Can't allocate Rx buffer for index %d\n",					i);			return -ENOMEM;		}		psIntfAdapter->asUsbRcb[i].urb->transfer_buffer_length =			MAX_DATA_BUFFER_SIZE;	}	return 0;} static int device_run(struct bcm_interface_adapter *psIntfAdapter){	int value = 0;	UINT status = STATUS_SUCCESS;	struct bcm_mini_adapter *psAd = psIntfAdapter->psAdapter; 	status = InitCardAndDownloadFirmware(psAd);	if (status != STATUS_SUCCESS) {		pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n");		return status;	}	if (psAd->fw_download_done) {		if (StartInterruptUrb(psIntfAdapter)) {			BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,					DBG_LVL_ALL,					"Cannot send interrupt in URB\n");		} 		/*		 * now register the cntrl interface.  after downloading the f/w		 * waiting for 5 sec to get the mailbox interrupt.		 */		psAd->waiting_to_fw_download_done = false;		value = wait_event_timeout(psAd->ioctl_fw_dnld_wait_queue,					   psAd->waiting_to_fw_download_done,					   5 * HZ); 		if (value == 0)			pr_err(DRV_NAME ": Timeout waiting for mailbox interrupt.\n"); 		if (register_control_device_interface(psAd) < 0) {			pr_err(DRV_NAME ": Register Control Device failed.\n");			return -EIO;		}	}	return 0;} static int select_alternate_setting_for_highspeed_modem(		struct bcm_interface_adapter *psIntfAdapter,		struct usb_endpoint_descriptor **endpoint,		const struct usb_host_interface *iface_desc,		int *usedIntOutForBulkTransfer){	int retval = 0;	struct bcm_mini_adapter *psAd = psIntfAdapter->psAdapter; 	/* selecting alternate setting one as a default setting	 * for High Speed  modem. */	if (psIntfAdapter->bHighSpeedDevice)		retval = usb_set_interface(psIntfAdapter->udev,					   DEFAULT_SETTING_0,					   ALTERNATE_SETTING_1);	BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,			"BCM16 is applicable on this dongle\n");	if (retval || !psIntfAdapter->bHighSpeedDevice) {		*usedIntOutForBulkTransfer = EP2;		*endpoint = &iface_desc->endpoint[EP2].desc;		BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,				"Interface altsetting failed or modem is configured to Full Speed, hence will work on default setting 0\n");		/*		 * If Modem is high speed device EP2 should be		 * INT OUT End point		 *		 * If Mode is FS then EP2 should be bulk end		 * point		 */		if ((psIntfAdapter->bHighSpeedDevice &&					!usb_endpoint_is_int_out(*endpoint)) ||				(!psIntfAdapter->bHighSpeedDevice &&				 !usb_endpoint_is_bulk_out(*endpoint))) {			BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,					DBG_LVL_ALL,					"Configuring the EEPROM\n");			/* change the EP2, EP4 to INT OUT end point */			ConfigureEndPointTypesThroughEEPROM(					psAd); 			/*			 * It resets the device and if any thing			 * gets changed in USB descriptor it			 * will show fail and re-enumerate the			 * device			 */			retval = usb_reset_device(psIntfAdapter->udev);			if (retval) {				BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT,						DRV_ENTRY, DBG_LVL_ALL,						"reset failed.  Re-enumerating the device.\n");				return retval;			} 		}		if (!psIntfAdapter->bHighSpeedDevice &&		    usb_endpoint_is_bulk_out(*endpoint)) {			/*			 * Once BULK is selected in FS mode.			 * Revert it back to INT.			 * Else USB_IF will fail.			 */			UINT _uiData = ntohl(EP2_CFG_INT); 			BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,					DBG_LVL_ALL,					"Reverting Bulk to INT as it is in Full Speed mode.\n");			BeceemEEPROMBulkWrite(psAd, (PUCHAR) & _uiData, 0x136,					      4, TRUE);		}	} else {		*usedIntOutForBulkTransfer = EP4;		*endpoint = &iface_desc->endpoint[EP4].desc;		BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,				"Choosing AltSetting as a default setting.\n");		if (!usb_endpoint_is_int_out(*endpoint)) {			BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,					DBG_LVL_ALL,					"Dongle does not have BCM16 Fix.\n");			/*			 * change the EP2, EP4 to INT OUT end point and use EP4			 * in altsetting			 */			ConfigureEndPointTypesThroughEEPROM(psAd); 			/*			 * It resets the device and if any thing			 * gets changed in USB descriptor it			 * will show fail and re-enumerate the			 * device			 */			retval = usb_reset_device(psIntfAdapter->udev);			if (retval) {				BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT,						DRV_ENTRY, DBG_LVL_ALL,						"reset failed.  Re-enumerating the device.\n");				return retval;			}		}	} 	return 0;} static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter){	struct usb_host_interface *iface_desc;	struct usb_endpoint_descriptor *endpoint;	size_t buffer_size;	unsigned long value;	int retval = 0;	int usedIntOutForBulkTransfer = 0;	bool bBcm16 = false;	UINT uiData = 0;	int bytes;	struct bcm_mini_adapter *psAd = psIntfAdapter->psAdapter; 	/* Store the usb dev into interface adapter */	psIntfAdapter->udev =		usb_get_dev(interface_to_usbdev(psIntfAdapter->interface)); 

Lines 1–500 of 729.