USB(universal serial bus)總線:通用串行總線,是一種外部總線標准,用於規范電腦與外部設備的連接和通訊。
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系統來說,都有一個稱為主機控制器的設備,該控制器和一個根Hub作為
一個整體。這個根Hub下可以接多級的Hub,每個子Hub又可以接子Hub。每個USB設備
作為一個節點接在不同級別的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個層次。設備通常有一個或多個配置,配置通常有一個或多個接口,接口有零或多個端點(端點可以比喻成寄存器)。
USB設備中的唯一可尋址的部分是設備端點,端點的作用類似於寄存器。每個端點在設備內部有唯一的端點號,這個端點號是在設備設計時給定的。主機和設備的通信最終都作用於設備上的各個端點。每個端點所支持的操作都是單向的,要麼只讀,要麼只寫。
主機能自動設備USB設備的原因:
在每一個USB設備內部,包含了固定格式的數據,通過這些數據,USB主機就可以獲取USB設備的類型、生產廠商等信息。這些固定格式的數據,我們就稱之為USB描述符。標准的USB設備有5種USB描述符:設備描述符,配置描述符,接口描述符,端點描述符,字符串描述符。
格式查看:《USB specification :Table-9.8》
設備描述符:一個USB設備只有一個設備描述符,設備描述符長度為18個字節。
配置描述符:
接口描述符:
端點描述符
USB數據通訊:
USB的數據通訊首先是基於傳輸(Transfer)的,傳輸的類型有:中斷傳輸、批量傳輸、同步傳輸、控制傳輸
一次傳輸由一個或多個事務(transaction)構成,事務可分為:In事務,Out事務,Setup事務
一個事務由一個或多個包(packet)構成,包可分為:令牌包(setup)、數據包(data)、握手包(ACK)和特殊包
一個包由多個域構成,域可分為:同步域(SYNC),標識域(PID),地址域(ADDR),端點域(ENDP),幀號域(FRAM),數據域(DATA),校驗域(CRC)
USB枚舉:
USB設備在正常工作以前, 第一件要做的事就是枚舉。枚舉是讓主機認得這個USB設備, 並且為該設備准備資源,建立好主機和設備之間的數據傳遞通道。
USB 尋址
USB設備裡的每個尋址單元稱作端點。每個端點分配的地址稱作端點地址。每個端點地址都有與之相關的傳輸模式。如果一個端點的數據傳輸模式時批量傳輸模式,該端點叫做批量端點。地址為0的端點專門用來配置設備。控制管道和它相連,完成設備枚舉過程.
USB設備地址和I2C一樣,並不占用CPU可尋址的空間,它們的地址空間是私有的,同樣采用主從結構..
開發板作為主機,掛載U盤
開發板作為從設備,PC機為主機
URB(USB Request Block,USB請求塊)通訊模型:USB數據傳輸機制使用的核心數據結構
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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)usb_[control|int|bulk]_msg()
3、批量傳輸屬於字符設備操作,既要初始化字符操作函數集
1)usb_register_dev():該函數能將字符設備和USB總線關聯在一起
綜合以上分析:
prob只需做的就是第三步;關聯字符設備
其他地方需要用到那種數據結構在來這裡初始化就好了
****************************************************************************/
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
{
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 同樣是一種總線協議,所以初始化一般是向
其總線注冊
************************************/
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);