USB(universal serial bus)总线:通用串行总线,是1种外部总线标准,用于规范电脑与外部装备的连接和通讯。
USB1.0:1.5MB/S
USB1.1(full speed):12MB/S
USB2.0(high speed):480MB/S
USB3.0(supper sped):4800MB/S
USB硬件结构(4线):电源(5V,500mA),地线,D+,D-
工作原理:
USB端口的D+、D-数据线上有15K左右的“高值”下拉电阻,从而使USB的数据线悬空电平为低。USB装备的D+(高速High Speed或全速Full Speed)或D-(低速Low Speed)上具有1.5K左右的“低值”上拉电阻,而USB端口的VCC和GND引出线擅长数据线,这保证了USB装备先上电后挂线,如此上拉电阻能可靠地将USB端口的相应数据线拉高,这样便可辨别USB装备的接入及其速度了。通过改变D+和D- 两根数据线之间的电压差来表示0/1;
拓普结构:
对每一个USB系统来讲,都有1个称为主机控制器的装备,该控制器和1个根Hub作为
1个整体。这个根Hub下可以接多级的Hub,每一个子Hub又可以接子Hub。每一个USB装备
作为1个节点接在不同级别的Hub上。 每条USB总线上最多可以接127个装备。
常见的USB主控制器规格有:
OHCI(Open HCI
开放主机接口):主要是非PC系统上的USB芯片
UHCI:大多是Intel和Via主板上的USB控制器芯片。他们都是由USB1.1规格的。
EHCI(Enhanced Host Connective Interface
增强主机控制器接口):由Intel等几个厂商研发,兼容OHCI,UHCI
,遵守USB2.0规范
USB OTG(on the go)控制器:这类控制器在嵌入式微控制器领域备受欢迎,采取otg 控制器,每一个通讯终端能充当DRD(Dual-Role Device,两重角色装备)。用HNP(Host Negotiation Protocol,主机沟通协议)初始化装备连接后,这样的装备可以根据功能需要在主机模式和装备模式之间任意切换。
HCD主控制器驱动:Host Control Driver
USB装备逻辑结构
在USB装备的逻辑组织中,包括装备、配置、接口和端点4个层次。装备通常有1个或多个配置,配置通常有1个或多个接口,接口有零或多个端点(端点可以比喻成寄存器)。
USB装备中的唯1可寻址的部份是装备端点,端点的作用类似于寄存器。每一个端点在装备内部有唯1的端点号,这个端点号是在装备设计时给定的。主机和装备的通讯终究都作用于装备上的各个端点。每一个端点所支持的操作都是单向的,要末只读,要末只写。
主性能自动装备USB装备的缘由:
在每个USB装备内部,包括了固定格式的数据,通过这些数据,USB主机就能够获得USB装备的类型、生产厂商等信息。这些固定格式的数据,我们就称之为USB描写符。标准的USB装备有5种USB描写符:装备描写符,配置描写符,接口描写符,端点描写符,字符串描写符。
格式查看:《USB specification :Table⑼.8》
装备描写符:1个USB装备只有1个装备描写符,装备描写符长度为18个字节。
配置描写符:
接口描写符:
端点描写符
USB数据通讯:
USB的数据通讯首先是基于传输(Transfer)的,传输的类型有:中断传输、批量传输、同步传输、控制传输
1次传输由1个或多个事务(transaction)构成,事务可分为:In事务,Out事务,Setup事务
1个事务由1个或多个包(packet)构成,包可分为:令牌包(setup)、数据包(data)、握手包(ACK)和特殊包
1个包由多个域构成,域可分为:同步域(SYNC),标识域(PID),地址域(ADDR),端点域(ENDP),帧号域(FRAM),数据域(DATA),校验域(CRC)
USB枚举:
USB装备在正常工作之前, 第1件要做的事就是枚举。枚举是让主机认得这个USB装备, 并且为该装备准备资源,建立好主机和装备之间的数据传递通道。
USB 寻址
USB装备里的每一个寻址单元称作 端点。每一个端点分配的地址称作端点地址。每一个端点地址都有与之相干的传输模式。如果1个端点的数据传输模式时批量传输模式,该端点叫做批量端点。地址为0的端点专门用来配置装备。控制管道和它相连,完成装备枚举进程.
USB装备地址和I2C1样,其实不占用CPU可寻址的空间,它们的地址空间是私有的,一样采取主从结构..
开发板作为主机,挂载U盘
开发板作为从装备,PC机为主机
URB(USB Request Block,USB要求块)通讯模型:USB数据传输机制使用的核心数据结构
#include<linux/init.h>
#include<linux/module.h>
#include<linux/types.h>
#include<linux/errno.h>
#include <linux/usb.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/mm.h>
#define USB_VID_TQ210 0x04e8
#define USB_PID_TQ210 0X1234
#define DES_BUF_SIZE 512
unsigned char bulk_out_endaddr; /*目标端点地址*/
char *des_buffer;
struct usb_device *usb_dev; /*指向USB装备*/
/***********************************
当USB核心检测到某个装备的属性和某个驱动程序
的ID匹配时(既枚举进程完成),
这个驱动程序的prob函数就被khubd履行。
查看从装备时先让从装备进入下载状态,在PC终端
使用 lsusb 查看
***********************************/
static struct usb_device_id dnw_table [] = {
{ USB_DEVICE(USB_VID_TQ210, USB_PID_TQ210) },
{ },
};
/***********************************
文件操作:
************************************/
static int dnw_open(struct inode *inode, struct file *file)
{
/*分配内核空间*/
des_buffer = kmalloc(DES_BUF_SIZE,GFP_KERNEL);
return 0;
}
static ssize_t dnw_write(struct file *file, const __user char *buffer,
size_t count, loff_t *ppos)
{
size_t toWrite=0,totalshift=0;
int actual_length;
unsigned long ret = 0;
while(count > 0)
{
/*获得用户传输下来的数据*/
/*获得较小值*/
toWrite = min(count,(size_t)DES_BUF_SIZE);
ret = copy_from_user(des_buffer,buffer+totalshift,toWrite);
/*将数据提交给USB主控制器*/
/*
usb_dev:指向需要操作的usb装备
管道操作:
usb_sndbulkpipe(usb_dev,bulk_out_endaddr):建立usb装备与端点的批量传输管道
1)管道包括:端点地址
数据传输方向(IN/OUT)
数据传输模式:控制,中断,批量,等时
1)函数格式:usb_[rcv|snd][ctrl|int|bulk|isoc]pipe
actual_length:实际传输的字节数寄存在这里
3*HZ:等待超时
*/
usb_bulk_msg(usb_dev,usb_sndbulkpipe(usb_dev,bulk_out_endaddr),des_buffer,toWrite,&actual_length,3*HZ);
count -= toWrite;
totalshift+=toWrite;
}
return 0;
}
static int dnw_release(struct inode *inode, struct file *file)
{
kfree(des_buffer);
return 0;
}
/* file operations needed when we register this driver */
static const struct file_operations dnw_fops = {
.owner = THIS_MODULE,
.write = dnw_write,
.open = dnw_open,
.release = dnw_release,
};
struct usb_class_driver dnw_class = {
.name = "dnw%d",
.fops = &dnw_fops,
.minor_base = 100,
};
/****************************************************************************
装备捕获函数需要做的工作分析:
1、USB是围绕URB数据传输机制展开的,所以开始应当初始化URB,URB使用步骤:
1)分配内存:usb_alloc_urb():这个和网络装备差不多
2)初始化:usb_fill_[control|int|bulk]_urb
3)异步提交:usb_sumit_urb():这项工作在读写操作函数中进行
2、同步提交URB接口函数:既使用1下函数就可以完成1中3步的工作,这个函数合适在读写操作中进行
1)usb_[control|int|bulk]_msg()
3、批量传输属于字符装备操作,既要初始化字符操作函数集
1)usb_register_dev():该函数能将字符装备和USB总线关联在1起
综合以上分析:
prob只需做的就是第3步;关联字符装备
其他地方需要用到那种数据结构在来这里初始化就行了
****************************************************************************/
static int dnw_probe(struct usb_interface *intf,const struct usb_device_id *id)
{
int ret = -ENOMEM;
int i=0;
printk("Device prob!\n");
/* 接口设置描写 ,主机对每一个接口的描写*/
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
/*获得USB装备,在初始化URB中使用*/
usb_dev = usb_get_dev(interface_to_usbdev(intf));
/*获得接口*/
interface = intf->cur_altsetting;
/*获得目标端点*/
for(i=0;i<interface->desc.bNumEndpoints;i++)
{
endpoint = &interface->endpoint[i].desc;
if(usb_endpoint_is_bulk_out(endpoint))
{
bulk_out_endaddr = endpoint->bEndpointAddress;
break;
}
}
/*把字符装备和usb装备关联起来*/
if((ret = usb_register_dev(intf,&dnw_class)) < 0)
{
printk("usb_register_dev err!\n");
}
return ret;
}
void dnw_disconnect (struct usb_interface *intf)
{
usb_deregister_dev(intf,&dnw_class);
}
static struct usb_driver dnw_driver = {
.name = "dnw",
.probe = dnw_probe,
.disconnect = dnw_disconnect,
.id_table = dnw_table,
};
/***********************************
USB 一样是1种总线协议,所以初始化1般是向
其总线注册
************************************/
static int dnw_init(void)
{
/*1、向usb核心注册USB装备*/
int result;
if ((result = usb_register(&dnw_driver))) {
err("usb_register failed. Error number %d",result);
return result;
}
return 0;
}
static void dnw_exit(void)
{
/* deregister this driver from the USB subsystem */
usb_deregister(&dnw_driver);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Hntea");
module_init(dnw_init);
module_exit(dnw_exit);
下一篇 CORS解决ajax跨域问题