usb.c源碼:
// 參考drivers/hid/usbhid/usbmouse.c
#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"
#include "linux/input.h"
static struct input_dev *mk_dev;
static int len;
static char *buf;
static dma_addr_t buf_phys;
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) },
//{USB_DEVICE(0x46d, 0xc52f)},
{ } // Terminating entry
};
// 當USB主機控制器獲得鼠標數據后,
// 會調用這個函數
static void uk_callback(struct urb *urb)
{
int i;
static char pre_val;
#if 0
printk("Get datas:\n");
for (i = 0; i < len; i++)
{
printk("x ", buf[i]);
}
printk("\n");
#endif
// 鼠標數據含義:
// buf[0]: bit0-左鍵, 0-松開, 1-按下
// bit1-右鍵, 0-松開, 1-按下
// bit2-中鍵, 0-松開, 1-按下
// buf[1],buf[2]構成一個整數, 表示X方向的相對位移
// >0 : 右移
// <0 : 左移
// buf[3],buf[4]構成一個整數, 表示Y方向的相對位移
// >0 : 下移
// <0 : 上移
// buf[6]: 滾輪
// 確定按鍵值
// 上報數據
if ((pre_val & (1<<0)) != (buf[0] & (1<<0)))
{
// 左鍵按下或松開
input_event(mk_dev, EV_KEY, KEY_L, (buf[0] & (1<<0)) ? 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);
}
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;
// 每一個設備都有端點0
// interface->endpoint[]數組里放"除了端點0外的其他端點"
// interface->endpoint[0]表示"除端點0外的第1個端點"
// interface->endpoint[1]表示"除端點0外的第2個端點"
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
// 1. 分配inputd_dev
mk_dev = input_allocate_device();
// 2. 設置
// 2.1 能產生哪類事件
set_bit(EV_KEY, mk_dev->evbit);
set_bit(EV_REP, mk_dev->evbit);
// 2.2 能產生這類事件里的哪些事件
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. 硬件相關的操作:
// 對于GPIO按鍵, 是request_irq, 在中斷處理函數里上報按鍵
// 對于USB設備, 是使用"USB主機驅動程序提供的函數"發起USB傳輸獲得數據
// 數據傳輸3要素: 源, 目的, 長度
// A. 源: USB設備的某個端點
// ((PIPE_INTERRUPT << 30) | (dev->devnum << 8) | (endpoint << 15) | USB_DIR_IN)
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
// C. 長度: 這個端點描述符的wMaxPacketSize
len = endpoint->wMaxPacketSize;
// B. 目的: 分配buffer
buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &buf_phys);
// D. 怎么使用這3要素 ?
// 分配URB: USB Reqeust Block
mk_urb = usb_alloc_urb(0, GFP_KERNEL);
// 用3要素填充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;
// 使用URB
usb_submit_urb(mk_urb, GFP_KERNEL);
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_buffer_free(dev,len, buf, buf_phys);
input_unregister_device(mk_dev);
input_free_device(mk_dev);
}
// 1. 分配usb_driver
// 2. 設置
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");
=====================================================================
Makefile文件:
KERN_DIR = /home/linux/linux-3.0.1
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += usb.o
=====================================================================
測試部分參考:JZ2440的USB設備驅動程序
上一篇:OK6410塊設備驅動之用內存模擬磁盤
下一篇:OK6410分層分離(總線-驅動-設備模型)
推薦閱讀
史海拾趣
隨著Afero物聯網平臺的逐漸成熟,公司開始積極尋求與各行各業的合作伙伴建立合作關系。他們與多家知名的電子設備制造商、軟件開發商和服務提供商簽訂了戰略合作協議,共同開發基于Afero平臺的物聯網解決方案。這些合作不僅幫助Afero拓展了業務領域,還提升了其在行業內的知名度和影響力。
在LED照明產品的生產過程中,DDP Engineered LED Solutions公司始終堅守品質控制的原則。公司建立了嚴格的生產流程和質檢標準,確保每一件產品都符合質量要求。同時,公司還積極引入先進的生產設備和管理系統,提升生產效率和產品質量。正是這些努力,讓DDP的產品在市場上贏得了客戶的信任和好評,為公司贏得了良好的口碑。
自FCI成立以來,公司憑借其專業的設計、精密的制造工藝和創新精神,迅速在全球連接器市場上嶄露頭角。通過不斷的技術創新和產品升級,FCI逐漸成為了全球領先的連接器制造商之一。其產品線涵蓋了通訊、電源、醫療等多個領域,為全球眾多知名品牌提供了優質的連接器解決方案。
隨著LED照明市場的不斷擴大,Heatron LED Integration憑借敏銳的市場洞察力,迅速調整市場戰略。公司不僅鞏固了在國內市場的領先地位,還積極開拓國際市場,與多家國際知名企業建立了長期合作關系。通過參加國際展會、設立海外分支機構等方式,公司成功將產品推向全球多個國家和地區,實現了品牌的國際化。
Agilent Fundamentals of RF and Microwave Modern receiving systems must often process veryweak signals, but the noise added by the systemcomponents tends to obscure those very weak signals.Sensitivity, bit error ratio (BER) and noise figure aresystem parameters that chara ...… 查看全部問答∨ |
長期供應頻譜分析儀HP8563E/E4402B/E4403B/MS2665C/MS 一、 綜合測試儀 R&S CMU200(可測GSM900/1800);Agilent8960 E5515B(可測GSM900/1800/1900/GPRS);Agilnet8960 E5515C(OPT:002、003,可測GSM、CDMA);R&S CMD55(可測900/1800);R&S CMD60(DECT測試儀);MT8801B(PHS測試儀); ...… 查看全部問答∨ |
我現在在對話框中添加了按鈕 void xxxDlg::OnButton1() 想實現的功能有兩個,點擊按鈕后首先能獲取要顯示圖片的路徑,現在已經實現了并把路徑保存在CString pathname 中。第二個功能 想接著把對應路徑的這個圖片顯示到對話框中。(這個按鈕是程序 ...… 查看全部問答∨ |
|
在platform。bib下,添加某個文件,系統啟動后默認會在windows下找到。 如果我想將一個文件夾放在桌面,文件夾里有幾個文件,系統啟動后,自動運行的程序可以對這個文件夾里的文件進行操作。 在制作nk的時候應該怎么做?… 查看全部問答∨ |
|
尋有無線條碼數據終端Symbol PDT8146編程經驗的高手 想做一個固定資產清查軟件: 通過無線終端可以實現對粘有條碼的設備進行清查,并能夠與服務器數據進行互連 PC端的程序不需要實現,只要實現無線終端查詢和報表功能.請有興趣的朋友與我聯系,有償服務 QQ 30107562 暗號 無線終端… 查看全部問答∨ |
|
在使用ADS Debug uC/OS系統和一個簡單的讓蜂鳴器響的應用程序時,AXD loading image后,沒有進入StartUP函數而是進入Disassembly,Go后不停的running image ,蜂鳴器不響,也不知道是不是下到板子里了。 請問是怎么回事?… 查看全部問答∨ |
本來這次我想搞點硬件,但我那光盤單位和家里串來串去地,在家找不到,在單位放到光驅里,明天再說吧。 我想要想編好程序,必須得攝及一個東東------庫,提起這個庫我以前搞過STM32哈,那個庫我是百分之百反對地,但我越反它越大,還把CMS ...… 查看全部問答∨ |