USB驅動程式之滑鼠用做鍵盤

fight_onlyfor_you發表於2017-03-20

我們還是接著來看看我們的例子程式 usbmouse.c


這裡它接著判斷了他是不是滑鼠,

得到它的usb_host_interface,interface=intf->cur_alsetting就是當前介面的設定



這裡有個介面描述符,我們來看看介面描述符


介面描述符裡面有個__u8  bNumEndpoints端點的個數

這個端點的個數是除了端點0之外還有多少個端點


這裡首先判斷如果除了端點0之外,端點個數不是1的話就返回錯誤,不是我能夠支援的裝置

如果只有一個端點,那就把這個端點放到endpoint這個陣列裡面,這個並不是端點0,而是除了端點0之外第一個端點

得到一個端點描述符

if(!usb_endpoint_is_int_in(endpoint))這個是指如果他不是中斷類似的端點,不是輸入端點,注意了我們這裡輸入輸出是站在主機的角度說的,站在主機角度,我們的滑鼠是輸入裝置,資料是輸入給主機的。如果不是輸入型別端點,中斷型別端點,就返回一個錯誤。這個怎麼回事呢,怎麼知道你是不是中斷輸入端點呢,端點描述符裡面不是有個屬性嗎,屬性裡面就是表示它是什麼型別的,方向。


我們在我們自己的程式裡就不做判斷了,我們回到我們的主題,我們就認為就是一個滑鼠,



我們硬體相關的操作要用到USB匯流排驅動程式裡面的讀寫函式

我們只需要記住資料傳輸3要素,把這個三要素找出就可以實現這一點

1.源   在我們這裡是USB裝置的某個端點


這個就是源

我們來看看usb_rcvintpipe這個巨集


這個源是個整數,pipe_interrupt是指中斷型別端點,USB_DIR_IN是端點的方向。我們進入__create_pipe(dev,endpoint)這個巨集


devnum是裝置的地址,endpoint是端點的地址也是端點編號


2.目的

我們從USB裝置裡面讀資料,讀到哪裡去,肯定讀到緩衝區,但這個緩衝區肯定不能用kmallioc函式,

用這函式

返回一個void* 是個虛擬地址

最後一個引數是指的實體地址


3.長度就是我們的端點描述符最大包大小


使用我們三要素

怎麼用呢,看一下我們的例子


分配一個urb urb是什麼意思呢,就是USB請求快的意思 usb request block

然後使用這個3要素設定我們的urb  來看我們的例子程式




看看這個函式原型


第一個引數是urb,第二個引數是裝置,第三個引數是源,第四個引數是目的,第五個引數是長度 ,第6個引數是完成函式,第7個引數是給那個完成函式用的,我們不需要,第8個引數是查詢的頻率。

我們前面說過usb裝置不能打斷主機控制器,只能讓主機控制器查詢,不斷的去查詢,等有資料之後才能中斷CPU。當它得到資料之後,匯流排驅動程式就會呼叫這個complete_fn這個函式,查詢多頻繁呢就是int interval 。

端點描述符裡面有個binterval就是的



我們USB主機控制器,得到資料之後是往某個地方寫,但是我們主機控制器沒那麼聰明,所以我們要告訴它,例子裡面


第一句就是告訴實體地址,下面一句是設定某些標記


我們構造了URB 就要使用urb

怎麼使用urb


使用usb_submit_urb提交urb



usb滑鼠資料含義

我們前面說框架的時候說過,USB裝置驅動程式知道資料的含義,USB匯流排驅動程式提供識別裝置,給裝置找到驅動,提供讀寫函式,但是不知道資料的含義。這些資料需要由裝置驅動程式來解析,


data[0] bit 0表示左鍵,1表示按下,0表示鬆開

     bit 1表示右鍵,1表示按下,0表示鬆開

     bit  2表示中鍵    1表示按下,0表示鬆開



程式碼如下

#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>


static struct input_dev *usb_key;
static char * usb_buf;
static dma_addr_t usb_buf_phys;
static int len;
static struct urb *uk_urb;
static struct usb_device_id usbmouse_as_key_id_table[] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,USB_INTERFACE_PROTOCOL_MOUSE) },
{ } /* Terminating entry */
};


static void usbmouse_as_key_irq(struct urb *urb)
{
static unsigned char pre_val;
/* USB滑鼠資料含義
* data[0]: bit0-左鍵, 1-按下, 0-鬆開
*          bit1-右鍵, 1-按下, 0-鬆開
*          bit2-中鍵, 1-按下, 0-鬆開 
*/
if((pre_val & (1<<0)) != (usb_buf[0] & (1<<0)))
{
//左鍵發生了變化
input_event(usb_key, EV_KEY, KEY_L, (usb_buf[0] & (1<<0)) ? 1 : 0);
input_sync(usb_key);
}
if ((pre_val & (1<<1)) != (usb_buf[0] & (1<<1)))
{
/* 右鍵發生了變化 */
input_event(usb_key, EV_KEY, KEY_S, (usb_buf[0] & (1<<1)) ? 1 : 0);
input_sync(usb_key);
}
if ((pre_val & (1<<2)) != (usb_buf[0] & (1<<2)))
{
/* 中鍵發生了變化 */
input_event(usb_key, EV_KEY, KEY_ENTER, (usb_buf[0]  & (1<<2)) ? 1 : 0);
input_sync(usb_key);
}

pre_val = usb_buf[0];


/* 重新提交urb */
usb_submit_urb(uk_urb, GFP_KERNEL);
}


static int usbmouse_as_key_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;//源


interface = intf->cur_altsetting;


endpoint = &interface->endpoint[0].desc;
/*a.分配一個input_device結構體*/
usb_key=input_allocate_device();
/*b.設定*/
/*b.1能產生哪類事件*/
//能夠產生按鍵類事件
set_bit(EV_KEY,usb_key->evbit);
set_bit(EV_REP,usb_key->evbit);//能夠產生重複類事件,就是隻我們按下一個字母不動就會不斷的列印出來


/*b.2能產生這類事件的哪些事件*/
set_bit(KEY_L,usb_key->keybit);
set_bit(KEY_S,usb_key->keybit);
set_bit(KEY_ENTER,usb_key->keybit);


/*c.註冊*/
input_register_device(usb_key);
/*d.硬體相關的操作*/
/*資料傳輸3要素 源,目的,長度*/
/*1.源 :USB裝置的某個端點*/
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);


//長度 等於端點描述符的最大包大小
len=endpoint->wMaxPacketSize;


/*2.目的 */
usb_buf = usb_alloc_coherent(dev,len, GFP_ATOMIC, &usb_buf_phys);


//使用三要素
/*分配一個urb usb request block*/
uk_urb= usb_alloc_urb(0, GFP_KERNEL);
//使用3要素設定這個urb
usb_fill_int_urb(uk_urb, dev, pipe, usb_buf,len,usbmouse_as_key_irq,NULL, endpoint->bInterval);
uk_urb->transfer_dma = usb_buf_phys;
uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
//使用URB
usb_submit_urb(uk_urb, GFP_KERNEL);


return 0;
}


static void usbmouse_as_key_disconnect(struct usb_interface *intf)
{
struct usb_device *dev = interface_to_usbdev(intf);
usb_kill_urb(uk_urb);
usb_free_urb(uk_urb);
usb_free_coherent(dev, len, usb_buf, usb_buf_phys);
input_unregister_device(usb_key);
input_free_device(usb_key);




}
/*1.分配/設定usb_driver*/
static struct usb_driver usbmouse_as_key_driver = {
.name = "usbmouse_as_key",
.probe = usbmouse_as_key_probe,
.disconnect = usbmouse_as_key_disconnect,
.id_table = usbmouse_as_key_id_table,
};
static int usbmouse_as_key_init(void)
{
/*2.註冊usb_driver結構體*/
usb_register(&usbmouse_as_key_driver);
return 0;
}

static void usbmouse_as_key_exit(void)
{
usb_deregister(&usbmouse_as_key_driver);
}


module_init(usbmouse_as_key_init);
module_exit(usbmouse_as_key_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EIGHT");


測試結構如下圖







相關文章