read()函数流程(USB读取文件)

ssize_t read(int fd, FAR void *buf, size_t nbytes);

通过当前的TCB(或者说PCB的文件列表找到) 找到打开的文件列表group->tg_filelist,然后根据相应的fd,找到对应filep(&list->fl_files[fd])。

size_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes);

每一个filep都对应着一个inode节点,对后的对硬件真正意义上的读写也是对inode所注册的回调函数的读写。

ret = (int)inode->u.i_ops->read(filep, (FAR char *)buf, (size_t)nbytes);

而该回调函数是在mount文件系统的时候被赋值的,其中我们使用的是fat32文件系统,所以最后得到的是fat_xxx相关函数,至于文件系统操作函数结构体u.i_mops和何时被赋值给u.i_ops的具体步骤还是么有找到。

int register_driver(FAR const char *path, FAR const struct file_operations *fops, mode_t mode, FAR void *priv)

{ node->u.i_ops   = fops; }

之后调用到static ssize_t fat_read(FAR struct file *filep, FAR char *buffer,size_t buflen);

在读数据之前会检查挂载点现在是否正常,实际上最终调用的还是块设备驱动程序,注册上来的geometry函数。

同时需要确定当前读的位置,并且将脏数据重新写回块设备中去,最后才开始读。

而读写的函数分别是

int fat_hwwrite(struct fat_mountpt_s *fs, uint8_t *buffer, off_t sector, unsigned int nsectors);

{ inode->u.i_bops->write(inode, buffer,sector, nsectors);

int fat_hwread(struct fat_mountpt_s *fs, uint8_t *buffer,  off_t sector, unsigned int nsectors);

{ inode->u.i_bops->read(inode, buffer,sector, nsectors);}

上面的最主要的是找到u.i_bops的回调函数是谁来提供的。

int register_blockdriver(FAR const char *path, FAR const struct block_operations *bops, mode_t mode, FAR void *priv)

{ node->u.i_bops  = bops  }

该函数在static inline int usbhost_initvolume(FAR struct usbhost_state_s *priv);时被调用。

 static const struct block_operations g_bops =
 {
   usbhost_open,           /* open     */
   usbhost_close,          /* close    */
   usbhost_read,           /* read     */
 #ifdef CONFIG_FS_WRITABLE
   usbhost_write,          /* write    */
 #else
   NULL,                   /* write    */
 #endif
   usbhost_geometry,       /* geometry */
   usbhost_ioctl           /* ioctl    */
 };


static int silan_usb_initialize(void);

usbhost_msc_initialize();

usbhost_registerclass(&g_storage); //usbhost_registry_s g_storage

static struct usbhost_registry_s g_storage =
 {
   NULL,                   /* flink    */
   usbhost_create,         /* create   */
   1,                      /* nids     */
   &g_id                   /* id[]     */
 };
主要是赋值给g_classregistry,为以后usbhost_enumerate函数遍历链表的时候使用(主要是调用create)。


g_usbconn = silan_otghshost_initialize(0);

该函数主要是一些USB回调函数的注册

   drvr                 = &priv->drvr;
   drvr->ep0configure   = stm32_ep0configure;
   drvr->epalloc        = stm32_epalloc;
   drvr->epfree         = stm32_epfree;
   drvr->alloc          = stm32_alloc;
5111   drvr->free           = stm32_free;
   drvr->ioalloc        = stm32_ioalloc;
   drvr->iofree         = stm32_iofree;
   drvr->ctrlin         = stm32_ctrlin;
   drvr->ctrlout        = stm32_ctrlout;
   drvr->transfer       = stm32_transfer;
 #ifdef CONFIG_USBHOST_ASYNCH
   drvr->asynch         = stm32_asynch;
 #endif
   drvr->cancel         = stm32_cancel;
 #ifdef CONFIG_USBHOST_HUB
   drvr->connect        = stm32_connect;
 #endif
   drvr->disconnect     = stm32_disconnect;
 
   /* Initialize the public port representation */
 
   hport                = &priv->rhport.hport;
   hport->drvr          = drvr;
 #ifdef CONFIG_USBHOST_HUB
   hport->parent        = NULL;
 #endif
   hport->ep0           = (usbhost_ep_t)&priv->ep0;
   hport->speed         = USB_SPEED_FULL;

和中断处理函数的注册,有好几种中断状态的处理函数

(1) Handle the RxFIFO non-empty interrupt

(2)Handle the non-periodic TxFIFO empty interrupt

(3)Handle the periodic TxFIFO empty interrupt

(4)Handle the host channels interrupt

(5)Handle the host port interrupt

(6)Handle the disconnect detected interrupt

(7)Handle the incomplete periodic transfer

当然少不了USB硬件初始化(配置寄存器)的步骤

最后返回usbhost_connection_s g_usbconn USB连接类型的结构体

 static struct usbhost_connection_s g_usbconn =
 {
   .wait             = stm32_wait,
   .enumerate        = stm32_enumerate,
 };


最后创建一个线程,里面等待连接,并且枚举连接成功的USB设备。(猜想是可以支持热插拔)

实际上最核心的函数是int usbhost_enumerate(FAR struct usbhost_hubport_s *hport, FAR struct usbhost_class_s **devclass)

(1) get the device's configuration descriptor, 

(2)extract the class ID info from the configuration descriptor, 

(3) call usbhost_findclass() to find the class that supports this device,

(4) call the create() method on the struct usbhost_registry_s interface to get a class instance, and finally 

(5) call the connect() method of the struct usbhost_class_s interface.  

首先给请求和数据分别分配各自的空间(通过malloc来实现)。

配置端点0最大的数据包大小,注意每一个USB设备都需要都端点0。

从设备描述符中获取最大的数据包大小,然后重新配置端点0。

为这个设备创建新的设备地址,然后再发送设置新地址的请求,然后重新配置端点0的地址。

之后比较关键的是

static inline int usbhost_classbind(FAR struct usbhost_hubport_s *hport, const uint8_t *configdesc, int desclen,

struct usbhost_id_s *id,  FAR struct usbhost_class_s **usbclass)

该函数中就有我们之前注册号的g_classregistry,然后调用它的create函数。

static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_hubport_s *hport, FAR const struct usbhost_id_s *id);

该函数又会注册几个回调函数,供接下来返回之后马上引用。

  <span style="white-space:pre">	</span>   priv->usbclass.hport        = hport;
           priv->usbclass.connect      = usbhost_connect;
           priv->usbclass.disconnected = usbhost_disconnected;

以后要被用到的就是

static int usbhost_connect(FAR struct usbhost_class_s *usbclass, FAR const uint8_t *configdesc, int desclen);

{

usbhost_cfgdesc(priv, configdesc, desclen); //获取配置文件参数,并且配置端点0,当然在该函数中也定义好了传输方向是IN还是OUT

usbhost_initvolume(priv); //该函数也是核心函数,主要是注册块设备

}

static inline int usbhost_initvolume(FAR struct usbhost_state_s *priv);

分配传输数据的缓冲区。

发送获取最大LUN号(logic unit number)。

读取U盘需要使用到CBW结构,填充好数据之后,发送不同的CBW操作码,就能返回各种不同的状态CSW。

 /* Command Block Wrapper (CBW) */
 
 struct usbmsc_cbw_s
 {
   uint8_t signature[4];           /* 'USBC' = 0x43425355 */
   uint8_t tag[4];                 /* Depends on command id */
   uint8_t datlen[4];              /* Number of bytes that host expects to transfer */
   uint8_t flags;                  /* Bit 7: Direction=IN (other obsolete or reserved) */
   uint8_t lun;                    /* LUN (normally 0) */
   uint8_t cdblen;                 /* len of cdb[] */
   uint8_t cdb[USBMSC_MAXCDBLEN];  /* Command Data Block */
 }; 
 
 /* Command Status Wrapper (CSW) */
 
 struct usbmsc_csw_s
 {
   uint8_t signature[4];           /* 'USBS' = 0x53425355 */
   uint8_t tag[4];                 /* Same tag as original command */
   uint8_t residue[4];             /* Amount not transferred */
   uint8_t status;                 /* Status of transfer */
 };

 /* Common Block Wrapper (CBW) */
 
 #define USBMSC_CBW_SIZEOF            (31)
 #define USBMSC_CBW_SIGNATURE         (0x43425355)   /*  Little endian USBC */
 #define USBMSC_CBWFLAG_IN            (0x80)         /* Bit 7=1: Direction = IN */
 
 #define USBMSC_MAXCDBLEN             (16)           /* Max length of SCSI Command Data Block */
 
 /* Command Status Wrapper (CSW) */
 
 #define USBMSC_CSW_SIZEOF            (13)
 #define USBMSC_CSW_SIGNATURE         (0x53425355)   /* Little endian 'USBS' */
 #define USBMSC_CSWSTATUS_PASS        (0)
 #define USBMSC_CSWSTATUS_FAIL        (1)
 #define USBMSC_CSWSTATUS_PHASEERROR  (2) 

最后当然少不了注册块设备驱动程序register_blockdriver(devname, &g_bops, 0, priv);

 static const struct block_operations g_bops =
  {
    usbhost_open,           /* open     */
    usbhost_close,          /* close    */
    usbhost_read,           /* read     */
  #ifdef CONFIG_FS_WRITABLE
    usbhost_write,          /* write    */
  #else
    NULL,                   /* write    */
  #endif
    usbhost_geometry,       /* geometry */
    usbhost_ioctl           /* ioctl    */
  };
以USB读作为例子

static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer, size_t startsector, unsigned int nsectors);

过程和之前相同,构建分配CBW,填充CBW,最后发送CBW请求,之后开始读取真正的数据。

cbw = usbhost_cbwalloc(priv);

usbhost_readcbw(startsector, priv->blocksize, nsectors, cbw);

DRVR_TRANSFER(hport->drvr, priv->bulkout, (FAR uint8_t *)cbw, USBMSC_CBW_SIZEOF);

DRVR_TRANSFER(hport->drvr, priv->bulkin, buffer, priv->blocksize * nsectors);

而这里的核心又是之前在sw_initialize中注册好的回调函数。

static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen);

而传输USB的数据结构的核心

  struct stm32_chan_s
  {
    sem_t             waitsem;   /* Channel wait semaphore */
    volatile uint8_t  result;    /* The result of the transfer */
    volatile uint8_t  chreason;  /* Channel halt reason. See enum stm32_chreason_e */
    uint8_t           chidx;     /* Channel index */
    uint8_t           epno;      /* Device endpoint number (0-127) */
    uint8_t           eptype;    /* See OTGHS_EPTYPE_* definitions */
    uint8_t           funcaddr;  /* Device function address */
    uint8_t           speed;     /* Device speed */
    uint8_t           pid;       /* Data PID */
    uint8_t           npackets;  /* Number of packets (for data toggle) */
    bool              inuse;     /* True: This channel is "in use" */
    volatile bool     indata1;   /* IN data toggle. True: DATA01 (Bulk and INTR only) */
    volatile bool     outdata1;  /* OUT data toggle.  True: DATA01 */
    bool              in;        /* True: IN endpoint */
    volatile bool     waiter;    /* True: Thread is waiting for a channel event */
    uint16_t          maxpacket; /* Max packet size */
    uint16_t          buflen;    /* Buffer length (at start of transfer) */
    volatile uint16_t xfrd;      /* Bytes transferred (at end of transfer) */
    volatile uint16_t inflight;  /* Number of Tx bytes "in-flight" */
    FAR uint8_t      *buffer;    /* Transfer buffer pointer */
  #ifdef CONFIG_USBHOST_ASYNCH
    usbhost_asynch_t  callback;  /* Transfer complete callback */
    FAR void         *arg;       /* Argument that accompanies the callback */
  #endif
  };

传输主要分三步:

(1)Set up for the wait BEFORE starting the transfer

(2)Set up for the transfer based on the direction and the endpoint type

(3)Wait for the transfer to complete and get the result


USB有四种传输方式

 #define OTGHS_EPTYPE_CTRL               (0) /* Control */
 #define OTGHS_EPTYPE_ISOC               (1) /* Isochronous */
 #define OTGHS_EPTYPE_BULK               (2) /* Bulk */
 #define OTGHS_EPTYPE_INTR               (3) /* Interrupt */


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值