23_ZYNQ7020开发板_USB驱动

usb是通用串行总线的总称。Linux支持几乎所有的usb设备和鼠标,键盘,打印机。
一、USB识别的过程,USB设备接入主机后,匹配过程如下;
usb设备接入主机后,匹配的过程如下
1)硬件检测
usb接口有四条线分别为5V、GND、D-、D+,usb设备接入主机后,会把主机usb接口的D-或D+拉高。从而主机从硬件的角度检测到了usb设备的接入。
2)握手匹配
主机检测到usb设备接入后,就会和设备进行交互,主机端主动发起获取设备信息的描述符,设备则需要按照固定格式返回描述符。如果实在windos桌面系统下,此时我们就能看到xxx设备接入的弹框
3)分配地址
一个主机上可以接入多个usb设备,为了区分这些设备,在握手成功后,主机会给设备分配设备地址,主机发出的命令中都会包办地址信息。
二、USB传输
usb的传输时主从结构,主就是主机,从就是设备。所有的传输都是由主机发起的。设备没有主动通知能力。我们常说的输入输出都是从主机的角度描述的,键盘,鼠标,显示器等。
USB 的三种传输模式
1)控制传输
USB设备连接主机,主机发送控制命令对设备进行配置。同时需要通过控制传输获取usb设备的描述符对设备进行识别。
2)批量传输
批量传输一般用于数据量大单对时间要求不高的场所,比如U盘,一点硬盘。可靠,但是不保证时效性。
3)中断传输
中断传输用于数据量小,不连续实时性高德场所。比如鼠标、键盘等。
4)等时传输
等时传输一般用于数据量大,连续且实时要求高德场合,但可靠性难以保证。一般用于摄像头,话筒等。
三、总线驱动
在这里插入图片描述
总线驱动需要做的事
1)识别usb设备
2)查找并安装相应的设备驱动
3)为设备驱动提供函数
四、写一个usb鼠标点击动作捕捉实验,点击左键控制台输出1,右键控制台输出0
原理图:
在这里插入图片描述
设备树
在这里插入图片描述

/include/ "system-conf.dtsi"
/ {
    model = "Zynq ALINX Development Board";
    compatible = "alinx,zynq", "xlnx,zynq-7000";

    aliases {
        ethernet0 = "&gem0";
        serial0 = "&uart1";
    };

    usb_phy0: usb_phy@0 {
        compatible = "ulpi-phy";
        #phy-cells = <0>;
        reg = <0xe0002000 0x1000>;
        view-port = <0x0170>;
        drv-vbus;
    };
    
    amba {
        slcr@f8000000 {
            pinctrl@700 {
                pinctrl_led_default: led-default {  
                    mux {  
                        groups = "gpio0_0_grp";  
                        function = "gpio0";  
                    };  

                    conf {  
                        pins = "MIO0"; 
                        io-standard = <1>; 
                        bias-disable;  
                        slew-rate = <0>;  
                    };      
                }; 
                pinctrl_key_default: key-default {
                    mux {
                        groups = "gpio0_50_grp";
                        function = "gpio0";
                    };

                    conf {
                        pins = "MIO50";
                        io-standard = <1>;
                        bias-high-impedance;
                        slew-rate = <0>;
                    };
                };
            };
        };
    };

    alinxled {
        compatible = "alinx-led";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_led_default>;
        alinxled-gpios = <&gpio0 0 0>;
    };

    alinxkey {
        compatible = "alinx-key";
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_key_default>;
        alinxkey-gpios = <&gpio0 50 0>;
    };
};

&i2c0 {
    clock-frequency = <100000>;
};

&usb0 {
    dr_mode = "host";
    usb-phy = <&usb_phy0>;
};

&sdhci0 {
    u-boot,dm-pre-reloc;
};

&uart1 {
    u-boot,dm-pre-reloc;
};

&flash0 {
    compatible = "micron,m25p80", "w25q256", "spi-flash";
};

&gem0 {
    phy-handle = <&ethernet_phy>;
    ethernet_phy: ethernet-phy@1 {
        reg = <1>;
        device_type = "ethernet-phy";
    };
};

&amba_pl {
    hdmi_encoder_0:hdmi_encoder {
        compatible = "digilent,drm-encoder";
        digilent,edid-i2c = <&i2c0>;
    };

    xilinx_drm {
        compatible = "xlnx,drm";
        xlnx,vtc = <&v_tc_0>;
        xlnx,connector-type = "HDMIA";
        xlnx,encoder-slave = <&hdmi_encoder_0>;
        clocks = <&axi_dynclk_0>;
        dglnt,edid-i2c = <&i2c0>;
        planes {
            xlnx,pixel-format = "rgb888";
            plane0 {
                dmas = <&axi_vdma_0 0>;
                dma-names = "dma";
            };
        };
    };
};

&axi_dynclk_0 {
    compatible = "digilent,axi-dynclk";
    #clock-cells = <0>;
    clocks = <&clkc 15>;
};

&v_tc_0 {
    compatible = "xlnx,v-tc-5.01.a";
};

驱动程序
ax-usb-drv.c
在这里插入图片描述

/** ===================================================== **
 *Author : ALINX Electronic Technology (Shanghai) Co., Ltd.
 *Website: http://www.alinx.com
 *Address: Room 202, building 18, 
           No.518 xinbrick Road, 
           Songjiang District, Shanghai
 *Created: 2020-3-2 
 *Version: 1.0
 ** ===================================================== **/

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
#include <linux/hid.h>

/* 定义一个输入事件, 表示鼠标的点击事件 */
static struct input_dev *mouse_dev;
/* 定义缓冲区首地址 */
static char             *usb_buf;
/* dma缓冲区 */
static dma_addr_t       usb_buf_dma;
/* 缓冲区长度 */
static int              usb_buf_len;
/* 定义一个urb */
static struct urb       *mouse_urb;

static void ax_usb_irq(struct urb *urb)
{
    static unsigned char pre_sts;
    int i;

    /* 左键发生了变化 */
    if ((pre_sts & 0x01) != (usb_buf[0] & 0x01))
    {
        printk("lf click\n");
        input_event(mouse_dev, EV_KEY, KEY_L, (usb_buf[0] & 0x01) ? 1 : 0);
        input_sync(mouse_dev);
    }

    /* 右键发生了变化 */
    if ((pre_sts & 0x02) != (usb_buf[0] & 0x02))
    {
        printk("rt click\n");
        input_event(mouse_dev, EV_KEY, KEY_S, (usb_buf[0] & 0x02) ? 1 : 0);
        input_sync(mouse_dev);
    }
    
    /* 记录当前状态 */
    pre_sts = usb_buf[0];

    /* 重新提交urb */
    usb_submit_urb(mouse_urb, GFP_KERNEL);
}

static int ax_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
    /* 获取usb_device */
    struct usb_device *dev = interface_to_usbdev(intf);
    struct usb_host_interface *interface;
    struct usb_endpoint_descriptor *endpoint;
    int pipe;
        
    /* 获取端点 */
    interface = intf->cur_altsetting;
    endpoint = &interface->endpoint[0].desc;

    /* 分配input_dev */
    mouse_dev = input_allocate_device();
    /* 设置input_dev */
    set_bit(EV_KEY, mouse_dev->evbit);
    set_bit(EV_REP, mouse_dev->evbit);
    set_bit(KEY_L, mouse_dev->keybit);
    set_bit(KEY_S, mouse_dev->keybit);
    /* 注册input_dev */
    input_register_device(mouse_dev);
    
    /* 获取USB设备端点对应的管道 */
    pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);

    /* 获取端点最大长度作为缓冲区长度 */
    usb_buf_len = endpoint->wMaxPacketSize;

    /* 分配缓冲区 */
    usb_buf = usb_alloc_coherent(dev, usb_buf_len, GFP_ATOMIC, &usb_buf_dma);

    /* 创建urb */
    mouse_urb = usb_alloc_urb(0, GFP_KERNEL);
    
    /* 分配urb" */
    usb_fill_int_urb(mouse_urb, dev, pipe, usb_buf, usb_buf_len, ax_usb_irq, NULL, endpoint->bInterval);
    mouse_urb->transfer_dma = usb_buf_dma;
    mouse_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

    /* 提交urb */
    usb_submit_urb(mouse_urb, GFP_KERNEL);
    
    return 0;
}

static void ax_usb_disconnect(struct usb_interface *intf)
{
    struct usb_device *dev = interface_to_usbdev(intf);

    /* 主动结束urb */
    usb_kill_urb(mouse_urb);
    /* 释放urb */
    usb_free_urb(mouse_urb);
    /* 释放缓冲区 */
    usb_free_coherent(dev, usb_buf_len, usb_buf, &usb_buf_dma);
    /* 注销输入事件 */
    input_unregister_device(mouse_dev);
    /* 释放输入事件 */
    input_free_device(mouse_dev);
}

/* 定义初始化id_table */
static struct usb_device_id ax_usb_id_table [] = {
    /* 鼠标mouse接口描述符里类是HID类,子类boot,协议mouse */
    { 
        USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, 
                           USB_INTERFACE_SUBCLASS_BOOT, 
                           USB_INTERFACE_PROTOCOL_MOUSE) 
    }, { }
};

/* 定义并初始化usb_driver */
static struct usb_driver ax_usb_driver = {
    .name       = "ax_usb_test",
    .probe      = ax_usb_probe,
    .disconnect = ax_usb_disconnect,
    .id_table   = ax_usb_id_table,
};

/* 驱动入口函数 */
static int ax_usb_init(void)
{
    /* 注册usb_driver */
    return usb_register(&ax_usb_driver);
}

/* 驱动出口函数 */
static void ax_usb_exit(void)
{
    /* 注销usb_driver */
    usb_deregister(&ax_usb_driver);    
}

/* 标记加载、卸载函数 */ 
module_init(ax_usb_init);
module_exit(ax_usb_exit);

/* 驱动描述信息 */  
MODULE_AUTHOR("Alinx");  
MODULE_ALIAS("pwm_led");  
MODULE_DESCRIPTION("USB TEST driver");  
MODULE_VERSION("v1.0");  
MODULE_LICENSE("GPL"); 



在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值