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

📄 file_storage.c

📁 LINUX2.4.18内核下的usb GADGET驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
		/* Wait for something to happen */		if ((rc = sleep_thread(fsg)) != 0)			return rc;	}	return -EIO;		// No default reply}/*-------------------------------------------------------------------------*//* Sync the file data, don't bother with the metadata. * This code was copied from fs/buffer.c:sys_fdatasync(). */static int fsync_sub(struct lun *curlun){	struct file	*filp = curlun->filp;	struct inode	*inode;	int		rc, err;	if (curlun->ro || !filp)		return 0;	if (!filp->f_op->fsync)		return -EINVAL;	inode = filp->f_dentry->d_inode;	down(&inode->i_sem);	rc = filemap_fdatasync(inode->i_mapping);	err = filp->f_op->fsync(filp, filp->f_dentry, 1);	if (!rc)		rc = err;	err = filemap_fdatawait(inode->i_mapping);	if (!rc)		rc = err;	up(&inode->i_sem);	VLDBG(curlun, "fdatasync -> %d\n", rc);	return rc;}static void fsync_all(struct fsg_dev *fsg){	int	i;	for (i = 0; i < fsg->nluns; ++i)		fsync_sub(&fsg->luns[i]);}static int do_synchronize_cache(struct fsg_dev *fsg){	struct lun	*curlun = fsg->curlun;	int		rc;	/* We ignore the requested LBA and write out all file's	 * dirty data buffers. */	rc = fsync_sub(curlun);	if (rc)		curlun->sense_data = SS_WRITE_ERROR;	return 0;}/*-------------------------------------------------------------------------*/static void invalidate_sub(struct lun *curlun){	struct file	*filp = curlun->filp;	struct inode	*inode = filp->f_dentry->d_inode;	invalidate_inode_pages(inode);}static int do_verify(struct fsg_dev *fsg){	struct lun		*curlun = fsg->curlun;	u32			lba;	u32			verification_length;	struct fsg_buffhd	*bh = fsg->next_buffhd_to_fill;	loff_t			file_offset, file_offset_tmp;	u32			amount_left;	unsigned int		amount;	ssize_t			nread;	/* Get the starting Logical Block Address and check that it's	 * not too big */	lba = get_be32(&fsg->cmnd[2]);	if (lba >= curlun->num_sectors) {		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;		return -EINVAL;	}	/* We allow DPO (Disable Page Out = don't save data in the	 * cache) but we don't implement it. */	if ((fsg->cmnd[1] & ~0x10) != 0) {		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;		return -EINVAL;	}	verification_length = get_be16(&fsg->cmnd[7]);	if (unlikely(verification_length == 0))		return -EIO;		// No default reply	/* Prepare to carry out the file verify */	amount_left = verification_length << 9;	file_offset = ((loff_t) lba) << 9;	/* Write out all the dirty buffers before invalidating them */	fsync_sub(curlun);	if (signal_pending(current))		return -EINTR;	invalidate_sub(curlun);	if (signal_pending(current))		return -EINTR;	/* Just try to read the requested blocks */	while (amount_left > 0) {		/* Figure out how much we need to read:		 * Try to read the remaining amount, but not more than		 * the buffer size.		 * And don't try to read past the end of the file.		 * 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);		if (amount == 0) {			curlun->sense_data =					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;			curlun->sense_data_info = file_offset >> 9;			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 verify: %d\n",					(int) nread);			nread = 0;		} else if (nread < amount) {			LDBG(curlun, "partial file verify: %d/%u\n",					(int) nread, amount);			nread -= (nread & 511);	// Round down to a sector		}		if (nread == 0) {			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;			curlun->sense_data_info = file_offset >> 9;			break;		}		file_offset += nread;		amount_left -= nread;	}	return 0;}/*-------------------------------------------------------------------------*/static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh){	u8	*buf = (u8 *) bh->buf;	static char vendor_id[] = "Linux   ";	static char product_id[] = "File-Stor Gadget";	if (!fsg->curlun) {		// Unsupported LUNs are okay		fsg->bad_lun_okay = 1;		memset(buf, 0, 36);		buf[0] = 0x7f;		// Unsupported, no device-type		return 36;	}	memset(buf, 0, 8);	// Non-removable, direct-access device	if (mod_data.removable)		buf[1] = 0x80;	buf[2] = 2;		// ANSI SCSI level 2	buf[3] = 2;		// SCSI-2 INQUIRY data format	buf[4] = 31;		// Additional length				// No special options	sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, product_id,			mod_data.release);	return 36;}static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh){	struct lun	*curlun = fsg->curlun;	u8		*buf = (u8 *) bh->buf;	u32		sd, sdinfo;	/*	 * From the SCSI-2 spec., section 7.9 (Unit attention condition):	 *	 * If a REQUEST SENSE command is received from an initiator	 * with a pending unit attention condition (before the target	 * generates the contingent allegiance condition), then the	 * target shall either:	 *   a) report any pending sense data and preserve the unit	 *	attention condition on the logical unit, or,	 *   b) report the unit attention condition, may discard any	 *	pending sense data, and clear the unit attention	 *	condition on the logical unit for that initiator.	 *	 * FSG normally uses option a); enable this code to use option b).	 */#if 0	if (curlun && curlun->unit_attention_data != SS_NO_SENSE) {		curlun->sense_data = curlun->unit_attention_data;		curlun->unit_attention_data = SS_NO_SENSE;	}#endif	if (!curlun) {		// Unsupported LUNs are okay		fsg->bad_lun_okay = 1;		sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;		sdinfo = 0;	} else {		sd = curlun->sense_data;		sdinfo = curlun->sense_data_info;		curlun->sense_data = SS_NO_SENSE;		curlun->sense_data_info = 0;	}	memset(buf, 0, 18);	buf[0] = 0x80 | 0x70;			// Valid, current error	buf[2] = SK(sd);	put_be32(&buf[3], sdinfo);		// Sense information	buf[7] = 18 - 8;			// Additional sense length	buf[12] = ASC(sd);	buf[13] = ASCQ(sd);	return 18;}static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh){	struct lun	*curlun = fsg->curlun;	u32		lba = get_be32(&fsg->cmnd[2]);	int		pmi = fsg->cmnd[8];	u8		*buf = (u8 *) bh->buf;	/* Check the PMI and LBA fields */	if (pmi > 1 || (pmi == 0 && lba != 0)) {		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;		return -EINVAL;	}	put_be32(&buf[0], curlun->num_sectors - 1);	// Max logical block	put_be32(&buf[4], 512);				// Block length	return 8;}static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh){	struct lun	*curlun = fsg->curlun;	int		mscmnd = fsg->cmnd[0];	u8		*buf = (u8 *) bh->buf;	u8		*buf0 = buf;	int		pc, page_code;	int		changeable_values, all_pages;	int		valid_page = 0;	int		len, limit;	if ((fsg->cmnd[1] & ~0x08) != 0) {		// Mask away DBD		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;		return -EINVAL;	}	pc = fsg->cmnd[2] >> 6;	page_code = fsg->cmnd[2] & 0x3f;	if (pc == 3) {		curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;		return -EINVAL;	}	changeable_values = (pc == 1);	all_pages = (page_code == 0x3f);	/* Write the mode parameter header.  Fixed values are: default	 * medium type, no cache control (DPOFUA), and no block descriptors.	 * The only variable value is the WriteProtect bit.  We will fill in	 * the mode data length later. */	memset(buf, 0, 8);	if (mscmnd == SC_MODE_SENSE_6) {		buf[2] = (curlun->ro ? 0x80 : 0x00);		// WP, DPOFUA		buf += 4;		limit = 255;	} else {			// SC_MODE_SENSE_10		buf[3] = (curlun->ro ? 0x80 : 0x00);		// WP, DPOFUA		buf += 8;		limit = 65535;		// Should really be mod_data.buflen	}	/* No block descriptors */	/* The mode pages, in numerical order.  The only page we support	 * is the Caching page. */	if (page_code == 0x08 || all_pages) {		valid_page = 1;		buf[0] = 0x08;		// Page code		buf[1] = 10;		// Page length		memset(buf+2, 0, 10);	// None of the fields are changeable		if (!changeable_values) {			buf[2] = 0x04;	// Write cache enable,					// Read cache not disabled					// No cache retention priorities			put_be16(&buf[4], 0xffff);  // Don't disable prefetch					// Minimum prefetch = 0			put_be16(&buf[8], 0xffff);  // Maximum prefetch			put_be16(&buf[10], 0xffff); // Maximum prefetch ceiling		}		buf += 12;	}	/* Check that a valid page was requested and the mode data length	 * isn't too long. */	len = buf - buf0;	if (!valid_page || len > limit) {		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;		return -EINVAL;	}	/*  Store the mode data length */	if (mscmnd == SC_MODE_SENSE_6)		buf0[0] = len - 1;	else		put_be16(buf0, len - 2);	return len;}static int do_start_stop(struct fsg_dev *fsg){	struct lun	*curlun = fsg->curlun;	int		loej, start;	if (!mod_data.removable) {		curlun->sense_data = SS_INVALID_COMMAND;		return -EINVAL;	}	// int immed = fsg->cmnd[1] & 0x01;	loej = fsg->cmnd[4] & 0x02;	start = fsg->cmnd[4] & 0x01;#ifdef CONFIG_USB_FILE_STORAGE_TEST	if ((fsg->cmnd[1] & ~0x01) != 0 ||		// Mask away Immed			(fsg->cmnd[4] & ~0x03) != 0) {	// Mask LoEj, Start		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;		return -EINVAL;	}	if (!start) {		/* Are we allowed to unload the media? */		if (curlun->prevent_medium_removal) {			LDBG(curlun, "unload attempt prevented\n");			curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;			return -EINVAL;		}		if (loej) {		// Simulate an unload/eject			up_read(&fsg->filesem);			down_write(&fsg->filesem);			close_backing_file(curlun);			up_write(&fsg->filesem);			down_read(&fsg->filesem);		}	} else {		/* Our emulation doesn't support mounting; the medium is		 * available for use as soon as it is loaded. */		if (!backing_file_is_open(curlun)) {			curlun->sense_data = SS_MEDIUM_NOT_PRESENT;			return -EINVAL;		}	}#endif	return 0;}static int do_prevent_allow(struct fsg_dev *fsg){	struct lun	*curlun = fsg->curlun;	int		prevent;	if (!mod_data.removable) {		curlun->sense_data = SS_INVALID_COMMAND;		return -EINVAL;	}	prevent = fsg->cmnd[4] & 0x01;	if ((fsg->cmnd[4] & ~0x01) != 0) {		// Mask away Prevent		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;		return -EINVAL;	}	if (curlun->prevent_medium_removal && !prevent)		fsync_sub(curlun);	curlun->prevent_medium_removal = prevent;	return 0;}static int do_read_format_capacities(struct fsg_dev *fsg,			struct fsg_buffhd *bh){	struct lun	*curlun = fsg->curlun;	u8		*buf = (u8 *) bh->buf;	buf[0] = buf[1] = buf[2] = 0;	buf[3] = 8;		// Only the Current/Maximum Capacity Descriptor	buf += 4;	put_be32(&buf[0], curlun->num_sectors);		// Number of blocks	put_be32(&buf[4], 512);				// Block length	buf[4] = 0x02;					// Current capacity	return 12;}static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh){	struct lun	*curlun = fsg->curlun;	/* We don't support MODE SELECT */	curlun->sense_data = SS_INVALID_COMMAND;	return -EINVAL;}/*-------------------------------------------------------------------------*/static int halt_bulk_in_endpoint(struct fsg_dev *fsg){	int	rc;	rc = fsg_set_halt(fsg, fsg->bulk_in);	if (rc == -EAGAIN)		VD

⌨️ 快捷键说明

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