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 = <ðernet_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
*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");
更多推荐
23_ZYNQ7020开发板_USB驱动
发布评论