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

📄 ub.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
				break;			cmd->error = rc;			cmd->state = UB_CMDST_DONE;		} else {			if (!ub_is_completed(&sc->work_done))				break;			del_timer(&sc->work_timer);			ub_scsi_urb_compl(sc, cmd);		}	}}static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	struct urb *urb = &sc->work_urb;	struct bulk_cs_wrap *bcs;	int len;	int rc;	if (atomic_read(&sc->poison)) {		ub_state_done(sc, cmd, -ENODEV);		return;	}	if (cmd->state == UB_CMDST_CLEAR) {		if (urb->status == -EPIPE) {			/*			 * STALL while clearning STALL.			 * The control pipe clears itself - nothing to do.			 */			printk(KERN_NOTICE "%s: stall on control pipe\n",			    sc->name);			goto Bad_End;		}		/*		 * We ignore the result for the halt clear.		 */		/* reset the endpoint toggle */		usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe),			usb_pipeout(sc->last_pipe), 0);		ub_state_sense(sc, cmd);	} else if (cmd->state == UB_CMDST_CLR2STS) {		if (urb->status == -EPIPE) {			printk(KERN_NOTICE "%s: stall on control pipe\n",			    sc->name);			goto Bad_End;		}		/*		 * We ignore the result for the halt clear.		 */		/* reset the endpoint toggle */		usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe),			usb_pipeout(sc->last_pipe), 0);		ub_state_stat(sc, cmd);	} else if (cmd->state == UB_CMDST_CLRRS) {		if (urb->status == -EPIPE) {			printk(KERN_NOTICE "%s: stall on control pipe\n",			    sc->name);			goto Bad_End;		}		/*		 * We ignore the result for the halt clear.		 */		/* reset the endpoint toggle */		usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe),			usb_pipeout(sc->last_pipe), 0);		ub_state_stat_counted(sc, cmd);	} else if (cmd->state == UB_CMDST_CMD) {		switch (urb->status) {		case 0:			break;		case -EOVERFLOW:			goto Bad_End;		case -EPIPE:			rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);			if (rc != 0) {				printk(KERN_NOTICE "%s: "				    "unable to submit clear (%d)\n",				    sc->name, rc);				/*				 * This is typically ENOMEM or some other such shit.				 * Retrying is pointless. Just do Bad End on it...				 */				ub_state_done(sc, cmd, rc);				return;			}			cmd->state = UB_CMDST_CLEAR;			return;		case -ESHUTDOWN:	/* unplug */		case -EILSEQ:		/* unplug timeout on uhci */			ub_state_done(sc, cmd, -ENODEV);			return;		default:			goto Bad_End;		}		if (urb->actual_length != US_BULK_CB_WRAP_LEN) {			goto Bad_End;		}		if (cmd->dir == UB_DIR_NONE || cmd->nsg < 1) {			ub_state_stat(sc, cmd);			return;		}		// udelay(125);		// usb-storage has this		ub_data_start(sc, cmd);	} else if (cmd->state == UB_CMDST_DATA) {		if (urb->status == -EPIPE) {			rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);			if (rc != 0) {				printk(KERN_NOTICE "%s: "				    "unable to submit clear (%d)\n",				    sc->name, rc);				ub_state_done(sc, cmd, rc);				return;			}			cmd->state = UB_CMDST_CLR2STS;			return;		}		if (urb->status == -EOVERFLOW) {			/*			 * A babble? Failure, but we must transfer CSW now.			 */			cmd->error = -EOVERFLOW;	/* A cheap trick... */			ub_state_stat(sc, cmd);			return;		}		if (cmd->dir == UB_DIR_WRITE) {			/*			 * Do not continue writes in case of a failure.			 * Doing so would cause sectors to be mixed up,			 * which is worse than sectors lost.			 *			 * We must try to read the CSW, or many devices			 * get confused.			 */			len = urb->actual_length;			if (urb->status != 0 ||			    len != cmd->sgv[cmd->current_sg].length) {				cmd->act_len += len;				cmd->error = -EIO;				ub_state_stat(sc, cmd);				return;			}		} else {			/*			 * If an error occurs on read, we record it, and			 * continue to fetch data in order to avoid bubble.			 *			 * As a small shortcut, we stop if we detect that			 * a CSW mixed into data.			 */			if (urb->status != 0)				cmd->error = -EIO;			len = urb->actual_length;			if (urb->status != 0 ||			    len != cmd->sgv[cmd->current_sg].length) {				if ((len & 0x1FF) == US_BULK_CS_WRAP_LEN)					goto Bad_End;			}		}		cmd->act_len += urb->actual_length;		if (++cmd->current_sg < cmd->nsg) {			ub_data_start(sc, cmd);			return;		}		ub_state_stat(sc, cmd);	} else if (cmd->state == UB_CMDST_STAT) {		if (urb->status == -EPIPE) {			rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);			if (rc != 0) {				printk(KERN_NOTICE "%s: "				    "unable to submit clear (%d)\n",				    sc->name, rc);				ub_state_done(sc, cmd, rc);				return;			}			/*			 * Having a stall when getting CSW is an error, so			 * make sure uppper levels are not oblivious to it.			 */			cmd->error = -EIO;		/* A cheap trick... */			cmd->state = UB_CMDST_CLRRS;			return;		}		/* Catch everything, including -EOVERFLOW and other nasties. */		if (urb->status != 0)			goto Bad_End;		if (urb->actual_length == 0) {			ub_state_stat_counted(sc, cmd);			return;		}		/*		 * Check the returned Bulk protocol status.		 * The status block has to be validated first.		 */		bcs = &sc->work_bcs;		if (sc->signature == cpu_to_le32(0)) {			/*			 * This is the first reply, so do not perform the check.			 * Instead, remember the signature the device uses			 * for future checks. But do not allow a nul.			 */			sc->signature = bcs->Signature;			if (sc->signature == cpu_to_le32(0)) {				ub_state_stat_counted(sc, cmd);				return;			}		} else {			if (bcs->Signature != sc->signature) {				ub_state_stat_counted(sc, cmd);				return;			}		}		if (bcs->Tag != cmd->tag) {			/*			 * This usually happens when we disagree with the			 * device's microcode about something. For instance,			 * a few of them throw this after timeouts. They buffer			 * commands and reply at commands we timed out before.			 * Without flushing these replies we loop forever.			 */			ub_state_stat_counted(sc, cmd);			return;		}		len = le32_to_cpu(bcs->Residue);		if (len != cmd->len - cmd->act_len) {			/*			 * It is all right to transfer less, the caller has			 * to check. But it's not all right if the device			 * counts disagree with our counts.			 */			goto Bad_End;		}		switch (bcs->Status) {		case US_BULK_STAT_OK:			break;		case US_BULK_STAT_FAIL:			ub_state_sense(sc, cmd);			return;		case US_BULK_STAT_PHASE:			goto Bad_End;		default:			printk(KERN_INFO "%s: unknown CSW status 0x%x\n",			    sc->name, bcs->Status);			ub_state_done(sc, cmd, -EINVAL);			return;		}		/* Not zeroing error to preserve a babble indicator */		if (cmd->error != 0) {			ub_state_sense(sc, cmd);			return;		}		cmd->state = UB_CMDST_DONE;		ub_cmdq_pop(sc);		(*cmd->done)(sc, cmd);	} else if (cmd->state == UB_CMDST_SENSE) {		ub_state_done(sc, cmd, -EIO);	} else {		printk(KERN_WARNING "%s: "		    "wrong command state %d\n",		    sc->name, cmd->state);		ub_state_done(sc, cmd, -EINVAL);		return;	}	return;Bad_End: /* Little Excel is dead */	ub_state_done(sc, cmd, -EIO);}/* * Factorization helper for the command state machine: * Initiate a data segment transfer. */static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	struct scatterlist *sg = &cmd->sgv[cmd->current_sg];	int pipe;	int rc;	UB_INIT_COMPLETION(sc->work_done);	if (cmd->dir == UB_DIR_READ)		pipe = sc->recv_bulk_pipe;	else		pipe = sc->send_bulk_pipe;	sc->last_pipe = pipe;	usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, sg_virt(sg),	    sg->length, ub_urb_complete, sc);	sc->work_urb.actual_length = 0;	sc->work_urb.error_count = 0;	sc->work_urb.status = 0;	if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {		/* XXX Clear stalls */		ub_complete(&sc->work_done);		ub_state_done(sc, cmd, rc);		return;	}	sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;	add_timer(&sc->work_timer);	cmd->state = UB_CMDST_DATA;}/* * Factorization helper for the command state machine: * Finish the command. */static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc){	cmd->error = rc;	cmd->state = UB_CMDST_DONE;	ub_cmdq_pop(sc);	(*cmd->done)(sc, cmd);}/* * Factorization helper for the command state machine: * Submit a CSW read. */static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	int rc;	UB_INIT_COMPLETION(sc->work_done);	sc->last_pipe = sc->recv_bulk_pipe;	usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe,	    &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc);	sc->work_urb.actual_length = 0;	sc->work_urb.error_count = 0;	sc->work_urb.status = 0;	if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {		/* XXX Clear stalls */		ub_complete(&sc->work_done);		ub_state_done(sc, cmd, rc);		return -1;	}	sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;	add_timer(&sc->work_timer);	return 0;}/* * Factorization helper for the command state machine: * Submit a CSW read and go to STAT state. */static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	if (__ub_state_stat(sc, cmd) != 0)		return;	cmd->stat_count = 0;	cmd->state = UB_CMDST_STAT;}/* * Factorization helper for the command state machine: * Submit a CSW read and go to STAT state with counter (along [C] path). */static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	if (++cmd->stat_count >= 4) {		ub_state_sense(sc, cmd);		return;	}	if (__ub_state_stat(sc, cmd) != 0)		return;	cmd->state = UB_CMDST_STAT;}/* * Factorization helper for the command state machine: * Submit a REQUEST SENSE and go to SENSE state. */static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	struct ub_scsi_cmd *scmd;	struct scatterlist *sg;	int rc;	if (cmd->cdb[0] == REQUEST_SENSE) {		rc = -EPIPE;		goto error;	}	scmd = &sc->top_rqs_cmd;	memset(scmd, 0, sizeof(struct ub_scsi_cmd));	scmd->cdb[0] = REQUEST_SENSE;	scmd->cdb[4] = UB_SENSE_SIZE;	scmd->cdb_len = 6;	scmd->dir = UB_DIR_READ;	scmd->state = UB_CMDST_INIT;	scmd->nsg = 1;	sg = &scmd->sgv[0];	sg_init_table(sg, UB_MAX_REQ_SG);	sg_set_page(sg, virt_to_page(sc->top_sense), UB_SENSE_SIZE,			(unsigned long)sc->top_sense & (PAGE_SIZE-1));	scmd->len = UB_SENSE_SIZE;	scmd->lun = cmd->lun;	scmd->done = ub_top_sense_done;	scmd->back = cmd;	scmd->tag = sc->tagcnt++;	cmd->state = UB_CMDST_SENSE;	ub_cmdq_insert(sc, scmd);	return;error:	ub_state_done(sc, cmd, rc);}/* * A helper for the command's state machine: * Submit a stall clear. */static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,    int stalled_pipe){	int endp;	struct usb_ctrlrequest *cr;	int rc;	endp = usb_pipeendpoint(stalled_pipe);	if (usb_pipein (stalled_pipe))		endp |= USB_DIR_IN;	cr = &sc->work_cr;	cr->bRequestType = USB_RECIP_ENDPOINT;	cr->bRequest = USB_REQ_CLEAR_FEATURE;	cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT);	cr->wIndex = cpu_to_le16(endp);	cr->wLength = cpu_to_le16(0);	UB_INIT_COMPLETION(sc->work_done);	usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,	    (unsigned char*) cr, NULL, 0, ub_urb_complete, sc);	sc->work_urb.actual_length = 0;	sc->work_urb.error_count = 0;	sc->work_urb.status = 0;	if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {		ub_complete(&sc->work_done);		return rc;	}	sc->work_timer.expires = jiffies + UB_CTRL_TIMEOUT;	add_timer(&sc->work_timer);	return 0;}

⌨️ 快捷键说明

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