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

📄 usb.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Driver for USB Mass Storage compliant devices * * $Id: usb.c,v 1.57 2000/11/21 02:56:41 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) * * 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 <linux/config.h>#include "usb.h"#include "scsiglue.h"#include "transport.h"#include "protocol.h"#include "debug.h"#include "initializers.h"#ifdef CONFIG_USB_STORAGE_HP8200e#include "shuttle_usbat.h"#endif#ifdef CONFIG_USB_STORAGE_SDDR09#include "sddr09.h"#endif#ifdef CONFIG_USB_STORAGE_DPCM#include "dpcm.h"#endif#ifdef CONFIG_USB_STORAGE_FREECOM#include "freecom.h"#endif#include <linux/module.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/malloc.h>/* Some informational data */MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");MODULE_DESCRIPTION("USB Mass Storage driver for Linux");/* * Per device data */static int my_host_number;/* * 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/* The list of structures and the protective lock for them */struct us_data *us_list;struct semaphore us_list_semaphore;static void * storage_probe(struct usb_device *dev, unsigned int ifnum,			    const struct usb_device_id *id);static void storage_disconnect(struct usb_device *dev, void *ptr);struct usb_driver usb_storage_driver = {	name:		"usb-storage",	probe:		storage_probe,	disconnect:	storage_disconnect,};/* * fill_inquiry_response takes an unsigned char array (which must * be at least 36 characters) and populates the vendor name, * product name, and revision fields. Then the array is copied * into the SCSI command's response buffer (oddly enough * called request_buffer). data_len contains the length of the * data array, which again must be at least 36. */void fill_inquiry_response(struct us_data *us, unsigned char *data,		unsigned int data_len) {	int i;	struct scatterlist *sg;	int len =		us->srb->request_bufflen > data_len ? data_len :		us->srb->request_bufflen;	int transferred;	int amt;	if (data_len<36) // You lose.		return;	memcpy(data+8, us->unusual_dev->vendorName, 		strlen(us->unusual_dev->vendorName) > 8 ? 8 :		strlen(us->unusual_dev->vendorName));	memcpy(data+16, us->unusual_dev->productName, 		strlen(us->unusual_dev->productName) > 16 ? 16 :		strlen(us->unusual_dev->productName));	data[32] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>12) & 0x0F);	data[33] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>8) & 0x0F);	data[34] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>4) & 0x0F);	data[35] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice) & 0x0F);	if (us->srb->use_sg) {		sg = (struct scatterlist *)us->srb->request_buffer;		for (i=0; i<us->srb->use_sg; i++)			memset(sg[i].address, 0, sg[i].length);		for (i=0, transferred=0; 				i<us->srb->use_sg && transferred < len;				i++) {			amt = sg[i].length > len-transferred ? 					len-transferred : sg[i].length;			memcpy(sg[i].address, data+transferred, amt);			transferred -= amt;		}	} else {		memset(us->srb->request_buffer, 0, us->srb->request_bufflen);		memcpy(us->srb->request_buffer, data, len);	}}static int usb_stor_control_thread(void * __us){	wait_queue_t wait;	struct us_data *us = (struct us_data *)__us;	int action;	lock_kernel();	/*	 * This thread doesn't need any user-level access,	 * so get rid of all our resources..	 */	exit_files(current);	current->files = init_task.files;	atomic_inc(&current->files->count);	daemonize();	/* set our name for identification purposes */	sprintf(current->comm, "usb-storage-%d", us->host_number);	unlock_kernel();	/* set up for wakeups by new commands */	init_waitqueue_entry(&wait, current);	init_waitqueue_head(&(us->wqh));	add_wait_queue(&(us->wqh), &wait);	/* signal that we've started the thread */	up(&(us->notify));	set_current_state(TASK_INTERRUPTIBLE);	for(;;) {		US_DEBUGP("*** thread sleeping.\n");		schedule();		US_DEBUGP("*** thread awakened.\n");		/* lock access to the queue element */		down(&(us->queue_exclusion));		/* take the command off the queue */		action = us->action;		us->action = 0;		us->srb = us->queue_srb;		/* release the queue lock as fast as possible */		up(&(us->queue_exclusion));		switch (action) {		case US_ACT_COMMAND:			/* reject the command if the direction indicator 			 * is UNKNOWN			 */			if (us->srb->sc_data_direction == SCSI_DATA_UNKNOWN) {				US_DEBUGP("UNKNOWN data direction\n");				us->srb->result = DID_ERROR << 16;				set_current_state(TASK_INTERRUPTIBLE);				us->srb->scsi_done(us->srb);				us->srb = NULL;				break;			}			/* reject if target != 0 or if LUN is higher than			 * the maximum known LUN			 */			if (us->srb->target && 					!(us->flags & US_FL_SCM_MULT_TARG)) {				US_DEBUGP("Bad target number (%d/%d)\n",					  us->srb->target, us->srb->lun);				us->srb->result = DID_BAD_TARGET << 16;				set_current_state(TASK_INTERRUPTIBLE);				us->srb->scsi_done(us->srb);				us->srb = NULL;				break;			}			if (us->srb->lun > us->max_lun) {				US_DEBUGP("Bad LUN (%d/%d)\n",					  us->srb->target, us->srb->lun);				us->srb->result = DID_BAD_TARGET << 16;				set_current_state(TASK_INTERRUPTIBLE);				us->srb->scsi_done(us->srb);				us->srb = NULL;				break;			}			/* handle those devices which can't do a START_STOP */			if ((us->srb->cmnd[0] == START_STOP) &&			    (us->flags & US_FL_START_STOP)) {				US_DEBUGP("Skipping START_STOP command\n");				us->srb->result = GOOD << 1;				set_current_state(TASK_INTERRUPTIBLE);				us->srb->scsi_done(us->srb);				us->srb = NULL;				break;			}			/* lock the device pointers */			down(&(us->dev_semaphore));			/* our device has gone - pretend not ready */			if (!us->pusb_dev) {				US_DEBUGP("Request is for removed device\n");				/* For REQUEST_SENSE, it's the data.  But				 * for anything else, it should look like				 * we auto-sensed for it.				 */				if (us->srb->cmnd[0] == REQUEST_SENSE) {					memcpy(us->srb->request_buffer, 					       usb_stor_sense_notready, 					       sizeof(usb_stor_sense_notready));					us->srb->result = GOOD << 1;				} else {					memcpy(us->srb->sense_buffer, 					       usb_stor_sense_notready, 					       sizeof(usb_stor_sense_notready));					us->srb->result = CHECK_CONDITION << 1;				}			} else { /* !us->pusb_dev */				/* we've got a command, let's do it! */				US_DEBUG(usb_stor_show_command(us->srb));				us->proto_handler(us->srb, us);			}			/* unlock the device pointers */			up(&(us->dev_semaphore));			/* indicate that the command is done */			if (us->srb->result != DID_ABORT << 16) {				US_DEBUGP("scsi cmd done, result=0x%x\n", 					   us->srb->result);				set_current_state(TASK_INTERRUPTIBLE);				us->srb->scsi_done(us->srb);			} else {				US_DEBUGP("scsi command aborted\n");				set_current_state(TASK_INTERRUPTIBLE);				up(&(us->notify));			}			us->srb = NULL;			break;		case US_ACT_DEVICE_RESET:			break;		case US_ACT_BUS_RESET:			break;		case US_ACT_HOST_RESET:			break;		} /* end switch on action */		/* exit if we get a signal to exit */		if (action == US_ACT_EXIT) {			US_DEBUGP("-- US_ACT_EXIT command recieved\n");			break;		}	} /* for (;;) */	/* clean up after ourselves */	set_current_state(TASK_INTERRUPTIBLE);	remove_wait_queue(&(us->wqh), &wait);	/* notify the exit routine that we're actually exiting now */	up(&(us->notify));	return 0;}	/* This is the list of devices we recognize, along with their flag data *//* The vendor name should be kept at eight characters or less, and * the product name should be kept at 16 characters or less. If a device * has the US_FL_DUMMY_INQUIRY flag, then the vendor and product names * normally generated by a device thorugh the INQUIRY response will be * taken from this list, and this is the reason for the above size * restriction. However, if the flag is not present, then you * are free to use as many characters as you like. */static struct us_unusual_dev us_unusual_dev_list[] = {	{ 0x03ee, 0x0000, 0x0000, 0x0245, 		"Mitsumi",		"CD-R/RW Drive",		US_SC_8020, US_PR_CBI, NULL, 0}, 	{ 0x03f0, 0x0107, 0x0200, 0x0200, 		"HP",		"CD-Writer+",		US_SC_8070, US_PR_CB, NULL, 0}, #ifdef CONFIG_USB_STORAGE_HP8200e	{ 0x03f0, 0x0207, 0x0001, 0x0001, 		"HP",		"CD-Writer+ 8200e",		US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0}, #endif	{ 0x04e6, 0x0001, 0x0200, 0x0200, 		"Matshita",		"LS-120",		US_SC_8020, US_PR_CB, NULL, 0},	{ 0x04e6, 0x0002, 0x0100, 0x0100, 		"Shuttle",		"eUSCSI Bridge",		US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, 		US_FL_SCM_MULT_TARG }, #ifdef CONFIG_USB_STORAGE_SDDR09	{ 0x04e6, 0x0003, 0x0000, 0x9999, 		"Sandisk",		"ImageMate SDDR09",		US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,		US_FL_SINGLE_LUN | US_FL_START_STOP },#endif#ifdef CONFIG_USB_STORAGE_DPCM 	{ 0x0436, 0x0005, 0x0100, 0x0100,		"Microtech",		"CameraMate (DPCM_USB)", 		US_SC_SCSI, US_PR_DPCM_USB, NULL,		US_FL_START_STOP },#endif	{ 0x04e6, 0x0006, 0x0100, 0x0200, 		"Shuttle",		"eUSB MMC Adapter",		US_SC_SCSI, US_PR_CB, NULL, 		US_FL_SINGLE_LUN}, 	{ 0x04e6, 0x0007, 0x0100, 0x0200, 		"Sony",		"Hifd",		US_SC_SCSI, US_PR_CB, NULL, 		US_FL_SINGLE_LUN}, 	{ 0x04e6, 0x0009, 0x0200, 0x0200, 		"Shuttle",

⌨️ 快捷键说明

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