国产毛片a精品毛-国产毛片黄片-国产毛片久久国产-国产毛片久久精品-青娱乐极品在线-青娱乐精品

嵌入式Linux下USB驅動程序的設計

發(fā)布時間:2010-8-16 15:54    發(fā)布者:lavida
關鍵詞: linux , USB , 嵌入式 , 驅動程序
一、引言  

USB(Universal Serial Bus)即通用串行總線,是一種全新的雙向同步傳輸?shù)闹С譄岵灏蔚臄?shù)據(jù)傳輸總線,其目的是為了提供一種兼容不同速度的、可擴充的并且使用方便的外圍設備接口,同時也是為了解決計算機接口的太多的弊端而設計的。一個USB系統(tǒng)主要有三部分組成:USB互連、USB主機、USB設備三部分組成的,其結構如圖1所示。在編寫USB設備驅動程序設計時,可以分為三部分編寫:主機端設備驅動程序、主機控制器驅動程序設計和設備端驅動程序三部分,在本文中重點介紹主機端驅動程序的設計。  

二、USB設備驅動程序的設計  

USB設備驅動程序的設計包括主機端設備驅動程序設計、主機控制器驅動程序設計和設備端驅動程序設計三部分組成。主機端設備驅動程序就是通常說的設備驅動程序,它是主機環(huán)境中為用戶應用程序提供一個訪問USB外設的接口。Linux為這部分驅動程序提供編程接口,驅動程序設計者只要按照需求編寫驅動程序框架,通過調用操作系統(tǒng)提供的API接口函數(shù)可以完成對USB外設的特定訪問。  

主機控制驅動主要是對USB主機控制器的驅動,在大多數(shù)PC環(huán)境下,主機控制器都是由操作系統(tǒng)提供。嵌入式設備一般都沒有USB主機控制器,只是工作在Slave模式下。如果要使USB具有主機功能,那么設備中需要選用一個帶主機控制器的USB接口控制芯片, 同時自己還要有實現(xiàn)該主機控制器的驅動程序。目前Linux內核中只提供USB主機控制器的開放主機控制器和通用主機控制器接口兩種規(guī)格,而這兩種規(guī)格主要用在PC架構中。USB主機端驅動程序與主機控制器的結構如圖2所示。其中USB核是Linux的一個子模塊,集中定義了一組USB相關的數(shù)據(jù)結構、宏以及API函數(shù)。  

USB設備驅動程序是常說的設備固件程序的一部分,提供設備信息與主機的通信接口。設備端USB驅動程序設計由以下幾部分處理程序組成。初始化例程:完成描述符指針、端點、配置改變等操作。數(shù)據(jù)傳輸例程:完成控制傳輸、批量傳輸、中斷傳輸及同步傳輸?shù)葌鬏敺绞较碌臄?shù)據(jù)收發(fā)工作。標準設備處理請求:處理標準設備請求。廠商請求處理:處理生產(chǎn)商指定請求。其他操作:處理主機發(fā)出的端口復位、配置改變等操作。  

1.USB設備驅動程序框架  

USB驅動程序首先要向Linux內核注冊自己,并告訴系統(tǒng)它所支持的設備類型以及它所支持的操作。這些信息通過一個usb_driver結構來傳遞。usb_driver結構如下:  

static struct usb_driver skel_driver = {  

name: "skeleton";/*驅動程序的名稱*/  

probe: skel_probe; /*設備列舉時被調用*/  

disconnect: skel_disconnect; /*設備被卸載時被調用*/  

fops: &skel_fops; /*指向一個file_operation結構,內核通過它來訪問驅動程序的文件操作函數(shù),與用戶程序的read、write等操作進行交互*/  

minor USB_SKEL_MINOR_BASE; /*指向設備的次設備號,用于系統(tǒng)識別主設備號相同的設備(即一個驅動程序可以同時支持多個USB設備*/  

id_table: skel_table; /*保存設備的廠商ID和產(chǎn)品ID,作為該設備的唯一標識,驅動程序向系統(tǒng)注冊后,當下次插入時,系統(tǒng)根據(jù)這個標識查找正確的驅動程序,實現(xiàn)設備的即插即用*/  

};  

static struct file_operation skel_fops={  

{  

owner:THIS_module,  

read:skel_read,  

write:skel_write,  

ioctl:skel_ioctl,  

open:skel_open,  

release:skel_release,  

};  

(1)注冊和注銷  

USB驅動程序注冊,就是把在初始化函數(shù)中填好的use_driver結構作為參數(shù)傳遞給  

use_register()函數(shù)即可,函數(shù)的調用方法為:  

result=usb_register(&skel_driver);  

當要從系統(tǒng)卸載驅動程序時,也是將use_driver結構作為參數(shù)傳遞給usb_deregister 函數(shù)處理。 函數(shù)的調用格式為:  

static void __exit usb_skel_exit(void)  

{ /* deregister this driver with the USB subsystem */  

usb_deregister(&skel_driver);  

}  

module_exit(usb_skel_exit);  

當USB設備插入時,為了使linux-hotplug(Linux中PCI、USB等設備熱插拔支持)系統(tǒng)自動裝載驅動程序,需要創(chuàng)建一個MODULE_device_TABLE。核心代碼如下(這個模塊僅支持某一特定設備):  

/* table of Devices that work with this driver */  

static struct usb_device_id skel_table [] = {  

{ USB_DEVICE(USB_SKEL_VENDOR_ID,  

USB_SKEL_Product_ID) },  

{ } /* Terminating entry */  

};  

MODULE_DEVICE_TABLE (usb, skel_table);  

USB_DEVICE宏利用廠商ID和產(chǎn)品ID提供了一個設備的唯一標識。當系統(tǒng)插入一個ID匹配的USB設備到USB總線時,驅動會在USB core中注冊,驅動程序中probe 函數(shù)也就會被調用。usb_device 結構指針、接口號和接口ID都會被傳遞到函數(shù)中。  

(2)probe()函數(shù)  

probe()函數(shù)的編寫格式為:static void * skel_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id);驅動程序需要確認插入的設備是否可以被接受,如果不接受,或者在初始化的過程中發(fā)生任何錯誤,probe()函數(shù)返回一個NULL值。否則返回一個含有設備驅動程序狀態(tài)的指針,通過這個指針,就可以訪問所有結構中的回調函數(shù)。  

在驅動程序里,最后一點是要注冊devfs(設備文件系統(tǒng))。首先創(chuàng)建一個緩沖用來保存那些被發(fā)送給USB設備的數(shù)據(jù)和那些從設備上接受的數(shù)據(jù),并為設備傳輸創(chuàng)建一個USB請求塊(URB)以向設備寫入數(shù)據(jù),同時USB urb 被初始化,然后在devfs子系統(tǒng)中注冊設備,允許devfs用戶訪問USB的設備。注冊過程如下:  

/* initialize the devfs node for this device and register it */  

sprintf(name, "skel%d", skel->minor);  

skel->devfs = devfs_register (usb_devfs_handle, name, DEVFS_FL_DEFAULT, USB_MAJOR, USB_SKEL_MINOR_BASE + skel->minor, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, &skel_fops, NULL);  

如果devfs_register函數(shù)失敗, devfs子系統(tǒng)會將此情況報告給用戶。如果設備從USB總線拔掉,設備指針會調用disconnect 函數(shù)。驅動程序就需要清除那些被分配了的所有私有數(shù)據(jù)、關閉urbs,并且從devfs上注銷調自己。調用函數(shù)的格式為:  

/* remove our devfs node */  

devfs_unregister(skel->devfs);  

現(xiàn)在,skeleton驅動就已經(jīng)和設備綁定上了,任何用戶態(tài)程序要操作此設備都可以通過file_operations結構所定義的函數(shù)進行了。  

(3)open()、write()和read()函數(shù)  

首先,要打開此設備。在open()函數(shù)中MODULE_INC_USE_COUNT 宏是一個關鍵,它起到一個計數(shù)的作用,有一個用戶態(tài)程序打開一個設備,計數(shù)器就加1。例如,以模塊方式加入一個驅動,若計數(shù)器不為零,就說明仍然有用戶程序在使用此驅動,這時候,就不能通過rmmod命令卸載驅動模塊了。  

/* increment our usage count for the module */  

MOD_INC_USE_COUNT;  

++skel->open_count;  

/* save our object in the file's private structure */  

file->private_data = skel;  

當open完設備后,read()、write()函數(shù)就可以收、發(fā)數(shù)據(jù)了。  

read()函數(shù)首先從open()函數(shù)中保存的fi。  

Write()函數(shù)和read()函數(shù)是完成驅動對讀寫等操作的響應。在skel_write中,一個FILL_BULK_URB函數(shù),就完成了urb 系統(tǒng)callbak和的skel_write_bulk_callback之間的聯(lián)系。注意skel_write_bulkcallback是中斷方式,所以要注意時間不能太久,本程序中它就只是報告一些urb的狀態(tài)等。 read 函數(shù)與write 函數(shù)稍有不同在于:程序并沒有用urb 將數(shù)據(jù)從設備傳送到驅動程序,而是用usb_bulk_msg 函數(shù)代替,這個函數(shù)能夠不需要創(chuàng)建urbs 和操作urb函數(shù)的情況下,來發(fā)送數(shù)據(jù)給設備,或者從設備來接收數(shù)據(jù)。調用usb_bulk_msg函數(shù)并傳到一個存儲空間,用來緩沖和放置驅動收到的數(shù)據(jù),若沒有收到數(shù)據(jù)表示失敗并返回一個錯誤信息。  

usb_bulk_msg函數(shù):當對usb設備進行一次讀或者寫時,usb_bulk_msg 函數(shù)是非常有用的; 然而, 當需要連續(xù)地對設備進行讀/寫時,應建立一個自己的urbs,同時將urbs 提交給USB子系統(tǒng)。  

skel_disconnect函數(shù):當釋放設備文件句柄時,這個函數(shù)會被調用。  

MOD_DEC_USE_COUNT宏也會被調用到(和MOD_INC_USE_COUNT剛好對應,它減少一個計數(shù)器),首先確認當前是否有其他的程序正在訪問這個設備,如果是最后一個用戶在使用,可以關閉任何正在發(fā)生的寫,操作如下:  

/* decrement our usage count for the device */  

--skel->open_count;  

if (skel->open_count /* shutdown any bulk writes that might be  

going on */  

usb_unlink_urb (skel->write_urb);  

skel->open_count = 0;  

}  

/* decrement our usage count for the module */  

MOD_DEC_USE_COUNT;  

USB設備可以在任何時間點從系統(tǒng)中取走,即使程序目前正在訪問它。USB驅動程序必須要能夠很好地處理解決此問題,它需要能夠切斷任何當前的讀寫,同時通知用戶空間程序:USB設備已經(jīng)被取走。  

2.設計實例  

下面通過介紹鍵盤飛梭驅動程序的實例來讓讀者更好的理解USB驅動程序的工作原理,實現(xiàn)代碼如下:  

/*需要的頭文件*/  

#include   

#include   

#include   

#include   

#include   

#include   

#include   

/* 驅動程序版本信息*/  

#define DRIVER_VERSION ""  

#define DRIVER_AUTHOR " TGE HOTKEY "  

#define DRIVER_DESC "USB HID Tge hotkey driver"  

#define USB_HOTKEY_VENDOR_ID 0x07e4  

#define USB_HOTKEY_PRODUCT_ID 0x9473  

/*廠商和產(chǎn)品ID信息就是/proc/bus/usb/devices中看到的值,通過cat/proc/bus/usb/devices得到當前系統(tǒng)探測到的USB總線上的設備信息。它包括Vendor、ProdID、Product等*/  

MODULE_AUTHOR( DRIVER_AUTHOR );  

MODULE_DESCRIPTION( DRIVER_DESC );  

/*此結構來自內核中drivers/usb/usbkbd.c*/  

struct usb_kbd {  

struct input_dev dev;  

struct usb_device *usbdev;  

unsigned char new[8];  

unsigned char old[8];  

struct urb irq, led;  

struct usb_ctrlrequest dr;  

unsigned char leds, newleds;  

char name[128];  

int open;  

};  

static void usb_kbd_irq(struct urb *urb) /*urb為USB請求塊*/  

{  

struct usb_kbd *kbd = urb->context;  

int *new;  

new = (int *) kbd->new;  

if(kbd->new[0] == (char)0x01)  

{  

if(((kbd->new[1]>>4)&0x0f)!=0x7)  

{  

handle_scancode(0xe0,1);  

handle_scancode(0x4b,1);  

handle_scancode(0xe0,0);  

handle_scancode(0x4b,0);  

}  

else  

{ handle_scancode(0xe0,1);  

handle_scancode(0x4d,1);  

handle_scancode(0xe0,0);  

handle_scancode(0x4d,0);  

}  

}  

printk("new=%x %x %x %x %x %x %x %x", kbd->new[0],kbd->new[1],kbd->new[2],kbd->new[3],  

kbd->new[4],kbd->new[5],kbd->new[6],kbd->new[7]);  

}  

static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)  

{  

struct usb_interface *iface;  

struct usb_interface_descriptor *interface;  

struct usb_endpoint_descriptor *endpoint;  

struct usb_kbd *kbd;  

int pipe, maxp;  

iface = &dev->actconfig->interface[ifnum];  

interface = &iface->altsetting[iface->act_altsetting];  

if ((dev->descriptor.idVendor != USB_HOTKEY_VENDOR_ID) || (dev->descriptor.idProduct != USB_HOTKEY_PRODUCT_ID) || (ifnum != 1))  

{  

return NULL;  

}  

if (dev->actconfig->bNumInterfaces != 2)  

{  

return NULL;  

}  

if (interface->bNumEndpoints != 1) return NULL;  

endpoint = interface->endpoint + 0;  

pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);  

maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));  

usb_set_protocol(dev, interface->bInterfaceNumber, 0);  

usb_set_idle(dev, interface->bInterfaceNumber, 0, 0);  

printk(KERN_INFO "GUO: Vid = %.4x, Pid = %.4x, Device = %.2x, ifnum = %.2x, bufCount = %.8x\\n", dev->descriptor.idVendor,dev->descriptor.idProduct,dev->descriptor.bcdDevice, ifnum, maxp);  

if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL;  

memset(kbd, 0, sizeof(struct usb_kbd));  

kbd->usbdev = dev;  

FILL_INT_URB(&kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp, usb_kbd_irq,kbd, endpoint->bInterval); kbd->irq.dev = kbd->usbdev;  

if (dev->descriptor.iManufacturer) usb_string(dev, dev->descriptor.iManufacturer, kbd->name, 63);  

if (usb_submit_urb(&kbd->irq)) {  

kfree(kbd); return NULL; }  

printk(KERN_INFO "input%d: %s on usb%d:%d.%d\\n", kbd->dev.number, kbd->name, dev->bus->busnum, dev->devnum, ifnum);  

return kbd; }  

static void usb_kbd_disconnect(struct usb_device *dev, void *ptr)  

{  

struct usb_kbd *kbd = ptr;  

usb_unlink_urb(&kbd->irq);  

kfree(kbd);  

}  

static struct usb_device_id usb_kbd_id_table [] = {  

{ USB_DEVICE(USB_HOTKEY_VENDOR_ID, USB_HOTKEY_PRODUCT_ID) },  

{ } /* Terminating entry */  

};  

MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);  

static struct usb_driver usb_kbd_driver = {  

name: "Hotkey",  

probe: usb_kbd_probe,  

disconnect: usb_kbd_disconnect,  

id_table: usb_kbd_id_table,  

NULL,  

};  

static int __init usb_kbd_init(void)  

{  

usb_register(&usb_kbd_driver);  

info(DRIVER_VERSION ":" DRIVER_DESC);  

return 0;  

}  

static void __exit usb_kbd_exit(void)  

{  

usb_deregister(&usb_kbd_driver);  

}  

module_init(usb_kbd_init);  

module_exit(usb_kbd_exit);  

三、結語  

USB規(guī)范是一門比較新的技術,接口使用方便,但是驅動程序的設計較復雜。上面介紹了USB設備驅動程序的設計,主要分析了主機端驅動程序的設計,并且給出了一個編寫USB驅動程序的實例。
本文地址:http://www.qingdxww.cn/thread-21630-1-1.html     【打印本頁】

本站部分文章為轉載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀點和對其真實性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問題,我們將根據(jù)著作權人的要求,第一時間更正或刪除。
您需要登錄后才可以發(fā)表評論 登錄 | 立即注冊

廠商推薦

  • Microchip視頻專區(qū)
  • Dev Tool Bits——使用MPLAB® Discover瀏覽資源
  • Dev Tool Bits——使用條件軟件斷點宏來節(jié)省時間和空間
  • Dev Tool Bits——使用DVRT協(xié)議查看項目中的數(shù)據(jù)
  • Dev Tool Bits——使用MPLAB® Data Visualizer進行功率監(jiān)視
  • 貿(mào)澤電子(Mouser)專區(qū)

相關視頻

關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復 返回頂部 返回列表
主站蜘蛛池模板: 欧美日韩中文一区二区三区 | 绿巨人香蕉草莓丝瓜茄子番茄在线 | 欧美成a高清在线观看www | 亚洲欧美一区二区三区在线 | 日韩美女在线视频 | 亚洲美日韩| 青草草在线观看免费视频 | www亚洲欲色成人久久精品 | 国产成人精品视频免费 | 欧美香蕉 | 亚洲网址在线 | 青青青视频在线播放视频 | 啄木乌欧美一区二区三区 | 色综合综合色综合色综合 | 四虎影午夜成年免费精品 | 一级做a爰片久久毛片人呢 一级做a爰片久久毛片免费看 | 四虎影院观看视频 | 在线观看国产情趣免费视频 | 亚洲免费观看视频 | 狠狠插综合 | 亚洲精品v欧美精品动漫精品 | jizz日本护士视频 | 久久久久久国产精品免费免费 | 一级黄色毛片视频 | 欧美三级在线观看视频 | 日本中文字幕一区二区三区不卡 | 99这里都是精品 | 亚洲黄色激情视频 | 一级特黄aaa大片在线观看视频 | 免费在线观看黄色的网站 | 最新亚洲一区二区三区四区 | 日本色www| 久久精品国产亚洲麻豆 | 日韩欧美第一区二区三区 | 四虎最新永久免费网址 | 午夜精品视频在线观看 | 日韩欧美小视频 | 日本在线不卡一区 | 美女一级毛片免费不卡视频 | 国产在线观看一区精品 | 日日夜夜免费精品视频 |