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

📄 file_storage.c

📁 LINUX2.4.18内核下的usb GADGET驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
#endif			value = populate_config_buf(fsg->gadget->speed,					req->buf,					ctrl->wValue >> 8,					ctrl->wValue & 0xff);			if (value >= 0)				value = min(ctrl->wLength, (u16) value);			break;		case USB_DT_STRING:			VDBG(fsg, "get string descriptor\n");			/* wIndex == language code */			value = usb_gadget_get_string(&stringtab,					ctrl->wValue & 0xff, req->buf);			if (value >= 0)				value = min(ctrl->wLength, (u16) value);			break;		}		break;	/* One config, two speeds */	case USB_REQ_SET_CONFIGURATION:		if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |				USB_RECIP_DEVICE))			break;		VDBG(fsg, "set configuration\n");		if (ctrl->wValue == CONFIG_VALUE || ctrl->wValue == 0) {			fsg->new_config = ctrl->wValue;			/* Raise an exception to wipe out previous transaction			 * state (queued bufs, etc) and set the new config. */			raise_exception(fsg, FSG_STATE_CONFIG_CHANGE);			value = DELAYED_STATUS;		}		break;	case USB_REQ_GET_CONFIGURATION:		if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |				USB_RECIP_DEVICE))			break;		VDBG(fsg, "get configuration\n");		*(u8 *) req->buf = fsg->config;		value = min(ctrl->wLength, (u16) 1);		break;	case USB_REQ_SET_INTERFACE:		if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD |				USB_RECIP_INTERFACE))			break;		if (fsg->config && ctrl->wIndex == 0) {			/* Raise an exception to wipe out previous transaction			 * state (queued bufs, etc) and install the new			 * interface altsetting. */			raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE);			value = DELAYED_STATUS;		}		break;	case USB_REQ_GET_INTERFACE:		if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD |				USB_RECIP_INTERFACE))			break;		if (!fsg->config)			break;		if (ctrl->wIndex != 0) {			value = -EDOM;			break;		}		VDBG(fsg, "get interface\n");		*(u8 *) req->buf = 0;		value = min(ctrl->wLength, (u16) 1);		break;	default:		VDBG(fsg,			"unknown control req %02x.%02x v%04x i%04x l%u\n",			ctrl->bRequestType, ctrl->bRequest,			ctrl->wValue, ctrl->wIndex, ctrl->wLength);	}	return value;}static int fsg_setup(struct usb_gadget *gadget,		const struct usb_ctrlrequest *ctrl){	struct fsg_dev		*fsg = get_gadget_data(gadget);	int			rc;	++fsg->ep0_req_tag;		// Record arrival of a new request	fsg->ep0req->context = NULL;	fsg->ep0req->length = 0;	dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)		rc = class_setup_req(fsg, ctrl);	else		rc = standard_setup_req(fsg, ctrl);	/* Respond with data/status or defer until later? */	if (rc >= 0 && rc != DELAYED_STATUS) {		fsg->ep0req->length = rc;		fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?				"ep0-in" : "ep0-out");		rc = ep0_queue(fsg);	}	/* Device either stalls (rc < 0) or reports success */	return rc;}/*-------------------------------------------------------------------------*//* All the following routines run in process context *//* Use this for bulk or interrupt transfers, not ep0 */static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,		struct usb_request *req, volatile int *pbusy,		volatile enum fsg_buffer_state *state){	int	rc;	if (ep == fsg->bulk_in)		dump_msg(fsg, "bulk-in", req->buf, req->length);	else if (ep == fsg->intr_in)		dump_msg(fsg, "intr-in", req->buf, req->length);	*pbusy = 1;	*state = BUF_STATE_BUSY;	rc = usb_ep_queue(ep, req, GFP_KERNEL);	if (rc != 0) {		*pbusy = 0;		*state = BUF_STATE_EMPTY;		/* We can't do much more than wait for a reset */		/* Note: currently the net2280 driver fails zero-length		 * submissions if DMA is enabled. */		if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP &&						req->length == 0))			WARN(fsg, "error in submission: %s --> %d\n",					ep->name, rc);	}}static int sleep_thread(struct fsg_dev *fsg){	int	rc;	/* Wait until a signal arrives or we are woken up */	rc = wait_event_interruptible(fsg->thread_wqh,			fsg->thread_wakeup_needed);	fsg->thread_wakeup_needed = 0;	return (rc ? -EINTR : 0);}/*-------------------------------------------------------------------------*/static int do_read(struct fsg_dev *fsg){	struct lun		*curlun = fsg->curlun;	u32			lba;	struct fsg_buffhd	*bh;	int			rc;	u32			amount_left;	loff_t			file_offset, file_offset_tmp;	unsigned int		amount;	unsigned int		partial_page;	ssize_t			nread;	/* Get the starting Logical Block Address and check that it's	 * not too big */	if (fsg->cmnd[0] == SC_READ_6)		lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]);	else {		lba = get_be32(&fsg->cmnd[2]);		/* We allow DPO (Disable Page Out = don't save data in the		 * cache) and FUA (Force Unit Access = don't read from the		 * cache), but we don't implement them. */		if ((fsg->cmnd[1] & ~0x18) != 0) {			curlun->sense_data = SS_INVALID_FIELD_IN_CDB;			return -EINVAL;		}	}	if (lba >= curlun->num_sectors) {		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;		return -EINVAL;	}	file_offset = ((loff_t) lba) << 9;	/* Carry out the file reads */	amount_left = fsg->data_size_from_cmnd;	if (unlikely(amount_left == 0))		return -EIO;		// No default reply	for (;;) {		/* Figure out how much we need to read:		 * Try to read the remaining amount.		 * But don't read more than the buffer size.		 * And don't try to read past the end of the file.		 * Finally, if we're not at a page boundary, don't read past		 *	the next page.		 * If this means reading 0 then we were asked to read past		 *	the end of file. */		amount = min((unsigned int) amount_left, mod_data.buflen);		amount = min((loff_t) amount,				curlun->file_length - file_offset);		partial_page = file_offset & (PAGE_CACHE_SIZE - 1);		if (partial_page > 0)			amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -					partial_page);		/* Wait for the next buffer to become available */		bh = fsg->next_buffhd_to_fill;		while (bh->state != BUF_STATE_EMPTY) {			if ((rc = sleep_thread(fsg)) != 0)				return rc;		}		/* If we were asked to read past the end of file,		 * end with an empty buffer. */		if (amount == 0) {			curlun->sense_data =					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;			curlun->sense_data_info = file_offset >> 9;			bh->inreq->length = 0;			bh->state = BUF_STATE_FULL;			break;		}		/* Perform the read */		file_offset_tmp = file_offset;		nread = curlun->filp->f_op->read(curlun->filp,				(char *) bh->buf,				amount, &file_offset_tmp);		VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,				(unsigned long long) file_offset,				(int) nread);		if (signal_pending(current))			return -EINTR;		if (nread < 0) {			LDBG(curlun, "error in file read: %d\n",					(int) nread);			nread = 0;		} else if (nread < amount) {			LDBG(curlun, "partial file read: %d/%u\n",					(int) nread, amount);			nread -= (nread & 511);	// Round down to a block		}		file_offset  += nread;		amount_left  -= nread;		fsg->residue -= nread;		bh->inreq->length = nread;		bh->state = BUF_STATE_FULL;		/* If an error occurred, report it and its position */		if (nread < amount) {			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;			curlun->sense_data_info = file_offset >> 9;			break;		}		if (amount_left == 0)			break;		// No more left to read		/* Send this buffer and go read some more */		bh->inreq->zero = 0;		start_transfer(fsg, fsg->bulk_in, bh->inreq,				&bh->inreq_busy, &bh->state);		fsg->next_buffhd_to_fill = bh->next;	}	return -EIO;		// No default reply}/*-------------------------------------------------------------------------*/static int do_write(struct fsg_dev *fsg){	struct lun		*curlun = fsg->curlun;	u32			lba;	struct fsg_buffhd	*bh;	int			get_some_more;	u32			amount_left_to_req, amount_left_to_write;	loff_t			usb_offset, file_offset, file_offset_tmp;	unsigned int		amount;	unsigned int		partial_page;	ssize_t			nwritten;	int			rc;	if (curlun->ro) {		curlun->sense_data = SS_WRITE_PROTECTED;		return -EINVAL;	}	curlun->filp->f_flags &= ~O_SYNC;	// Default is not to wait	/* Get the starting Logical Block Address and check that it's	 * not too big */	if (fsg->cmnd[0] == SC_WRITE_6)		lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]);	else {		lba = get_be32(&fsg->cmnd[2]);		/* We allow DPO (Disable Page Out = don't save data in the		 * cache) and FUA (Force Unit Access = write directly to the		 * medium).  We don't implement DPO; we implement FUA by		 * performing synchronous output. */		if ((fsg->cmnd[1] & ~0x18) != 0) {			curlun->sense_data = SS_INVALID_FIELD_IN_CDB;			return -EINVAL;		}		if (fsg->cmnd[1] & 0x08)	// FUA			curlun->filp->f_flags |= O_SYNC;	}	if (lba >= curlun->num_sectors) {		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;		return -EINVAL;	}	/* Carry out the file writes */	get_some_more = 1;	file_offset = usb_offset = ((loff_t) lba) << 9;	amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;	while (amount_left_to_write > 0) {		/* Queue a request for more data from the host */		bh = fsg->next_buffhd_to_fill;		if (bh->state == BUF_STATE_EMPTY && get_some_more) {			/* Figure out how much we want to get:			 * Try to get the remaining amount.			 * But don't get more than the buffer size.			 * And don't try to go past the end of the file.			 * If we're not at a page boundary,			 *	don't go past the next page.			 * If this means getting 0, then we were asked			 *	to write past the end of file.			 * Finally, round down to a block boundary. */			amount = min(amount_left_to_req, mod_data.buflen);			amount = min((loff_t) amount, curlun->file_length -					usb_offset);			partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);			if (partial_page > 0)				amount = min(amount,	(unsigned int) PAGE_CACHE_SIZE - partial_page);			if (amount == 0) {				get_some_more = 0;				curlun->sense_data =					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;				curlun->sense_data_info = usb_offset >> 9;				continue;			}			amount -= (amount & 511);			if (amount == 0) {				/* Why were we were asked to transfer a				 * partial block? */				get_some_more = 0;				continue;			}			/* Get the next buffer */			usb_offset += amount;			fsg->usb_amount_left -= amount;			amount_left_to_req -= amount;			if (amount_left_to_req == 0)				get_some_more = 0;			/* amount is always divisible by 512, hence by			 * the bulk-out maxpacket size */			bh->outreq->length = bh->bulk_out_intended_length =					amount;			start_transfer(fsg, fsg->bulk_out, bh->outreq,					&bh->outreq_busy, &bh->state);			fsg->next_buffhd_to_fill = bh->next;			continue;		}		/* Write the received data to the backing file */		bh = fsg->next_buffhd_to_drain;		if (bh->state == BUF_STATE_EMPTY && !get_some_more)			break;			// We stopped early		if (bh->state == BUF_STATE_FULL) {			fsg->next_buffhd_to_drain = bh->next;			bh->state = BUF_STATE_EMPTY;			/* Did something go wrong with the transfer? */			if (bh->outreq->status != 0) {				curlun->sense_data = SS_COMMUNICATION_FAILURE;				curlun->sense_data_info = file_offset >> 9;				break;			}			amount = bh->outreq->actual;			if (curlun->file_length - file_offset < amount) {				LERROR(curlun,	"write %u @ %llu beyond end %llu\n",	amount, (unsigned long long) file_offset,	(unsigned long long) curlun->file_length);				amount = curlun->file_length - file_offset;			}			/* Perform the write */			file_offset_tmp = file_offset;			nwritten = curlun->filp->f_op->write(curlun->filp,					(char *) bh->buf,					amount, &file_offset_tmp);			VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,					(unsigned long long) file_offset,					(int) nwritten);			if (signal_pending(current))				return -EINTR;		// Interrupted!			if (nwritten < 0) {				LDBG(curlun, "error in file write: %d\n",						(int) nwritten);				nwritten = 0;			} else if (nwritten < amount) {				LDBG(curlun, "partial file write: %d/%u\n",						(int) nwritten, amount);				nwritten -= (nwritten & 511);						// Round down to a block			}			file_offset += nwritten;			amount_left_to_write -= nwritten;			fsg->residue -= nwritten;			/* If an error occurred, report it and its position */			if (nwritten < amount) {				curlun->sense_data = SS_WRITE_ERROR;				curlun->sense_data_info = file_offset >> 9;				break;			}			/* Did the host decide to stop early? */			if (bh->outreq->actual != bh->outreq->length) {				fsg->short_packet_received = 1;				break;			}			continue;		}

⌨️ 快捷键说明

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