USB驱动详解

http://www.deansys.com/doc/ldd3/ch13.html

https://www.cnblogs.com/tureno/articles/6811367.html 

3.1:URB的相关接口

1:URB的创建

URB的创建是由usb_alloc_urb()完成的.这个函数会完成URB内存的分配和基本成员的初始化工作.代码如下:

struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)

{

   struct urb *urb;

 

    urb = kmalloc(sizeof(struct urb) +

        iso_packets * sizeof(struct usb_iso_packet_descriptor),

        mem_flags);

    if (!urb) {

        err("alloc_urb: kmalloc failed");

        return NULL;

    }

    usb_init_urb(urb);

    return urb;

}

这个函数有两个参数,一个是iso_packets.仅仅用于ISO传输.表示ISO数据包个数,如果用于其它类型的传输,此参数为0.另一个是mem_flags.是分配内存的参数.

Usb_init_urb()如下:

void usb_init_urb(struct urb *urb)

{

    if (urb) {

        memset(urb, 0, sizeof(*urb));

        kref_init(&urb->kref);

        INIT_LIST_HEAD(&urb->anchor_list);

    }

}

由此可以看到,它的初始化只是初始化了引用计数和ahchor_list链表.这个链表在URB被锁定的时候会用到.

 

2:URB的初始化

USB2.0 spec中定义了四种传输,为别为ISO,INTER,BULK,CONTORL.linux kernel为INTER,BULK,CONTORL的URB初始化提供了一些API,ISO的传输只能够手动去初始化.这些API如下:

static inline void usb_fill_control_urb(struct urb *urb,

                    struct usb_device *dev,

                    unsigned int pipe,

                    unsigned char *setup_packet,

                    void *transfer_buffer,

                    int buffer_length,

                    usb_complete_t complete_fn,

                    void *context)

static inline void usb_fill_bulk_urb(struct urb *urb,

                     struct usb_device *dev,

                     unsigned int pipe,

                     void *transfer_buffer,

                     int buffer_length,

                     usb_complete_t complete_fn,

                     void *context)

static inline void usb_fill_int_urb(struct urb *urb,

                    struct usb_device *dev,

                    unsigned int pipe,

                    void *transfer_buffer,

                    int buffer_length,

                    usb_complete_t complete_fn,

                    void *context,

                    int interval)

分别用来填充CONTORL,BULK,INT类型的URB.

观察他们的函数原型,发现有很多相的的参数.先对这些参数做一下解释:

Urb:是要初始化的urb

Dev:表示消息要被发送到的USB设备

Pipe:表示消息被发送到的端点

transfer_buffer:表示发送数据的缓冲区

length:就是transfer_buffer所表示的缓冲区大小

context:完成处理函数的上下文

complete_fn:传输完了之后要调用的函数.

usb_fill_control_urb()的setup_packet:即将被发送到端点的设备数据包

usb_fill_int_urb()中的interval:这个urb应该被调度的间隔.

函数的实际都是差不多的.以usb_fill_control_urb()为例:

static inline void usb_fill_control_urb(struct urb *urb,

                    struct usb_device *dev,

                    unsigned int pipe,

                    unsigned char *setup_packet,

                    void *transfer_buffer,

                    int buffer_length,

                    usb_complete_t complete_fn,

                    void *context)

{

    urb->dev = dev;

    urb->pipe = pipe;

    urb->setup_packet = setup_packet;

    urb->transfer_buffer = transfer_buffer;

    urb->transfer_buffer_length = buffer_length;

    urb->complete = complete_fn;

    urb->context = context;

}

如上所示,只是将函数的参数赋值给了URB相关的成员而已.

另外,关于ISO的URB初始化虽然没有可以调用的API,但它的初始化也很简单,对应就是填充几个成员而已.

另外,对于pipe的参数.有一系列辅助的宏.如下示:

/* Create various pipes... */

#define usb_sndctrlpipe(dev,endpoint)   \

    ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint))

#define usb_rcvctrlpipe(dev,endpoint)   \

    ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)

#define usb_sndisocpipe(dev,endpoint)   \

    ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint))

#define usb_rcvisocpipe(dev,endpoint)   \

    ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)

#define usb_sndbulkpipe(dev,endpoint)   \

    ((PIPE_BULK << 30) | __create_pipe(dev, endpoint))

#define usb_rcvbulkpipe(dev,endpoint)   \

    ((PIPE_BULK << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)

#define usb_sndintpipe(dev,endpoint)    \

    ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint))

#define usb_rcvintpipe(dev,endpoint)    \

    ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)

这个宏都是根据usb2.0 spec的规范来设计的.

 

3:提交URB

提交urb的接口是usb_submit_urb().代码如下:

int usb_submit_urb(struct urb *urb, gfp_t mem_flags)

{

    int             xfertype, max;

    struct usb_device       *dev;

    struct usb_host_endpoint    *ep;

    int             is_out;

 

    if (!urb || urb->hcpriv || !urb->complete)

        return -EINVAL;

    dev = urb->dev;

    if ((!dev) || (dev->state < USB_STATE_DEFAULT))

        return -ENODEV;

 

    /* For now, get the endpoint from the pipe.  Eventually drivers

     * will be required to set urb->ep directly and we will eliminate

     * urb->pipe.

     */

 

    //取得要传输的端口.对端地址是由方向+dev address+port number组成的

    ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)

            [usb_pipeendpoint(urb->pipe)];

    if (!ep)

        return -ENOENT;

 

    urb->ep = ep;

    urb->status = -EINPROGRESS;

    urb->actual_length = 0;

 

    /* Lots of sanity checks, so HCDs can rely on clean data

     * and don't need to duplicate tests

     */

     //取得ep的传输类型

    xfertype = usb_endpoint_type(&ep->desc);

    //如果是控制传输.端点0默认是控制传输

    if (xfertype == USB_ENDPOINT_XFER_CONTROL) {

        //控制传输的urb如果没有setup_packet是非法的

        struct usb_ctrlrequest *setup =

                (struct usb_ctrlrequest *) urb->setup_packet;

 

        if (!setup)

            return -ENOEXEC;

        //判断是否是out方向的传输

        is_out = !(setup->bRequestType & USB_DIR_IN) ||

                !setup->wLength;

    } else {

        //如果不是控制传输,在端点描述符的bEndportAddress的bit7 包含有端点的传输方向

        is_out = usb_endpoint_dir_out(&ep->desc);

    }

 

    /* Cache the direction for later use */

    //根据传输方向.置urb->transfer_flags的方向位

    urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) |

            (is_out ? URB_DIR_OUT : URB_DIR_IN);

 

    //根据usb2.0 spec.除控制传输外的其它传输只有在config状态的时候才能进行

    if (xfertype != USB_ENDPOINT_XFER_CONTROL &&

            dev->state < USB_STATE_CONFIGURED)

        return -ENODEV;

 

    //传送/接收的最大字节.如果这个最大巧若拙字节还要小于0,那就是非法的

    max = le16_to_cpu(ep->desc.wMaxPacketSize);

    if (max <= 0) {

        dev_dbg(&dev->dev,

            "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",

            usb_endpoint_num(&ep->desc), is_out ? "out" : "in",

            __FUNCTION__, max);

        return -EMSGSIZE;

    }

 

    /* periodic transfers limit size per frame/uframe,

     * but drivers only control those sizes for ISO.

     * while we're checking, initialize return status.

     */

     //如果是实时传输

    if (xfertype == USB_ENDPOINT_XFER_ISOC) {

        int n, len;

 

        /* "high bandwidth" mode, 1-3 packets/uframe? */

        //如果是高速传输.则要修正它的MAX值

        //高速传输时, 一个微帧内可以修输多个数据.bit 11~bit12用来表示一个微帧内

        //传输包的个数.

        //在USB1.1中是不支持HIGH的

        if (dev->speed == USB_SPEED_HIGH) {

            int mult = 1 + ((max >> 11) & 0x03);

            max &= 0x07ff;

            max *= mult;

        }

 

        //实现传输的数据包数目不能小于等于0

        if (urb->number_of_packets <= 0)

            return -EINVAL;

        //urb->number_of_packets: 实时数据包个数.每个实时数据包对应urb->iso_frame_desc[]中的一项

        for (n = 0; n < urb->number_of_packets; n++) {

            len = urb->iso_frame_desc[n].length;

            if (len < 0 || len > max)

                return -EMSGSIZE;

            urb->iso_frame_desc[n].status = -EXDEV;

            urb->iso_frame_desc[n].actual_length = 0;

        }

    }

 

    /* the I/O buffer must be mapped/unmapped, except when length=0 */

    //如果要传输的缓存区大小小于0.非法

    if (urb->transfer_buffer_length < 0)

        return -EMSGSIZE;

 

#ifdef DEBUG

    /* stuff that drivers shouldn't do, but which shouldn't

     * cause problems in HCDs if they get it wrong.

     */

    {

    unsigned int    orig_flags = urb->transfer_flags;

    unsigned int    allowed;

 

    /* enforce simple/standard policy */

    allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |

            URB_NO_INTERRUPT | URB_DIR_MASK | URB_FREE_BUFFER);

    switch (xfertype) {

    case USB_ENDPOINT_XFER_BULK:

        if (is_out)

            allowed |= URB_ZERO_PACKET;

        /* FALLTHROUGH */

    case USB_ENDPOINT_XFER_CONTROL:

        allowed |= URB_NO_FSBR; /* only affects UHCI */

        /* FALLTHROUGH */

    default:            /* all non-iso endpoints */

        if (!is_out)

            allowed |= URB_SHORT_NOT_OK;

        break;

    case USB_ENDPOINT_XFER_ISOC:

        allowed |= URB_ISO_ASAP;

        break;

    }

    urb->transfer_flags &= allowed;

 

    /* fail if submitter gave bogus flags */

    if (urb->transfer_flags != orig_flags) {

        err("BOGUS urb flags, %x --> %x",

            orig_flags, urb->transfer_flags);

        return -EINVAL;

    }

    }

#endif

    /*

     * Force periodic transfer intervals to be legal values that are

     * a power of two (so HCDs don't need to).

     *

     * FIXME want bus->{intr,iso}_sched_horizon values here.  Each HC

     * supports different values... this uses EHCI/UHCI defaults (and

     * EHCI can use smaller non-default values).

     */

 

//关于实时传输和中断传输的interval处理

    switch (xfertype) {

    case USB_ENDPOINT_XFER_ISOC:

    case USB_ENDPOINT_XFER_INT:

        /* too small? */

        //interval不能小于或等于0

        if (urb->interval <= 0)

            return -EINVAL;

        /* too big? */

        switch (dev->speed) {

        case USB_SPEED_HIGH:    /* units are microframes */

            /* NOTE usb handles 2^15 */

            if (urb->interval > (1024 * 8))

                urb->interval = 1024 * 8;

            max = 1024 * 8;

            break;

        case USB_SPEED_FULL:    /* units are frames/msec */

        case USB_SPEED_LOW:

            if (xfertype == USB_ENDPOINT_XFER_INT) {

                if (urb->interval > 255)

                    return -EINVAL;

                /* NOTE ohci only handles up to 32 */

                max = 128;

            } else {

                if (urb->interval > 1024)

                    urb->interval = 1024;

                /* NOTE usb and ohci handle up to 2^15 */

                max = 1024;

            }

            break;

        default:

            return -EINVAL;

        }

        /* Round down to a power of 2, no more than max */

        urb->interval = min(max, 1 << ilog2(urb->interval));

    }

 

    return usb_hcd_submit_urb(urb, mem_flags);

}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
USB转网口驱动是一种用于将USB接口转换为网口的驱动程序。它可以使得计算机通过USB接口连接到以太网,实现网络通信功能。 USB转网口驱动详解如下: 首先,USB转网口驱动需要通过软件程序来实现系统对USB转网口设备的识别和控制。这些软件程序通常由设备制造商提供,需要在计算机上安装和配置。安装驱动程序后,计算机操作系统能够识别并与USB转网口设备进行通信。 其次,USB转网口驱动通过将USB接口转换为以太网接口,使得计算机可以连接到局域网或互联网。通过该驱动,计算机可以使用以太网协议进行数据传输,实现与其他计算机或网络设备的通信。 此外,USB转网口驱动还支持常见的网络协议,如TCP/IP协议。它能够实现计算机的IP地址分配、数据包的封装与解封装等功能,使得计算机可以正常地进行网络通信。 最后,USB转网口驱动还具备一些特殊功能,如QoS(Quality of Service)和流量控制等。QoS功能可以根据不同应用程序或数据流的特点,对网络资源进行优先级分配,提高网络传输效率。而流量控制功能可以限制数据传输速率,避免网络拥塞和数据丢失。 总结起来,USB转网口驱动是一种重要的软件程序,它将USB接口转换为以太网接口,实现计算机的网络通信功能。通过安装和配置驱动程序,计算机能够识别USB转网口设备,并与其他计算机或网络设备进行正常的通信。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值