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跨域問題