⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_usb.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
				    "Received valid boot command response\n");		}		kfree_skb(skb);		if_usb_submit_rx_urb_fwload(cardp);		return;	}	syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);	if (!syncfwheader) {		lbs_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");		kfree_skb(skb);		return;	}	memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET,			sizeof(struct fwsyncheader));	if (!syncfwheader->cmd) {		/*		lbs_deb_usbd(&cardp->udev->dev,			    "FW received Blk with correct CRC\n");		lbs_deb_usbd(&cardp->udev->dev,			    "FW received Blk seqnum = %d\n",		       syncfwheader->seqnum);		*/		cardp->CRC_OK = 1;	} else {		lbs_deb_usbd(&cardp->udev->dev,			    "FW received Blk with CRC error\n");		cardp->CRC_OK = 0;	}	kfree_skb(skb);	if (cardp->fwfinalblk) {		cardp->fwdnldover = 1;		goto exit;	}	if_prog_firmware(cardp);	if_usb_submit_rx_urb_fwload(cardp);exit:	kfree(syncfwheader);	return;}#define MRVDRV_MIN_PKT_LEN	30static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,				       struct usb_card_rec *cardp,				       wlan_private *priv){	if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE +	    MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) {		lbs_deb_usbd(&cardp->udev->dev,			    "Packet length is Invalid\n");		kfree_skb(skb);		return;	}	skb_reserve(skb, IPFIELD_ALIGN_OFFSET);	skb_put(skb, recvlength);	skb_pull(skb, MESSAGE_HEADER_LEN);	libertas_process_rxed_packet(priv, skb);	priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);}static inline void process_cmdrequest(int recvlength, u8 *recvbuff,				      struct sk_buff *skb,				      struct usb_card_rec *cardp,				      wlan_private *priv){	u8 *cmdbuf;	if (recvlength > MRVDRV_SIZE_OF_CMD_BUFFER) {		lbs_deb_usbd(&cardp->udev->dev,			    "The receive buffer is too large\n");		kfree_skb(skb);		return;	}	if (!in_interrupt())		BUG();	spin_lock(&priv->adapter->driver_lock);	/* take care of cur_cmd = NULL case by reading the	 * data to clear the interrupt */	if (!priv->adapter->cur_cmd) {		cmdbuf = priv->upld_buf;		priv->adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;	} else		cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;	cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY;	priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);	memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN,	       priv->upld_len);	kfree_skb(skb);	libertas_interrupt(priv->dev);	spin_unlock(&priv->adapter->driver_lock);	lbs_deb_usbd(&cardp->udev->dev,		    "Wake up main thread to handle cmd response\n");	return;}/** *  @brief This function reads of the packet into the upload buff, *  wake up the main thread and initialise the Rx callack. * *  @param urb		pointer to struct urb *  @return 	   	N/A */static void if_usb_receive(struct urb *urb){	struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;	struct sk_buff *skb = rinfo->skb;	struct usb_card_rec *cardp = (struct usb_card_rec *) rinfo->cardp;	wlan_private * priv = cardp->priv;	int recvlength = urb->actual_length;	u8 *recvbuff = NULL;	u32 recvtype = 0;	lbs_deb_enter(LBS_DEB_USB);	if (recvlength) {		__le32 tmp;		if (urb->status) {			lbs_deb_usbd(&cardp->udev->dev,				    "URB status is failed\n");			kfree_skb(skb);			goto setup_for_next;		}		recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;		memcpy(&tmp, recvbuff, sizeof(u32));		recvtype = le32_to_cpu(tmp);		lbs_deb_usbd(&cardp->udev->dev,			    "Recv length = 0x%x, Recv type = 0x%X\n",			    recvlength, recvtype);	} else if (urb->status)		goto rx_exit;	switch (recvtype) {	case CMD_TYPE_DATA:		process_cmdtypedata(recvlength, skb, cardp, priv);		break;	case CMD_TYPE_REQUEST:		process_cmdrequest(recvlength, recvbuff, skb, cardp, priv);		break;	case CMD_TYPE_INDICATION:		/* Event cause handling */		spin_lock(&priv->adapter->driver_lock);		cardp->usb_event_cause = le32_to_cpu(*(__le32 *) (recvbuff + MESSAGE_HEADER_LEN));		lbs_deb_usbd(&cardp->udev->dev,"**EVENT** 0x%X\n",			    cardp->usb_event_cause);		if (cardp->usb_event_cause & 0xffff0000) {			libertas_send_tx_feedback(priv);			spin_unlock(&priv->adapter->driver_lock);			break;		}		cardp->usb_event_cause <<= 3;		cardp->usb_int_cause |= MRVDRV_CARDEVENT;		kfree_skb(skb);		libertas_interrupt(priv->dev);		spin_unlock(&priv->adapter->driver_lock);		goto rx_exit;	default:		lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",		             recvtype);		kfree_skb(skb);		break;	}setup_for_next:	if_usb_submit_rx_urb(cardp);rx_exit:	lbs_deb_leave(LBS_DEB_USB);}/** *  @brief This function downloads data to FW *  @param priv		pointer to wlan_private structure *  @param type		type of data *  @param buf		pointer to data buffer *  @param len		number of bytes *  @return 	   	0 or -1 */static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb){	struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;	lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type);	lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb);	if (type == MVMS_CMD) {		__le32 tmp = cpu_to_le32(CMD_TYPE_REQUEST);		priv->dnld_sent = DNLD_CMD_SENT;		memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,		       MESSAGE_HEADER_LEN);	} else {		__le32 tmp = cpu_to_le32(CMD_TYPE_DATA);		priv->dnld_sent = DNLD_DATA_SENT;		memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,		       MESSAGE_HEADER_LEN);	}	memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb);	return usb_tx_block(cardp, cardp->bulk_out_buffer,	                    nb + MESSAGE_HEADER_LEN);}/* called with adapter->driver_lock held */static int if_usb_get_int_status(wlan_private * priv, u8 * ireg){	struct usb_card_rec *cardp = priv->card;	*ireg = cardp->usb_int_cause;	cardp->usb_int_cause = 0;	lbs_deb_usbd(&cardp->udev->dev,"Int cause is 0x%X\n", *ireg);	return 0;}static int if_usb_read_event_cause(wlan_private * priv){	struct usb_card_rec *cardp = priv->card;	priv->adapter->eventcause = cardp->usb_event_cause;	/* Re-submit rx urb here to avoid event lost issue */	if_usb_submit_rx_urb(cardp);	return 0;}/** *  @brief This function issues Boot command to the Boot2 code *  @param ivalue   1:Boot from FW by USB-Download *                  2:Boot from FW in EEPROM *  @return 	   	0 */static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue){	struct bootcmdstr sbootcmd;	int i;	/* Prepare command */	sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);	sbootcmd.u8cmd_tag = ivalue;	for (i=0; i<11; i++)		sbootcmd.au8dumy[i]=0x00;	memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));	/* Issue command */	usb_tx_block(cardp, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));	return 0;}/** *  @brief This function checks the validity of Boot2/FW image. * *  @param data              pointer to image *         len               image length *  @return     0 or -1 */static int check_fwfile_format(u8 *data, u32 totlen){	u32 bincmd, exit;	u32 blksize, offset, len;	int ret;	ret = 1;	exit = len = 0;	do {		struct fwheader *fwh = (void *)data;		bincmd = le32_to_cpu(fwh->dnldcmd);		blksize = le32_to_cpu(fwh->datalength);		switch (bincmd) {		case FW_HAS_DATA_TO_RECV:			offset = sizeof(struct fwheader) + blksize;			data += offset;			len += offset;			if (len >= totlen)				exit = 1;			break;		case FW_HAS_LAST_BLOCK:			exit = 1;			ret = 0;			break;		default:			exit = 1;			break;		}	} while (!exit);	if (ret)		lbs_pr_err("firmware file format check FAIL\n");	else		lbs_deb_fw("firmware file format check PASS\n");	return ret;}static int if_usb_prog_firmware(struct usb_card_rec *cardp){	int i = 0;	static int reset_count = 10;	int ret = 0;	lbs_deb_enter(LBS_DEB_USB);	if ((ret = request_firmware(&cardp->fw, libertas_fw_name,				    &cardp->udev->dev)) < 0) {		lbs_pr_err("request_firmware() failed with %#x\n", ret);		lbs_pr_err("firmware %s not found\n", libertas_fw_name);		goto done;	}	if (check_fwfile_format(cardp->fw->data, cardp->fw->size))		goto release_fw;restart:	if (if_usb_submit_rx_urb_fwload(cardp) < 0) {		lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");		ret = -1;		goto release_fw;	}	cardp->bootcmdresp = 0;	do {		int j = 0;		i++;		/* Issue Boot command = 1, Boot from Download-FW */		if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB);		/* wait for command response */		do {			j++;			msleep_interruptible(100);		} while (cardp->bootcmdresp == 0 && j < 10);	} while (cardp->bootcmdresp == 0 && i < 5);	if (cardp->bootcmdresp == 0) {		if (--reset_count >= 0) {			if_usb_reset_device(cardp);			goto restart;		}		return -1;	}	i = 0;	cardp->totalbytes = 0;	cardp->fwlastblksent = 0;	cardp->CRC_OK = 1;	cardp->fwdnldover = 0;	cardp->fwseqnum = -1;	cardp->totalbytes = 0;	cardp->fwfinalblk = 0;	if_prog_firmware(cardp);	do {		lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n");		i++;		msleep_interruptible(100);		if (cardp->surprise_removed || i >= 20)			break;	} while (!cardp->fwdnldover);	if (!cardp->fwdnldover) {		lbs_pr_info("failed to load fw, resetting device!\n");		if (--reset_count >= 0) {			if_usb_reset_device(cardp);			goto restart;		}		lbs_pr_info("FW download failure, time = %d ms\n", i * 100);		ret = -1;		goto release_fw;	}release_fw:	release_firmware(cardp->fw);	cardp->fw = NULL;done:	lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);	return ret;}#ifdef CONFIG_PMstatic int if_usb_suspend(struct usb_interface *intf, pm_message_t message){	struct usb_card_rec *cardp = usb_get_intfdata(intf);	wlan_private *priv = cardp->priv;	lbs_deb_enter(LBS_DEB_USB);	if (priv->adapter->psstate != PS_STATE_FULL_POWER)		return -1;	if (priv->mesh_dev && !priv->mesh_autostart_enabled) {		/* Mesh autostart must be activated while sleeping		 * On resume it will go back to the current state		 */		struct cmd_ds_mesh_access mesh_access;		memset(&mesh_access, 0, sizeof(mesh_access));		mesh_access.data[0] = cpu_to_le32(1);		libertas_prepare_and_send_command(priv,				CMD_MESH_ACCESS,				CMD_ACT_MESH_SET_AUTOSTART_ENABLED,				CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);	}	netif_device_detach(cardp->eth_dev);	netif_device_detach(priv->mesh_dev);	/* Unlink tx & rx urb */	usb_kill_urb(cardp->tx_urb);	usb_kill_urb(cardp->rx_urb);	cardp->rx_urb_recall = 1;	lbs_deb_leave(LBS_DEB_USB);	return 0;}static int if_usb_resume(struct usb_interface *intf){	struct usb_card_rec *cardp = usb_get_intfdata(intf);	wlan_private *priv = cardp->priv;	lbs_deb_enter(LBS_DEB_USB);	cardp->rx_urb_recall = 0;	if_usb_submit_rx_urb(cardp->priv);	netif_device_attach(cardp->eth_dev);	netif_device_attach(priv->mesh_dev);	if (priv->mesh_dev && !priv->mesh_autostart_enabled) {		/* Mesh autostart was activated while sleeping		 * Disable it if appropriate		 */		struct cmd_ds_mesh_access mesh_access;		memset(&mesh_access, 0, sizeof(mesh_access));		mesh_access.data[0] = cpu_to_le32(0);		libertas_prepare_and_send_command(priv,				CMD_MESH_ACCESS,				CMD_ACT_MESH_SET_AUTOSTART_ENABLED,				CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);	}	lbs_deb_leave(LBS_DEB_USB);	return 0;}#else#define if_usb_suspend NULL#define if_usb_resume NULL#endifstatic struct usb_driver if_usb_driver = {	/* driver name */	.name = usbdriver_name,	/* probe function name */	.probe = if_usb_probe,	/* disconnect function  name */	.disconnect = if_usb_disconnect,	/* device signature table */	.id_table = if_usb_table,	.suspend = if_usb_suspend,	.resume = if_usb_resume,};static int if_usb_init_module(void){	int ret = 0;	lbs_deb_enter(LBS_DEB_MAIN);	if (libertas_fw_name == NULL) {		libertas_fw_name = default_fw_name;	}	ret = usb_register(&if_usb_driver);	lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);	return ret;}static void if_usb_exit_module(void){	struct usb_card_rec *cardp, *cardp_temp;	lbs_deb_enter(LBS_DEB_MAIN);	list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list) {		libertas_prepare_and_send_command(cardp->priv, CMD_802_11_RESET,		                                  CMD_ACT_HALT, 0, 0, NULL);	}	/* API unregisters the driver from USB subsystem */	usb_deregister(&if_usb_driver);	lbs_deb_leave(LBS_DEB_MAIN);}module_init(if_usb_init_module);module_exit(if_usb_exit_module);MODULE_DESCRIPTION("8388 USB WLAN Driver");MODULE_AUTHOR("Marvell International Ltd.");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -