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

📄 scsiglue.c

📁 LINUX下USB驱动程序的开发
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Driver for USB Mass Storage compliant devices * SCSI layer glue code * * $Id: scsiglue.c,v 1.24 2001/11/11 03:33:58 mdharm Exp $ * * Current development and maintenance by: *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) *   (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov) * * Initial work by: *   (c) 1999 Michael Gee (michael@linuxspecific.com) * * This driver is based on the 'USB Mass Storage Class' document. This * describes in detail the protocol used to communicate with such * devices.  Clearly, the designers had SCSI and ATAPI commands in * mind when they created this document.  The commands are all very * similar to commands in the SCSI-II and ATAPI specifications. * * It is important to note that in a number of cases this class * exhibits class-specific exemptions from the USB specification. * Notably the usage of NAK, STALL and ACK differs from the norm, in * that they are used to communicate wait, failed and OK on commands. * * Also, for certain devices, the interrupt endpoint is used to convey * status of a command. * * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more * information about this driver. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */#include "scsiglue.h"#include "usb.h"#include "debug.h"#include "transport.h"#include <linux/slab.h>/* * kernel thread actions */#define US_ACT_COMMAND		1#define US_ACT_DEVICE_RESET	2#define US_ACT_BUS_RESET	3#define US_ACT_HOST_RESET	4#define US_ACT_EXIT		5/*********************************************************************** * Host functions  ***********************************************************************/static const char* host_info(struct Scsi_Host *host){	return "SCSI emulation for USB Mass Storage devices";}/* detect a virtual adapter (always works) */static int detect(struct SHT *sht){	struct us_data *us;	char local_name[32];	/* Note: this function gets called with io_request_lock spinlock helt! */	/* This is not nice at all, but how else are we to get the	 * data here? */	us = (struct us_data *)sht->proc_dir;	/* set up the name of our subdirectory under /proc/scsi/ */	sprintf(local_name, "usb-storage-%d", us->host_number);	sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_ATOMIC);	if (!sht->proc_name) 		return 0;	strcpy(sht->proc_name, local_name);	/* we start with no /proc directory entry */	sht->proc_dir = NULL;	/* register the host */	us->host = scsi_register(sht, sizeof(us));	if (us->host) {		us->host->hostdata[0] = (unsigned long)us;		us->host_no = us->host->host_no;		return 1;	}	/* odd... didn't register properly.  Abort and free pointers */	kfree(sht->proc_name);	sht->proc_name = NULL;	return 0;}/* Release all resources used by the virtual host * * NOTE: There is no contention here, because we're already deregistered * the driver and we're doing each virtual host in turn, not in parallel */static int release(struct Scsi_Host *psh){	struct us_data *us = (struct us_data *)psh->hostdata[0];	US_DEBUGP("release() called for host %s\n", us->htmplt.name);	/* Kill the control threads	 *	 * Enqueue the command, wake up the thread, and wait for 	 * notification that it's exited.	 */	US_DEBUGP("-- sending US_ACT_EXIT command to thread\n");	us->action = US_ACT_EXIT;		up(&(us->sema));	wait_for_completion(&(us->notify));	/* remove the pointer to the data structure we were using */	psh->hostdata[0] = (unsigned long)NULL;	/* we always have a successful release */	return 0;}/* run command */static int command( Scsi_Cmnd *srb ){	US_DEBUGP("Bad use of us_command\n");	return DID_BAD_TARGET << 16;}/* run command */static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)){	struct us_data *us = (struct us_data *)srb->host->hostdata[0];	unsigned long flags;	US_DEBUGP("queuecommand() called\n");	srb->host_scribble = (unsigned char *)us;	/* get exclusive access to the structures we want */	spin_lock_irqsave(&(us->queue_exclusion), flags);	/* enqueue the command */	us->queue_srb = srb;	srb->scsi_done = done;	us->action = US_ACT_COMMAND;	/* release the lock on the structure */	spin_unlock_irqrestore(&(us->queue_exclusion), flags);	/* wake up the process task */	up(&(us->sema));	return 0;}/*********************************************************************** * Error handling functions ***********************************************************************//* Command abort */static int command_abort( Scsi_Cmnd *srb ){	struct us_data *us = (struct us_data *)srb->host->hostdata[0];	US_DEBUGP("command_abort() called\n");	/* if we're stuck waiting for an IRQ, simulate it */	if (atomic_read(us->ip_wanted)) {		US_DEBUGP("-- simulating missing IRQ\n");		up(&(us->ip_waitq));	}	/* if the device has been removed, this worked */	if (!us->pusb_dev) {		US_DEBUGP("-- device removed already\n");		return SUCCESS;	}	/* if we have an urb pending, let's wake the control thread up */	if (!us->current_done.done) {		atomic_inc(&us->abortcnt);		spin_unlock_irq(&io_request_lock);		/* cancel the URB -- this will automatically wake the thread */		usb_unlink_urb(us->current_urb);		/* wait for us to be done */		wait_for_completion(&(us->notify));		spin_lock_irq(&io_request_lock);		atomic_dec(&us->abortcnt);		return SUCCESS;	}	US_DEBUGP ("-- nothing to abort\n");	return FAILED;}/* This invokes the transport reset mechanism to reset the state of the * device */static int device_reset( Scsi_Cmnd *srb ){	struct us_data *us = (struct us_data *)srb->host->hostdata[0];	int rc;	US_DEBUGP("device_reset() called\n" );	spin_unlock_irq(&io_request_lock);	down(&(us->dev_semaphore));	if (!us->pusb_dev) {		up(&(us->dev_semaphore));		spin_lock_irq(&io_request_lock);		return SUCCESS;	}	rc = us->transport_reset(us);	up(&(us->dev_semaphore));	spin_lock_irq(&io_request_lock);	return rc;}/* This resets the device port, and simulates the device * disconnect/reconnect for all drivers which have claimed other * interfaces. */static int bus_reset( Scsi_Cmnd *srb ){	struct us_data *us = (struct us_data *)srb->host->hostdata[0];	int i;	int result;	/* we use the usb_reset_device() function to handle this for us */	US_DEBUGP("bus_reset() called\n");	spin_unlock_irq(&io_request_lock);	down(&(us->dev_semaphore));	/* if the device has been removed, this worked */	if (!us->pusb_dev) {		US_DEBUGP("-- device removed already\n");		up(&(us->dev_semaphore));		spin_lock_irq(&io_request_lock);		return SUCCESS;	}	/* The USB subsystem doesn't handle synchronisation between	 * a device's several drivers. Therefore we reset only devices	 * with just one interface, which we of course own. */	if (us->pusb_dev->actconfig->bNumInterfaces != 1) {		printk(KERN_NOTICE "usb-storage: "		    "Refusing to reset a multi-interface device\n");		up(&(us->dev_semaphore));		spin_lock_irq(&io_request_lock);		/* XXX Don't just return success, make sure current cmd fails */		return SUCCESS;	}	/* release the IRQ, if we have one */	if (us->irq_urb) {		US_DEBUGP("-- releasing irq URB\n");		result = usb_unlink_urb(us->irq_urb);		US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);	}	/* attempt to reset the port */	if (usb_reset_device(us->pusb_dev) < 0) {		/*		 * Do not return errors, or else the error handler might		 * invoke host_reset, which is not implemented.		 */		goto bail_out;	}	/* FIXME: This needs to lock out driver probing while it's working	 * or we can have race conditions */        for (i = 0; i < us->pusb_dev->actconfig->bNumInterfaces; i++) { 		struct usb_interface *intf =			&us->pusb_dev->actconfig->interface[i];		const struct usb_device_id *id;		/* if this is an unclaimed interface, skip it */		if (!intf->driver) {			continue;		}		US_DEBUGP("Examinging driver %s...", intf->driver->name);		/* skip interfaces which we've claimed */		if (intf->driver == &usb_storage_driver) {			US_DEBUGPX("skipping ourselves.\n");			continue;		}		/* simulate a disconnect and reconnect for all interfaces */		US_DEBUGPX("simulating disconnect/reconnect.\n");		down(&intf->driver->serialize);		intf->driver->disconnect(us->pusb_dev, intf->private_data);		id = usb_match_id(us->pusb_dev, intf, intf->driver->id_table);		intf->driver->probe(us->pusb_dev, i, id);		up(&intf->driver->serialize);	}bail_out:	/* re-allocate the IRQ URB and submit it to restore connectivity	 * for CBI devices	 */	if (us->protocol == US_PR_CBI) {		us->irq_urb->dev = us->pusb_dev;		result = usb_submit_urb(us->irq_urb);		US_DEBUGP("usb_submit_urb() returns %d\n", result);	}	up(&(us->dev_semaphore));	spin_lock_irq(&io_request_lock);	US_DEBUGP("bus_reset() complete\n");	return SUCCESS;}/* FIXME: This doesn't do anything right now */static int host_reset( Scsi_Cmnd *srb ){	printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" );	return FAILED;}/*********************************************************************** * /proc/scsi/ functions ***********************************************************************//* we use this macro to help us write into the buffer */#undef SPRINTF#define SPRINTF(args...) \	do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)static int proc_info (char *buffer, char **start, off_t offset, int length,		int hostno, int inout){	struct us_data *us;	char *pos = buffer;	/* if someone is sending us data, just throw it away */	if (inout)		return length;	/* lock the data structures */	down(&us_list_semaphore);	/* find our data from hostno */	us = us_list;	while (us) {		if (us->host_no == hostno)			break;		us = us->next;	}	/* release our lock on the data structures */	up(&us_list_semaphore);	/* if we couldn't find it, we return an error */	if (!us) {		return -ESRCH;	}	/* print the controller name */	SPRINTF("   Host scsi%d: usb-storage\n", hostno);	/* print product, vendor, and serial number strings */	SPRINTF("       Vendor: %s\n", us->vendor);	SPRINTF("      Product: %s\n", us->product);	SPRINTF("Serial Number: %s\n", us->serial);	/* show the protocol and transport */	SPRINTF("     Protocol: %s\n", us->protocol_name);	SPRINTF("    Transport: %s\n", us->transport_name);	/* show the GUID of the device */	SPRINTF("         GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));	SPRINTF("     Attached: %s\n", us->pusb_dev ? "Yes" : "No");	/*	 * Calculate start of next buffer, and return value.	 */	*start = buffer + offset;	if ((pos - buffer) < offset)		return (0);	else if ((pos - buffer - offset) < length)		return (pos - buffer - offset);	else		return (length);}/* * this defines our 'host' */Scsi_Host_Template usb_stor_host_template = {	name:			"usb-storage",	proc_info:		proc_info,	info:			host_info,	detect:			detect,	release:		release,	command:		command,	queuecommand:		queuecommand,	eh_abort_handler:	command_abort,	eh_device_reset_handler:device_reset,	eh_bus_reset_handler:	bus_reset,	eh_host_reset_handler:	host_reset,	can_queue:		1,	this_id:		-1,	sg_tablesize:		SG_ALL,	cmd_per_lun:		1,	present:		0,	unchecked_isa_dma:	FALSE,	use_clustering:		TRUE,	use_new_eh_code:	TRUE,	emulated:		TRUE};unsigned char usb_stor_sense_notready[18] = {	[0]	= 0x70,			    /* current error */	[2]	= 0x02,			    /* not ready */	[5]	= 0x0a,			    /* additional length */	[10]	= 0x04,			    /* not ready */	[11]	= 0x03			    /* manual intervention */};#define USB_STOR_SCSI_SENSE_HDRSZ 4#define USB_STOR_SCSI_SENSE_10_HDRSZ 8struct usb_stor_scsi_sense_hdr{  __u8* dataLength;  __u8* mediumType;  __u8* devSpecParms;  __u8* blkDescLength;};typedef struct usb_stor_scsi_sense_hdr Usb_Stor_Scsi_Sense_Hdr;union usb_stor_scsi_sense_hdr_u{  Usb_Stor_Scsi_Sense_Hdr hdr;  __u8* array[USB_STOR_SCSI_SENSE_HDRSZ];};

⌨️ 快捷键说明

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