版權(quán)聲明:本文為博主原創(chuàng)文章泣洞,如有需要, 請(qǐng)注明轉(zhuǎn)載地址:http://blog.csdn.net/tech_pro忧风。若是侵權(quán)用于商業(yè)用途,請(qǐng)聯(lián)系博主球凰,否則將追究責(zé)任狮腿。 https://blog.csdn.net/TECH_PRO/article/details/70738186
一、Linux下的USB驅(qū)動(dòng)程序
分離和分層是Linux下驅(qū)動(dòng)程序開(kāi)發(fā)采用的最基本的形式呕诉,USB驅(qū)動(dòng)開(kāi)發(fā)在主機(jī)端主要涉及兩個(gè)部分:主機(jī)控制器驅(qū)動(dòng)和設(shè)備驅(qū)動(dòng)缘厢。
主機(jī)控制器驅(qū)動(dòng)主要是和具體的Soc相關(guān)的,它來(lái)識(shí)別USB設(shè)備甩挫,安裝對(duì)應(yīng)的設(shè)備驅(qū)動(dòng)程序昧绣,提供對(duì)USB設(shè)備的讀寫(xiě)函數(shù)。
設(shè)備驅(qū)動(dòng)主要是根據(jù)具體的USB設(shè)備對(duì)USB主機(jī)驅(qū)動(dòng)提供的讀寫(xiě)函數(shù)獲得的數(shù)據(jù)進(jìn)行處理捶闸,實(shí)現(xiàn)這種USB設(shè)備特有的功能夜畴。具體的層次結(jié)構(gòu)如下所示:
基本的開(kāi)發(fā)環(huán)境:
操作系統(tǒng):Ubuntu12.04
內(nèi)核:Linux-3.0.86
GUI :Qtopia2.2.0
交叉編譯工具gcc版本 : 4.5.1
二、USB鼠標(biāo)設(shè)備驅(qū)動(dòng)的實(shí)現(xiàn)
這一部分主要完成的功能是:實(shí)現(xiàn)一個(gè)簡(jiǎn)單的USB鼠標(biāo)的設(shè)備驅(qū)動(dòng)程序删壮,讀取鼠標(biāo)進(jìn)行操作所產(chǎn)生的原始的數(shù)據(jù)贪绘。
1、準(zhǔn)備工作
默認(rèn)的在Linux內(nèi)核當(dāng)中已經(jīng)配置上了USB鼠標(biāo)相關(guān)的驅(qū)動(dòng)央碟,所以為了自己編寫(xiě)的驅(qū)動(dòng)程序能加載進(jìn)內(nèi)核和使用税灌,先要去掉內(nèi)核上的USB鼠標(biāo)驅(qū)動(dòng)。進(jìn)入內(nèi)核目錄亿虽,執(zhí)行make menuconfig菱涤,執(zhí)行如下配置:
-> Device Drivers
<span> </span>-> HID Devices
????????????????[ ]USB Human Interface Device (full HID) support
2、設(shè)備驅(qū)動(dòng)編寫(xiě)
a洛勉、分配粘秆、設(shè)置、注冊(cè)一個(gè)usb_driver的結(jié)構(gòu)體變量收毫,為了方便定義了如下一個(gè)結(jié)構(gòu)體:
/* 定義一個(gè)描述USB的結(jié)構(gòu)體 */
struct yl_usbmouse {
? ??????????????dma_addr_t usb_buf_phys; /* 描述分配的緩沖區(qū)的物理地址 */
? ??????????????char *usb_buf_virt; /* 描述分配的緩沖區(qū)的虛擬地址 */
? ??????????????int usb_buf_len; /* 用來(lái)描述緩沖區(qū)的大小 */
? ??????????????struct urb *urb; /* 描述usb的請(qǐng)求塊 */
};
定義一個(gè)usb_driver的結(jié)構(gòu)體攻走,并設(shè)置它:
/* 定義一個(gè)usb_driver的結(jié)構(gòu)體變量 */
static struct usb_driver yl_usb_mouse_driver = {
? ??????????????.name = "yl_usbmouse",
? ??????????????.probe = yl_usb_mouse_probe,
? ? ? ? ? ? ? ? ?.disconnect = yl_usb_mouse_disconnect,
? ??????????????.id_table = yl_usb_mouse_id_table,
};
在入口函數(shù)中注冊(cè)這個(gè)結(jié)構(gòu)體:
/* 模塊的入口函數(shù) */
staticint__inityl_usb_mouse_init(void)
{
????????/* 注冊(cè)一個(gè)usb_driver的結(jié)構(gòu)體變量 */
????????usb_register(&yl_usb_mouse_driver);
? ? ? ? return0;
}
b、分配此再、設(shè)置昔搂、初始化、提交一個(gè)urb输拇,urb是用來(lái)傳遞USB主機(jī)控制器驅(qū)動(dòng)的數(shù)據(jù)摘符。當(dāng)插入的設(shè)備和這個(gè)usb_driver匹配時(shí),它的probe函數(shù)將會(huì)調(diào)用,我們?cè)趐robe函數(shù)當(dāng)中實(shí)現(xiàn)對(duì)urb的一些列操作.
分配一個(gè)urb:
/* 1逛裤、分配一個(gè)usb請(qǐng)求塊 */
g_yl_usbmouse.urb = usb_alloc_urb(0, GFP_KERNEL);
設(shè)置蠢古、初始化這個(gè)urb:
/* 獲取USB設(shè)備的某個(gè)端點(diǎn) */
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
/* 獲取傳輸?shù)臄?shù)據(jù)的長(zhǎng)度 */
g_yl_usbmouse.usb_buf_len = endpoint->wMaxPacketSize;
/* 分配一塊緩沖區(qū)用來(lái)存放usb鼠標(biāo)的數(shù)據(jù) */
g_yl_usbmouse.usb_buf_virt = usb_alloc_coherent(dev, g_yl_usbmouse.usb_buf_len, GFP_ATOMIC, &g_yl_usbmouse.usb_buf_phys);
/* 2、初始化這個(gè)usb請(qǐng)求塊 */
usb_fill_int_urb(g_yl_usbmouse.urb, dev, pipe, g_yl_usbmouse.usb_buf_virt, g_yl_usbmouse.usb_buf_len, yl_usbmouse_irq, NULL, endpoint->bInterval);
g_yl_usbmouse.urb->transfer_dma = g_yl_usbmouse.usb_buf_phys;
g_yl_usbmouse.urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
提交這個(gè)urb:
/* 3别凹、提交這個(gè)usb請(qǐng)求塊 */
usb_submit_urb(g_yl_usbmouse.urb, GFP_KERNEL);
c草讶、usb鼠標(biāo)獲取數(shù)據(jù)的中斷處理函數(shù),這個(gè)函數(shù)是在urb初始化的時(shí)候傳遞進(jìn)來(lái)的回調(diào)函數(shù)炉菲,鼠標(biāo)發(fā)生動(dòng)作時(shí)便會(huì)觸及這個(gè)函數(shù)的調(diào)用堕战,把鼠標(biāo)的數(shù)據(jù)傳遞進(jìn)來(lái)。它的具體的實(shí)現(xiàn)如下所示:
/* usb鼠標(biāo)的中斷處理函數(shù) */
static void yl_usbmouse_irq(struct urb *urb)
{
? ??????int i = 0;
? ??????/* 依次把數(shù)據(jù)打印出來(lái) */
? ??????printk("yl_usbmouse data : ");
? ??????for(i = 0; i < g_yl_usbmouse.usb_buf_len; i++)
? ??????{
? ??????????????printk("0x%x ", g_yl_usbmouse.usb_buf_virt[i]);
? ??????}
? ??????printk("\n");
/* 再次提交urb */
usb_submit_urb(g_yl_usbmouse.urb, GFP_ATOMIC);
}
這個(gè)函數(shù)實(shí)現(xiàn)的功能很簡(jiǎn)單:就是把鼠標(biāo)產(chǎn)生的原始數(shù)據(jù)打印到終端上即可拍霜。
3嘱丢、編譯并安裝驅(qū)動(dòng),在開(kāi)發(fā)板上接入鼠標(biāo)實(shí)驗(yàn)結(jié)果如下:
從上面可以看出祠饺,鼠標(biāo)每操作一次會(huì)一次性產(chǎn)生7個(gè)字節(jié)的數(shù)據(jù)越驻。可以看出這些數(shù)據(jù)本身只是一些普通的數(shù)據(jù)道偷,沒(méi)有任何意義缀旁,那怎么讓鼠標(biāo)產(chǎn)生的這些數(shù)據(jù)發(fā)揮作用呢,就需要將usb鼠標(biāo)和輸入子系統(tǒng)結(jié)合使用勺鸦,才能真正發(fā)揮USB鼠標(biāo)的作用并巍。具體實(shí)現(xiàn)見(jiàn)下文。
附錄:本文實(shí)現(xiàn)的完整的例程源代碼如下所示:
#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>
/* 定義一個(gè)描述USB的結(jié)構(gòu)體 */
struct yl_usbmouse {
????????????????dma_addr_t usb_buf_phys; /* 描述分配的緩沖區(qū)的物理地址 */
????????????????char *usb_buf_virt; /* 描述分配的緩沖區(qū)的虛擬地址 */
????????????????int usb_buf_len; /* 用來(lái)描述緩沖區(qū)的大小 */
????????????????struct urb *urb; /* 描述usb的請(qǐng)求塊 */
};
/* 定義一個(gè)描述USB結(jié)構(gòu)體的變量 */
static struct yl_usbmouse g_yl_usbmouse;
/* usb鼠標(biāo)的中斷處理函數(shù) */
static void yl_usbmouse_irq(struct urb *urb)
{
????????int i = 0;
/* 依次把數(shù)據(jù)打印出來(lái) */
????????printk("yl_usbmouse data : ");
????????for(i = 0; i < g_yl_usbmouse.usb_buf_len; i++)
????????{
????????????????printk("0x%x ", g_yl_usbmouse.usb_buf_virt[i]);
????????}
????????printk("\n");
/* 再次提交urb */
????????usb_submit_urb(g_yl_usbmouse.urb, GFP_ATOMIC);
}
/* 匹配設(shè)備成功時(shí)調(diào)用的探測(cè)函數(shù) */
static int yl_usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
????????struct usb_device *dev = interface_to_usbdev(intf);
????????struct usb_host_interface *interface;
????????struct usb_endpoint_descriptor *endpoint;
????????int pipe;
/* 獲取接口和端點(diǎn)信息 */
????????interface = intf->cur_altsetting;
????????endpoint = &interface->endpoint[0].desc;
/* 獲取USB設(shè)備的某個(gè)端點(diǎn) */
????????pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
/* 獲取傳輸?shù)臄?shù)據(jù)的長(zhǎng)度 */
????????g_yl_usbmouse.usb_buf_len = endpoint->wMaxPacketSize;
/* 分配一塊緩沖區(qū)用來(lái)存放usb鼠標(biāo)的數(shù)據(jù) */
????????g_yl_usbmouse.usb_buf_virt = usb_alloc_coherent(dev, g_yl_usbmouse.usb_buf_len, GFP_ATOMIC, &g_yl_usbmouse.usb_buf_phys);
/* 1换途、分配一個(gè)usb請(qǐng)求塊 */
????????g_yl_usbmouse.urb = usb_alloc_urb(0, GFP_KERNEL);
/* 2懊渡、初始化這個(gè)usb請(qǐng)求塊 */
????????usb_fill_int_urb(g_yl_usbmouse.urb, dev, pipe, g_yl_usbmouse.usb_buf_virt, g_yl_usbmouse.usb_buf_len, yl_usbmouse_irq, NULL, endpoint->bInterval);
????????g_yl_usbmouse.urb->transfer_dma = g_yl_usbmouse.usb_buf_phys;
????????g_yl_usbmouse.urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* 3、提交這個(gè)usb請(qǐng)求塊 */
????????usb_submit_urb(g_yl_usbmouse.urb, GFP_KERNEL);
????????return 0;
}
/* usb設(shè)備拔除時(shí)調(diào)用的函數(shù) */
static void yl_usb_mouse_disconnect(struct usb_interface *intf)
{
????????struct usb_device *dev = interface_to_usbdev(intf);
????????usb_kill_urb(g_yl_usbmouse.urb);
????????usb_free_urb(g_yl_usbmouse.urb);
????????usb_free_coherent(dev, g_yl_usbmouse.usb_buf_len, g_yl_usbmouse.usb_buf_virt, g_yl_usbmouse.usb_buf_phys);
}
/* 定義一個(gè)id_table的數(shù)組军拟,當(dāng)usb設(shè)備插入時(shí)進(jìn)行比較和判斷 */
static struct usb_device_id yl_usb_mouse_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
{ } /* Terminating entry */
};
/* 定義一個(gè)usb_driver的結(jié)構(gòu)體變量 */
static struct usb_driver yl_usb_mouse_driver = {
????????.name = "yl_usbmouse",
????????.probe = yl_usb_mouse_probe,
????????.disconnect = yl_usb_mouse_disconnect,
????????.id_table = yl_usb_mouse_id_table,
};
/* 模塊的入口函數(shù) */
static int __init yl_usb_mouse_init(void)
{
/* 注冊(cè)一個(gè)usb_driver的結(jié)構(gòu)體變量 */
????????usb_register(&yl_usb_mouse_driver);
????????return 0;
}
/* 模塊的出口函數(shù) */
static void __exit yl_usb_mouse_exit(void)
{
/* 注銷(xiāo)一個(gè)usb_driver的結(jié)構(gòu)體變量 */
????????usb_deregister(&yl_usb_mouse_driver);
}
module_init(yl_usb_mouse_init);
module_exit(yl_usb_mouse_exit);
MODULE_LICENSE("GPL");