704 lines · 23.5 KB · C
RawDownload
#include "headers.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_SM250) },	{ 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) },	{ }};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(PS_INTERFACE_ADAPTER Adapter); static void InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter){	int i = 0; 	/* Wake up the wait_queue... */	if (psIntfAdapter->psAdapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) {		psIntfAdapter->psAdapter->DriverState = DRIVER_HALT;		wake_up(&psIntfAdapter->psAdapter->LEDInfo.notify_led_event);	}	reset_card_proc(psIntfAdapter->psAdapter); 	/*	 * 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 (psIntfAdapter->psAdapter->DeviceAccess) {		BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,			"Device is being accessed.\n");		msleep(100);	}	/* Free interrupt URB */	/* psIntfAdapter->psAdapter->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(psIntfAdapter->psAdapter);} static void ConfigureEndPointTypesThroughEEPROM(struct bcm_mini_adapter *Adapter){	unsigned long ulReg = 0;	int bytes; 	/* 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);	if (((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter))->bHighSpeedDevice == TRUE) {		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, (u32 *)&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, (PUINT)&ulReg);	ulReg &= 0x0101FFFF;	BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1FC, 4, TRUE); 	/* Update length field if required. Also make the string NULL terminated. */ 	ReadBeceemEEPROM(Adapter, 0xA8, (PUINT)&ulReg);	if ((ulReg&0x00FF0000)>>16 > 0x30) {		ulReg = (ulReg&0xFF00FFFF)|(0x30<<16);		BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0xA8, 4, TRUE);	}	ReadBeceemEEPROM(Adapter, 0x148, (PUINT)&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;	PS_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(S_INTERFACE_ADAPTER), GFP_KERNEL);	if (psIntfAdapter == NULL) {		dev_err(&udev->dev, DRV_NAME ": no memory for Interface adapter\n");		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){	PS_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(PS_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(PS_INTERFACE_ADAPTER psIntfAdapter){	int value = 0;	UINT status = STATUS_SUCCESS; 	status = InitCardAndDownloadFirmware(psIntfAdapter->psAdapter);	if (status != STATUS_SUCCESS) {		pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n");		return status;	}	if (TRUE == psIntfAdapter->psAdapter->fw_download_done) {		if (StartInterruptUrb(psIntfAdapter)) {			BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, 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.		 */		psIntfAdapter->psAdapter->waiting_to_fw_download_done = FALSE;		value = wait_event_timeout(psIntfAdapter->psAdapter->ioctl_fw_dnld_wait_queue,					psIntfAdapter->psAdapter->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(psIntfAdapter->psAdapter) < 0) {			pr_err(DRV_NAME ": Register Control Device failed.\n");			return -EIO;		}	}	return 0;}  static inline int bcm_usb_endpoint_num(const struct usb_endpoint_descriptor *epd){	return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;} static inline int bcm_usb_endpoint_type(const struct usb_endpoint_descriptor *epd){	return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;} static inline int bcm_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd){	return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);} static inline int bcm_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd){	return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);} static inline int bcm_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd){	return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==		USB_ENDPOINT_XFER_BULK);} static inline int bcm_usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd){	return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==		USB_ENDPOINT_XFER_CONTROL);} static inline int bcm_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd){	return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==		USB_ENDPOINT_XFER_INT);} static inline int bcm_usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd){	return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==		USB_ENDPOINT_XFER_ISOC);} static inline int bcm_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd){	return bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_in(epd);} static inline int bcm_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd){	return bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_out(epd);} static inline int bcm_usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd){	return bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_in(epd);} static inline int bcm_usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd){	return bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_out(epd);} static inline int bcm_usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd){	return bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_in(epd);} static inline int bcm_usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd){	return bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_out(epd);} static int InterfaceAdapterInit(PS_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 ;	BOOLEAN bBcm16 = FALSE;	UINT uiData = 0;	int bytes; 	/* Store the usb dev into interface adapter */	psIntfAdapter->udev = usb_get_dev(interface_to_usbdev(psIntfAdapter->interface)); 	psIntfAdapter->bHighSpeedDevice = (psIntfAdapter->udev->speed == USB_SPEED_HIGH);	psIntfAdapter->psAdapter->interface_rdm = BcmRDM;	psIntfAdapter->psAdapter->interface_wrm = BcmWRM; 	bytes = rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG,			(u32 *)&(psIntfAdapter->psAdapter->chip_id), sizeof(u32));	if (bytes < 0) {		retval = bytes;		BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "CHIP ID Read Failed\n");		return retval;	} 	if (0xbece3200 == (psIntfAdapter->psAdapter->chip_id & ~(0xF0)))		psIntfAdapter->psAdapter->chip_id &= ~0xF0; 	dev_info(&psIntfAdapter->udev->dev, "RDM Chip ID 0x%lx\n",		 psIntfAdapter->psAdapter->chip_id); 	iface_desc = psIntfAdapter->interface->cur_altsetting; 	if (psIntfAdapter->psAdapter->chip_id == T3B) {		/* T3B device will have EEPROM, check if EEPROM is proper and BCM16 can be done or not. */		BeceemEEPROMBulkRead(psIntfAdapter->psAdapter, &uiData, 0x0, 4);		if (uiData == BECM)			bBcm16 = TRUE; 		dev_info(&psIntfAdapter->udev->dev, "number of alternate setting %d\n",			 psIntfAdapter->interface->num_altsetting); 		if (bBcm16 == TRUE) {			/* 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(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,				"BCM16 is applicable on this dongle\n");			if (retval || (psIntfAdapter->bHighSpeedDevice == FALSE)) {				usedIntOutForBulkTransfer = EP2 ;				endpoint = &iface_desc->endpoint[EP2].desc;				BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, 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 == TRUE) && (bcm_usb_endpoint_is_int_out(endpoint) == FALSE))					|| ((psIntfAdapter->bHighSpeedDevice == FALSE) && (bcm_usb_endpoint_is_bulk_out(endpoint) == FALSE))) {					BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,						"Configuring the EEPROM\n");					/* change the EP2, EP4 to INT OUT end point */					ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter); 					/*					 * 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(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,							"reset failed.  Re-enumerating the device.\n");						return retval ;					}

Lines 1–500 of 704.