注意:本篇講的鼠標(biāo)驅(qū)動僅能實(shí)現(xiàn)鼠標(biāo)左右鍵跟滑輪這三個(gè)按鍵類似button的功能,按下左鍵則打出'l',右鍵打出“s”,滑輪打出“enter”。如果要實(shí)現(xiàn)正常的鼠標(biāo)驅(qū)動,參考內(nèi)核的鼠標(biāo)驅(qū)動,修改input的一些參數(shù)即可。
一、寫驅(qū)動的步驟(新手稍微看下即可,內(nèi)容有點(diǎn)搞)
1、復(fù)制頭文件;
2、寫入口函數(shù),出口函數(shù),再加上協(xié)議;
3、分配注冊usb_driver結(jié)構(gòu)體(拷別人的),
static struct usb_driver usb_mk_driver = {};
在init中注冊該結(jié)構(gòu)體:usb_register(&usb_mk_driver);
在exit中注銷該結(jié)構(gòu)體:usb_deregister(&usb_mk_driver);
4、寫id_table函數(shù),static struct usb_device_id usb_mk_id_table [] = {},只有滿足id_table中的各種類別,子類號,協(xié)議,才能調(diào)用;
5、寫probe函數(shù):static int usb_mk_probe(struct usb_interface *intf, const struct usb_device_id *id);
6、寫disconnect函數(shù):static void usb_mk_disconnect(struct usb_interface *intf)
7、如果想在開發(fā)板插入usb設(shè)備的時(shí)候打印設(shè)備信息(可以不用),可以在probe中加入:
printk('VID = 0x%x, PID = 0x%xn', dev->descriptor.idVendor, dev->descriptor.idProduct);
printk('USB VERS = 0x%x, PID = 0x%xn', dev->descriptor.bcdUSB);
8、probe之后要進(jìn)一步判斷你這個(gè)是不是鼠標(biāo):
1、分配一個(gè)input_dev結(jié)構(gòu)體:在頭文件下定義;static struct input_dev *mk_dev; 在probe內(nèi):mk_dev = input_allocate_device();
2、設(shè)置:
1、能產(chǎn)生哪類事件
set_bit(EV_KEY, mk_dev->evbit);
set_bit(EV_REP, mk_dev->evbit);
2、能產(chǎn)生哪些事件
set_bit(KEY_L, mk_dev->keybit);
set_bit(KEY_S, mk_dev->keybit);
set_bit(KEY_ENTER, mk_dev->keybit);
3、注冊:input_register_device(mk_dev);
4、設(shè)置:數(shù)據(jù)傳輸3要素: 源, 目的, 長度
先從usbmouse.c中拷入幾行代碼:
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
int pipe;
endpoint = &interface->endpoint[0].desc;
源:usb設(shè)備的某個(gè)端點(diǎn)
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
目的:需要設(shè)置緩沖區(qū)buffer:
buf = usb_alloc_coherent(dev, len, GFP_ATOMIC, &buf_phys);
在頭文件下定義一個(gè)緩沖區(qū):
static char *buf;
static dma_addr_t buf_phys;
長度:static int len(作為全局變量,等會有用)
len = endpoint->wMaxPacketSize;
5、怎么用那三要素呢?
在probe中;
1、分配一個(gè)urb,mk_urb = usb_alloc_urb(0, GFP_KERNEL);
在頭文件下定義urb:static struct urb *mk_urb;
2、使用三要素填充urb:
usb_fill_int_urb(mk_urb, dev, pipe, buf,
len,
uk_callback, NULL, endpoint->bInterval);
mk_urb->transfer_dma = buf_phys;
mk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
3、使用URB:usb_submit_urb(mk_urb, GFP_KERNEL);
6、要寫一個(gè)中斷函數(shù),原因是usb控制器收到從usb傳來的數(shù)據(jù)后,需要一個(gè)中斷來通知cpu有信號啦!static void uk_callback(struct urb *urb)
在中斷函數(shù)中定義一些唧唧歪歪的東西后看,重新提交urb:
usb_submit_urb(mk_urb, GFP_KERNEL);
7,提交urb后當(dāng)然還要做殺掉urb,在disconnect中殺掉它!usb_kill_urb(mk_urb);
順便再disconnect中注銷或卸載其他的函數(shù);
8、在中斷函數(shù)里上報(bào)事件。
**************************************************************************************************************
二、驅(qū)動程序
#include <linux/kernel.h>
#include #include #include #include #include #include /* 參考drivershidusbhidusbmouse.c */ static struct input_dev *mk_dev; static int len; static char *buf; //定義一個(gè)緩沖區(qū) static dma_addr_t buf_phys; //dma_addr實(shí)際上是一個(gè)物理地址 static struct urb *mk_urb; static struct usb_device_id usb_mk_id_table [] = { { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, USB_INTERFACE_PROTOCOL_MOUSE) }, /*只要它的類是class_hid,子類是boot,協(xié)議是mouse,那么就可以匹配*/ *{USB_DEVICE(0x46d, 0xc52f)或者直接指定自己的usb設(shè)備只支持這種廠家的設(shè)備。*/ { } /* Terminating entry */ }; /* 當(dāng)USB主機(jī)控制器獲得鼠標(biāo)數(shù)據(jù)后, * 會調(diào)用這個(gè)函數(shù) */ static void uk_callback(struct urb *urb)//這是一個(gè)中斷函數(shù)! { int i; static char pre_val; #if 0 //這一段都用不到了,因?yàn)閕f = 0 ;這一段的作用就是用來看鼠標(biāo)按下之后都顯示什么數(shù)值,最后通過這些數(shù)值來設(shè)置上報(bào)事件。 printk('Get datas:n'); for (i = 0; i < len; i++) { printk('%02x ', buf[i]); } printk('n'); #endif /* 鼠標(biāo)數(shù)據(jù)含義: * buf[0]: bit0-左鍵, 0-松開, 1-按下 * bit1-右鍵, 0-松開, 1-按下 * bit2-中鍵, 0-松開, 1-按下 * buf[1],buf[2]構(gòu)成一個(gè)整數(shù), 表示X方向的相對位移 * >0 : 右移 * <0 : 左移 * buf[3],buf[4]構(gòu)成一個(gè)整數(shù), 表示Y方向的相對位移 * >0 : 下移 * <0 : 上移 * buf[6]: 滾輪 */ /* 確定按鍵值 */ /* 上報(bào)數(shù)據(jù) */ if ((pre_val & (1<<0)) != (buf[0] & (1<<0))) //如果上次數(shù)據(jù)的bit0不等于這次數(shù)據(jù)的bit0,那么就是左鍵發(fā)生變化 { /* 左鍵按下或松開 */ input_event(mk_dev, EV_KEY, KEY_L, (buf[0] & (1<<0)) ? 1 : 0);//如果buf0=1的話那就是按下,既是1,否則為0; input_sync(mk_dev); } if ((pre_val & (1<<1)) != (buf[0] & (1<<1))) { /* 右鍵按下或松開 */ input_event(mk_dev, EV_KEY, KEY_S, (buf[0] & (1<<1)) ? 1 : 0); input_sync(mk_dev); } if ((pre_val & (1<<2)) != (buf[0] & (1<<2))) { /* 中鍵按下或松開 */ input_event(mk_dev, EV_KEY, KEY_ENTER, (buf[0] & (1<<2)) ? 1 : 0); input_sync(mk_dev); } pre_val = buf[0]; /* 重新提交URB */ usb_submit_urb(mk_urb, GFP_KERNEL); } /*interface是指接口,一個(gè)usb設(shè)備可能有多個(gè)邏輯接口,這個(gè)邏輯接口就是用下面的usb_interface來表示的*/ static int usb_mk_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; static int first = 1; if (!first) return -EIO; first = 0; /* 每一個(gè)設(shè)備都有端點(diǎn)0 * interface->endpoint[]數(shù)組里放'除了端點(diǎn)0外的其他端點(diǎn)' * interface->endpoint[0]表示'除端點(diǎn)0外的第1個(gè)端點(diǎn)' * interface->endpoint[1]表示'除端點(diǎn)0外的第2個(gè)端點(diǎn)' */ interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; /* 1. 分配inputd_dev */ mk_dev = input_allocate_device(); /* 2. 設(shè)置 */ /* 2.1 能產(chǎn)生哪類事件 */ set_bit(EV_KEY, mk_dev->evbit); //按鍵類事件 set_bit(EV_REP, mk_dev->evbit); //重復(fù)類事件,例如一直按著L,則會顯示LLLLLLL。。。 /* 2.2 能產(chǎn)生這類事件里的哪些事件 */ set_bit(KEY_L, mk_dev->keybit); set_bit(KEY_S, mk_dev->keybit); set_bit(KEY_ENTER, mk_dev->keybit); /* 3. 注冊 */ input_register_device(mk_dev); /* 4. 硬件相關(guān)的操作: * 對于GPIO按鍵, 是request_irq, 在中斷處理函數(shù)里上報(bào)按鍵 * 對于USB設(shè)備, 是使用'USB主機(jī)驅(qū)動程序提供的函數(shù)'發(fā)起USB傳輸獲得數(shù)據(jù) */ /* 數(shù)據(jù)傳輸3要素: 源, 目的, 長度 */ /* A. 源: USB設(shè)備的某個(gè)端點(diǎn) */ /* ((PIPE_INTERRUPT << 30) | (dev->devnum << 8) | (endpoint << 15) | USB_DIR_IN) */ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);//pipe是源,源是一個(gè)整數(shù),這個(gè)整數(shù)里有端點(diǎn)的類型,端點(diǎn)的方向 /* C. 長度: 這個(gè)端點(diǎn)描述符的wMaxPacketSize */ len = endpoint->wMaxPacketSize; /* B. 目的: 分配buffer */ buf = usb_alloc_coherent(dev, len, GFP_ATOMIC, &buf_phys);//從usb_buffer_alloc換成usb_alloc_coherent /* D. 怎么使用這3要素 ? */ /* 分配URB: USB Reqeust Block ,usb請求塊*/ mk_urb = usb_alloc_urb(0, GFP_KERNEL); /* 用3要素填充URB *實(shí)際上usb設(shè)備沒有中斷cpu的能力,但是電腦的usb主機(jī)有中斷cpu的能力,所以usb主機(jī)不斷查詢,有信號便中斷cpu。 */ usb_fill_int_urb(mk_urb, dev, pipe, buf, len, uk_callback, NULL, endpoint->bInterval);//bInterval:查詢頻率,uk_callback是一個(gè)中斷函數(shù); mk_urb->transfer_dma = buf_phys; //得到數(shù)據(jù)后要往某個(gè)內(nèi)存里寫,它沒那么聰明,需要一個(gè)物理地址 mk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;//還有設(shè)置某些標(biāo)記,這標(biāo)記什么意思偉哥也不懂 /* 使用URB ,看看別人怎么做*/ usb_submit_urb(mk_urb, GFP_KERNEL);//提交urb return 0; } static void usb_mk_disconnect(struct usb_interface *intf) { struct usb_device *dev = interface_to_usbdev(intf); printk('disconnect usb mouse!!!!!n'); usb_kill_urb(mk_urb); usb_free_urb(mk_urb); usb_free_coherent(dev,len, buf, buf_phys);//應(yīng)該是usb_free_coherent input_unregister_device(mk_dev); input_free_device(mk_dev); } /* 1. 分配usb_driver */ /* 2. 設(shè)置 */ static struct usb_driver usb_mk_driver = { .name = 'usbmk', .probe = usb_mk_probe, .disconnect = usb_mk_disconnect, .id_table = usb_mk_id_table, }; static int usb_mk_init(void) { /* 3. 注冊 */ usb_register(&usb_mk_driver); return 0; } static void usb_mk_exit(void) { usb_deregister(&usb_mk_driver); } module_init(usb_mk_init); module_exit(usb_mk_exit); MODULE_LICENSE('GPL');
上一篇:u-boot2010.03 移植篇(一) 建立編譯目標(biāo)
下一篇:基于ok6410的韋東山驅(qū)動視頻簡要分析--ts驅(qū)動
推薦閱讀最新更新時(shí)間:2025-07-13 18:40

設(shè)計(jì)資源 培訓(xùn) 開發(fā)板 精華推薦
- 神經(jīng)形態(tài)芯片可能是革新機(jī)器人實(shí)時(shí)電機(jī)控制的未來
- 從三個(gè)方面理解ARM嵌入式系統(tǒng)
- 自動報(bào)警 基于MCU的家庭防盜報(bào)警系統(tǒng)的設(shè)計(jì)
- 存儲控制器及其訪問外設(shè)的原理
- 基于51系列單片機(jī)的智能照明控制系統(tǒng)設(shè)計(jì)方案
- 基于STM32的四旋翼飛行器控制系統(tǒng)
- 單片機(jī)應(yīng)用編程技巧解析
- 基于89C52的教室智能節(jié)能照明系統(tǒng)設(shè)計(jì)
- 一種新型的雨量光照傳感器的設(shè)計(jì)
- SSL4101T Green Chip III+ SMPS控制IC典型應(yīng)用電路
- LTM8064IY ±6A、5V(2 象限)模塊穩(wěn)壓器的典型應(yīng)用電路
- LM2902S 單電源函數(shù)發(fā)生器運(yùn)算放大器的典型應(yīng)用電路
- LTC3400ES6-1 單節(jié) AA 電池至 ±3V 同步升壓轉(zhuǎn)換器的典型應(yīng)用電路
- LTM8022,模塊穩(wěn)壓器使電源開發(fā)變得快速而簡單,在 3.6 至 36V 輸入范圍內(nèi)提供 3.3V/1A
- KIT33905BD3EVBE: 評估套件 - 33905D3,帶CAN和LIN的第二代SBC
- LTC3425EUH 演示板,4MHz,多相器同步升壓轉(zhuǎn)換器,2V 至 3Vin,2 個(gè)電路,5Vout1 @ 2A,5Vout2 @ 1.5A
- TC682 反相倍壓器的典型應(yīng)用
- VAR-DVK-OM37_CE7,基于安裝了 Windows Embedded Compact 7 的 VAR-SOM-OM37 SOM 處理器的開發(fā)套件
- 具有低噪聲旁路的 LTM8057MPY 12V 反激式轉(zhuǎn)換器的典型應(yīng)用電路
- 2021年智能座艙設(shè)計(jì)趨勢研究:向第三生活空間邁進(jìn)
- Omdia:三星三季度半導(dǎo)體銷售額將反超英特爾登頂
- ??低暎好朗袌銮闆r不太樂觀,歐洲市場多地扎根更深
- 小米研發(fā)團(tuán)隊(duì)詳解MIX FOLD液態(tài)相機(jī):裝配連接復(fù)雜,良率90%
- 寧德時(shí)代再下一城!增資負(fù)極材料“新星”,持股35%!
- 如何利用視覺處理器在可視門鈴和智能零售設(shè)計(jì)中擴(kuò)展邊緣 AI 功能
- 泰克TPP0502電壓探頭在電源環(huán)路響應(yīng)測試方案
- ZDS5054D智能硬件分析型示波器的功能特點(diǎn)
- 高性能電動滑板車 BLDC 電機(jī)驅(qū)動器:技術(shù)解析與應(yīng)用展望
- 5G工業(yè)網(wǎng)關(guān)的“邊緣計(jì)算+AI推理”一體化設(shè)計(jì),PLC協(xié)議解析與缺陷檢測的實(shí)時(shí)聯(lián)動
- AR眼鏡的“工業(yè)指令投射”系統(tǒng),SLAM的空間定位、PLC數(shù)據(jù)實(shí)時(shí)疊加顯示
- 多光譜氣體傳感器的抗交叉干擾設(shè)計(jì)
- 多模態(tài)融合感知的“語義-幾何”聯(lián)合建模
- 工業(yè)觸摸屏的“壓感-手勢”多模態(tài)交互設(shè)計(jì)
- 工業(yè)機(jī)器人高精度力控的“雙模融合”傳感器設(shè)計(jì)
- 工業(yè)機(jī)器人集群的“數(shù)字孿生-物理實(shí)體”閉環(huán)優(yōu)化
- 工業(yè)以太網(wǎng)交換機(jī)的“時(shí)間敏感網(wǎng)絡(luò)(TSN)”改造
- 工業(yè)現(xiàn)場信號測試:耦合方式選擇實(shí)戰(zhàn)案例
- 由于駕駛使用不適當(dāng)?shù)腢SB而導(dǎo)致TeslaCam的問題
- 一種車載雷達(dá)測試系統(tǒng)
- 安森美物聯(lián)網(wǎng)創(chuàng)新設(shè)計(jì)工具將亮相國際物聯(lián)網(wǎng)展
- 基于低功耗藍(lán)牙傳感器的智能手表可實(shí)現(xiàn)數(shù)據(jù)同步功能
- UnitedSiC的UF3C FAST產(chǎn)品系列又添新成員
- 7nm不是盡頭,臺積電放眼未來主攻5nm
- STM32總結(jié)之開啟外設(shè)時(shí)鐘
- 致力半導(dǎo)體創(chuàng)新20余載,Soitec為中國“添磚加瓦”
- 一種可行的STM32F103外設(shè)RTC使用方法
- 從Mac換芯看國內(nèi)ARM架構(gòu)芯片應(yīng)用前景