请选择 进入手机版 | 继续访问电脑版
查看: 1012|回复: 0

[技术交流] USB接口WiFi驱动浅析 (二)

[复制链接]

185

主题

204

帖子

596

积分

利尔达员工

Rank: 9Rank: 9Rank: 9

积分
596
发表于 2020-10-13 09:26:33 | 显示全部楼层 |阅读模式
  二、USB 设备驱动分析

  在分析之前,我们需要理解在整个wifi模块中,USB充当什么角色?它的作用是什么?实质上wifi模块上的数据传输有两端,一端是wifi芯片与wifi芯片之间,通过无线射频(RF)进行数据传输;另一端则是wifi芯片与CPU之间,通过USB进行数据传输。

  了解Linux的USB驱动的读者都知道,USB驱动分为两种:一种是USB主机驱动;另一种是USB设备驱动。而我们的USB接口的wifi模块对于CPU(主机)来说,属于USB设备,因此采用USB设备驱动。

  有了以上信息之后,我们先让Linux系统识别该USB接口的wifi模块,首先我们在驱动源码中大致添加以下几步工作(前面分析过,这里只看步骤,不看代码):

  a——定义一个usb_driver结构体变量

  b——填充该设备的usb_driver结构体成员变量

  c——将该驱动注册到USB子系统

  简单完成以上几步工作,再加上板级文件(arch/mach-xxx.c)对USB设备的支持,Linux的USB子系统几乎可以挂载该wifi模块为USB设备了。但是这并不是我们最终想要的结果。我们还要让Linux系统知道它挂载的USB设备属于无线网络设备,同时能够访问它,利用它实施无线网络的工作。

  我们都知道,若要让USB设备真正工作起来,需要对USB设备的4个层次(设备、配置、接口、端点)进行初始化。当然这四个层次并不是一定都要进行初始化,而是根据你的USB设备的功能进行选择的,大致初始化流程如下伪代码:

  static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf)
  {
    int    i;
    u8     val8;
    int    status= _FAIL;
    struct dvobj_priv *pdvobjpriv;

    //设备
    struct usb_device *pusbd;
    struct usb_device_descriptor *pdev_desc;

    //配置
    struct usb_host_config *phost_conf;
    struct usb_config_descriptor *pconf_desc;

    //接口
    struct usb_host_interface *phost_iface;
    struct usb_interface_descriptor *piface_desc;

    //端点
    struct usb_host_endpoint *phost_endp;
    struct usb_endpoint_descriptor *pendp_desc;

    //设备的初始化
    pdvobjpriv->pusbintf = usb_intf ;
    pusbd =pdvobjpriv->pusbdev = interface_to_usbdev(usb_intf);
    usb_set_intfdata(usb_intf, pdvobjpriv);
    pdev_desc =&pusbd->descriptor;

    //配置的初始化
    phost_conf =pusbd->actconfig;
    pconf_desc =&phost_conf->desc;

    //接口的初始化
    phost_iface =&usb_intf->altsetting[0];
    piface_desc =&phost_iface->desc;

    //端点的初始化,由于wifi模块属于网络设备,传输批量数据,因此需要初始化为批量端点,端点方向(输入、输出)等。同时,由于wifi驱动功能比较多,需要初始化几个输入输出端点。
    for (i = 0; i <pdvobjpriv->nr_endpoint; i++)
    {
      phost_endp = phost_iface->endpoint +i;
      if (phost_endp)
      {
        pendp_desc =&phost_endp->desc;

        //检查是否为输入端点
        usb_endpoint_is_bulk_in(pendp_desc);

        //检查是否为输出端点
        usb_endpoint_is_bulk_out(pendp_desc);
      }

    }

    usb_get_dev(pusbd);
  }

  完成以上的初始化工作之后,接下来我们需要理清一下USB接口的作用,它是wifi芯片内部的固件程序与主机上的Linux系统进行数据通信。USB设备通信不像普通字符设备那样采用I/O内存和I/O端口的访问,而是采用一种称为URB(USB Request Block)的USB请求块,URB在整个USB子系统中,相当于通电设备中的“电波”,USB主机与设备的通信,通过“电波”来传递。下面我们就来编写USB接口的读写操作函数,伪代码如下:

  void xxx_wifi_usb_intf_ops(struct _io_ops     *pops)
  {
    //当需要进行简单数据的读取时,采用以下操作
    pops->_read8 = &usb_read8;
    pops->_read16 = &usb_read16;
    pops->_read32 = &usb_read32;

    //当需要进行批量数据的读取时,采用以下操作
    pops->_read_port = &usb_read_port;   

    //当需要进行简单数据的写时,采用以下操作
    pops->_write8 = &usb_write8;
    pops->_write16 = &usb_write16;
    pops->_write32 = &usb_write32;
    pops->_writeN = &usb_writeN;

    //当需要进行批量数据的写时,采用以下操作
    pops->_write_port = &usb_write_port;

    //取消读写urb
    pops->_read_port_cancel = &usb_read_port_cancel;
    pops->_write_port_cancel = &usb_write_port_cancel;
  }

  在进行批量数据的读写时,如usb_read_port()和usb_write_port()函数,需要完成urb创建、初始化、提交、完成处理这个完整的流程。伪代码如下:

  1)批量读操作

  static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
  {      
    int err;
    unsigned intpipe;
    PURB purb =NULL;
    structrecv_buf         *precvbuf = (structrecv_buf *)rmem;
    structusb_device    *pusbd = pdvobj->pusbdev;

    //创建urb,这里是在其它地方创建完成之后,传递过来
    purb =precvbuf->purb;

    //初始化批量urb
    usb_fill_bulk_urb(purb, pusbd, pipe,
      precvbuf->pbuf,
      MAX_RECVBUF_SZ,
      usb_read_port_complete,
      precvbuf);//contextis precvbuf

    //提交urb
    err =usb_submit_urb(purb, GFP_ATOMIC);

  }

  2)批量写操作

  u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)  
  {     
    unsigned int pipe;  
    intstatus;  
    PURB        purb = NULL;  

    structxmit_priv       *pxmitpriv =&padapter->xmitpriv;  
    structxmit_buf *pxmitbuf = (struct xmit_buf *)wmem;  
    structxmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data;  
    structusb_device *pusbd = pdvobj->pusbdev;  
    structpkt_attrib *pattrib = &pxmitframe->attrib;  

    //创建urb,这里是在其它地方创建完成之后,传递过来  
    purb = pxmitbuf->pxmit_urb[0];  

    //初始化批量urb  
    usb_fill_bulk_urb(purb, pusbd, pipe,  
      pxmitframe->buf_addr,//= pxmitbuf->pbuf  
      cnt,  
      usb_write_port_complete,  
      pxmitbuf);//contextis pxmitbuf  

    //提交urb  
    status = usb_submit_urb(purb,GFP_ATOMIC);  

    return ret;  

  }

  完成以上批量数据的读写操作之后,大家可能会疑问:这不是一般USB设备驱动的操作流程吗?貌似和wifi没有半毛钱的关系啊!从上面看,确实和wifi没有任何联系,但是以上只是一个铺垫。我们一直强调USB接口在wifi模块中充当什么角色,既然是接口,那么它就是为数据传输而生。所以,和wifi扯上关系的就在于usb_read_port()和usb_write_port()这两个函数。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表