linux 源码的U盘(三)



/* Probe to see if we can drive a newly-connected USB device */
static int storage_probe(struct usb_interface *intf,
			 const struct usb_device_id *id)
{
	struct Scsi_Host *host;
	struct us_data *us;
	int result;
	struct task_struct *th;

	if (usb_usual_check_type(id, USB_US_TYPE_STOR))
		return -ENXIO;

	US_DEBUGP("USB Mass Storage device detected\n");

	/*
	 * Ask the SCSI layer to allocate a host structure, with extra
	 * space at the end for our private us_data structure.
	 */
	host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us));
	if (!host) {
		printk(KERN_WARNING USB_STORAGE
			"Unable to allocate the scsi host\n");
		return -ENOMEM;
	}

	us = host_to_us(host);
	memset(us, 0, sizeof(struct us_data));
	mutex_init(&(us->dev_mutex));
	init_MUTEX_LOCKED(&(us->sema));
	init_completion(&(us->notify));
	init_waitqueue_head(&us->delay_wait);

	/* Associate the us_data structure with the USB device */
	result = associate_dev(us, intf);
	if (result)
		goto BadDevice;

	/*
	 * Get the unusual_devs entries and the descriptors
	 *
	 * id_index is calculated in the declaration to be the index number
	 * of the match from the usb_device_id table, so we can find the
	 * corresponding entry in the private table.
	 */
	result = get_device_info(us, id);
	if (result)
		goto BadDevice;

	/* Get the transport, protocol, and pipe settings */
	result = get_transport(us);
	if (result)
		goto BadDevice;
	result = get_protocol(us);
	if (result)
		goto BadDevice;
	result = get_pipes(us);
	if (result)
		goto BadDevice;

	/* Acquire all the other resources and add the host */
	result = usb_stor_acquire_resources(us);
	if (result)
		goto BadDevice;
	result = scsi_add_host(host, &intf->dev);
	if (result) {
		printk(KERN_WARNING USB_STORAGE
			"Unable to add the scsi host\n");
		goto BadDevice;
	}

	/* Start up the thread for delayed SCSI-device scanning */
	th = kthread_create(usb_stor_scan_thread, us, "usb-stor-scan");
	if (IS_ERR(th)) {
		printk(KERN_WARNING USB_STORAGE 
		       "Unable to start the device-scanning thread\n");
		quiesce_and_remove_host(us);
		result = PTR_ERR(th);
		goto BadDevice;
	}

	/* Take a reference to the host for the scanning thread and
	 * count it among all the threads we have launched.  Then
	 * start it up. */
	scsi_host_get(us_to_host(us));
	atomic_inc(&total_threads);
	wake_up_process(th);

	return 0;

	/* We come here if there are any problems */
BadDevice:
	US_DEBUGP("storage_probe() failed\n");
	release_everything(us);
	return result;
}

usb最基本的通信是通过endpoint通信,一个U盘做为存储设备,至少有一个控制端点,两个bulk端点。

USB协议里规定USB设备有四种通信方式,分别为控制传输、中断传输、批量传输、等时传输。

  1. 等时传输:用于音频和视频数据传输
  2. 控制传输:获取设备的各种描述符。
  3. 批量传输:U盘
  4. 中断传输:鼠标

其他对于本文不重要,本文只关注u盘,u盘使用的是一个叫做 Bulk-Only 的传输协议.使用这种
协议的设备只有两种传输方式,一种是批量传输,另一种是控制传输,控制传输是任何一种 usb 设
备都必须支持的,它专门用于传输一些控制信息.比如我想查询一下关于这个 interface 的一些信
息,那么就用控制传输,而 bulk 传输,它就是 U 盘的主要工作了,读写数据,这种情况就得用 bulk
传输。


/*
 * The entries in this table correspond, line for line,
 * with the entries of us_unusual_dev_list[].
 */
#ifndef CONFIG_USB_LIBUSUAL

#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
            vendorName, productName,useProtocol, useTransport, \
            initFunction, flags) \
{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax), \
  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }

#define USUAL_DEV(useProto, useTrans, useType) \
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \
  .driver_info = (USB_US_TYPE_STOR<<24) }

static struct usb_device_id storage_usb_ids [] = {

#    include "unusual_devs.h"
#undef UNUSUAL_DEV
#undef USUAL_DEV
    /* Terminating entry */
    { }
};

在unusual_devs.h有

/* Control/Bulk transport for all SubClass values */
USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_8020, US_PR_CB, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_QIC, US_PR_CB, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_UFI, US_PR_CB, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_8070, US_PR_CB, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_SCSI, US_PR_CB, USB_US_TYPE_STOR),

/* Control/Bulk/Interrupt transport for all SubClass values */
USUAL_DEV(US_SC_RBC, US_PR_CBI, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_8020, US_PR_CBI, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_QIC, US_PR_CBI, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_UFI, US_PR_CBI, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_8070, US_PR_CBI, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_SCSI, US_PR_CBI, USB_US_TYPE_STOR),

/* Bulk-only transport for all SubClass values */
USUAL_DEV(US_SC_RBC, US_PR_BULK, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_8020, US_PR_BULK, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_QIC, US_PR_BULK, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_UFI, US_PR_BULK, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_8070, US_PR_BULK, USB_US_TYPE_STOR),
USUAL_DEV(US_SC_SCSI, US_PR_BULK, 0),


其中u盘是USUAL_DEV(US_SC_SCSI, US_PR_BULK, 0)解析后

{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK), \
  .driver_info = (USB_US_TYPE_STOR<<24) }

其中USB_INTERFACE_INFO是在usb.h

/**
 * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces 
 * @cl: bInterfaceClass value
 * @sc: bInterfaceSubClass value
 * @pr: bInterfaceProtocol value
 *
 * This macro is used to create a struct usb_device_id that matches a
 * specific class of interfaces.
 */
#define USB_INTERFACE_INFO(cl,sc,pr) \
    .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), \
    .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
看到这么多目的是为了看probe的第一个函数usb_usual_check_type

/*
 * Match the calling driver type against the table.
 * Returns: 0 if the device matches.
 */
int usb_usual_check_type(const struct usb_device_id *id, int caller_type)
{
    int id_type = USB_US_TYPE(id->driver_info);

    if (caller_type <= 0 || caller_type >= 3)
        return -EINVAL;

    /* Drivers grab fixed assignment devices */
    if (id_type == caller_type)
        return 0;
    /* Drivers grab devices biased to them */
    if (id_type == USB_US_TYPE_NONE && caller_type == atomic_read(&usu_bias))
        return 0;
    return -ENODEV;
}

 

/*
 * The bias field for libusual and friends.
 */
#define USB_US_TYPE_NONE   0
#define USB_US_TYPE_STOR   1        /* usb-storage */
#define USB_US_TYPE_UB     2        /* ub */

 if (usb_usual_check_type(id, caller_type ))
        return -ENXIO;

这个函数caller_type =USB_US_TYPE_STOR 

#define USB_US_TYPE(flags)         (((flags) >> 24) & 0xFF)
其中id_type是USB_US_TYPE(id->driver_info)

.driver_info = (USB_US_TYPE_STOR<<24)

所以id_type = USB_US_TYPE_STOR,函数判断id_type == caller_type返回0.

接下来看US_DEBUGP("USB Mass Storage device detected\n");

#ifdef CONFIG_USB_STORAGE_DEBUG
void usb_stor_show_command(struct scsi_cmnd *srb);
void usb_stor_show_sense( unsigned char key,
        unsigned char asc, unsigned char ascq );
#define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE x )
#define US_DEBUGPX(x...) printk( x )
#define US_DEBUG(x) x 
#else
#define US_DEBUGP(x...)
#define US_DEBUGPX(x...)
#define US_DEBUG(x)
#endif

#endif
如果配置CONFIG_USB_STORAGE_DEBUG则会用打印函数printk。

下面看host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us));


/* we allocate one of these for every device that we remember */
struct us_data {
	/* The device we're working with
	 * It's important to note:
	 *    (o) you must hold dev_mutex to change pusb_dev
	 */
	struct mutex		dev_mutex;	 /* protect pusb_dev */
	struct usb_device	*pusb_dev;	 /* this usb_device */
	struct usb_interface	*pusb_intf;	 /* this interface */
	struct us_unusual_dev   *unusual_dev;	 /* device-filter entry     */
	unsigned long		flags;		 /* from filter initially */
	unsigned int		send_bulk_pipe;	 /* cached pipe values */
	unsigned int		recv_bulk_pipe;
	unsigned int		send_ctrl_pipe;
	unsigned int		recv_ctrl_pipe;
	unsigned int		recv_intr_pipe;

	/* information about the device */
	char			*transport_name;
	char			*protocol_name;
	__le32			bcs_signature;
	u8			subclass;
	u8			protocol;
	u8			max_lun;

	u8			ifnum;		 /* interface number   */
	u8			ep_bInterval;	 /* interrupt interval */ 

	/* function pointers for this device */
	trans_cmnd		transport;	 /* transport function	   */
	trans_reset		transport_reset; /* transport device reset */
	proto_cmnd		proto_handler;	 /* protocol handler	   */

	/* SCSI interfaces */
	struct scsi_cmnd	*srb;		 /* current srb		*/
	unsigned int		tag;		 /* current dCBWTag	*/

	/* control and bulk communications data */
	struct urb		*current_urb;	 /* USB requests	 */
	struct usb_ctrlrequest	*cr;		 /* control requests	 */
	struct usb_sg_request	current_sg;	 /* scatter-gather req.  */
	unsigned char		*iobuf;		 /* I/O buffer		 */
	unsigned char		*sensebuf;	 /* sense data buffer	 */
	dma_addr_t		cr_dma;		 /* buffer DMA addresses */
	dma_addr_t		iobuf_dma;

	/* mutual exclusion and synchronization structures */
	struct semaphore	sema;		 /* to sleep thread on	    */
	struct completion	notify;		 /* thread begin/end	    */
	wait_queue_head_t	delay_wait;	 /* wait during scan, reset */

	/* subdriver information */
	void			*extra;		 /* Any extra data          */
	extra_data_destructor	extra_destructor;/* extra data destructor   */
#ifdef CONFIG_PM
	pm_hook			suspend_resume_hook;
#endif
};

 


/**
 * scsi_host_alloc - register a scsi host adapter instance.
 * @sht:	pointer to scsi host template
 * @privsize:	extra bytes to allocate for driver
 *
 * Note:
 * 	Allocate a new Scsi_Host and perform basic initialization.
 * 	The host is not published to the scsi midlayer until scsi_add_host
 * 	is called.
 *
 * Return value:
 * 	Pointer to a new Scsi_Host
 **/
struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
{
	struct Scsi_Host *shost;
	gfp_t gfp_mask = GFP_KERNEL;
	int rval;

	if (sht->unchecked_isa_dma && privsize)
		gfp_mask |= __GFP_DMA;

	shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
	if (!shost)
		return NULL;

	shost->host_lock = &shost->default_lock;
	spin_lock_init(shost->host_lock);
	shost->shost_state = SHOST_CREATED;
	INIT_LIST_HEAD(&shost->__devices);
	INIT_LIST_HEAD(&shost->__targets);
	INIT_LIST_HEAD(&shost->eh_cmd_q);
	INIT_LIST_HEAD(&shost->starved_list);
	init_waitqueue_head(&shost->host_wait);

	mutex_init(&shost->scan_mutex);

	shost->host_no = scsi_host_next_hn++; /* XXX(hch): still racy */
	shost->dma_channel = 0xff;

	/* These three are default values which can be overridden */
	shost->max_channel = 0;
	shost->max_id = 8;
	shost->max_lun = 8;

	/* Give each shost a default transportt */
	shost->transportt = &blank_transport_template;

	/*
	 * All drivers right now should be able to handle 12 byte
	 * commands.  Every so often there are requests for 16 byte
	 * commands, but individual low-level drivers need to certify that
	 * they actually do something sensible with such commands.
	 */
	shost->max_cmd_len = 12;
	shost->hostt = sht;
	shost->this_id = sht->this_id;
	shost->can_queue = sht->can_queue;
	shost->sg_tablesize = sht->sg_tablesize;
	shost->cmd_per_lun = sht->cmd_per_lun;
	shost->unchecked_isa_dma = sht->unchecked_isa_dma;
	shost->use_clustering = sht->use_clustering;
	shost->ordered_tag = sht->ordered_tag;

	if (sht->max_host_blocked)
		shost->max_host_blocked = sht->max_host_blocked;
	else
		shost->max_host_blocked = SCSI_DEFAULT_HOST_BLOCKED;

	/*
	 * If the driver imposes no hard sector transfer limit, start at
	 * machine infinity initially.
	 */
	if (sht->max_sectors)
		shost->max_sectors = sht->max_sectors;
	else
		shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS;

	/*
	 * assume a 4GB boundary, if not set
	 */
	if (sht->dma_boundary)
		shost->dma_boundary = sht->dma_boundary;
	else
		shost->dma_boundary = 0xffffffff;

	rval = scsi_setup_command_freelist(shost);
	if (rval)
		goto fail_kfree;

	device_initialize(&shost->shost_gendev);
	snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d",
		shost->host_no);
	shost->shost_gendev.release = scsi_host_dev_release;

	class_device_initialize(&shost->shost_classdev);
	shost->shost_classdev.dev = &shost->shost_gendev;
	shost->shost_classdev.class = &shost_class;
	snprintf(shost->shost_classdev.class_id, BUS_ID_SIZE, "host%d",
		  shost->host_no);

	shost->ehandler = kthread_run(scsi_error_handler, shost,
			"scsi_eh_%d", shost->host_no);
	if (IS_ERR(shost->ehandler)) {
		rval = PTR_ERR(shost->ehandler);
		goto fail_destroy_freelist;
	}

	scsi_proc_hostdir_add(shost->hostt);
	return shost;

 fail_destroy_freelist:
	scsi_destroy_command_freelist(shost);
 fail_kfree:
	kfree(shost);
	return NULL;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值