1. 指定USB鍵盤驅(qū)動(dòng)所需的頭文件:
#include <linux/kernel.h>/*內(nèi)核頭文件,含有內(nèi)核一些常用函數(shù)的原型定義*/
- b ^$ i! [0 ^! F+ j9 G
#include <linux/slab.h>/*定義內(nèi)存分配的一些函數(shù)*/
#include <linux/module.h>/*模塊編譯必須的頭文件*/
#include <linux/input.h>/*輸入設(shè)備相關(guān)函數(shù)的頭文件*/
5 i4 ]& H; U3 a2 u' ?* A% {2 M
#include <linux/init.h>/*linux初始化模塊函數(shù)定義*/
#include <linux/usb.h> /*USB設(shè)備相關(guān)函數(shù)定義*/
# A- B3 ^7 l ~: b) E6 T
2. 定義鍵盤碼表數(shù)組:
/*使用第一套鍵盤掃描碼表:A-1E;B-30;C-2E…*/
static unsigned char usb_kbd_keycode[256] = {
5 K1 ]8 I% v8 o
0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
9 l$ @+ O4 f' u9 D8 V
105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! U& h2 }, O U1 d0 q: n- Z% h+ `
29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
5 _$ X& }( G% {' j k1 [! l, P
150,158,159,128,136,177,178,176,142,152,173,140
) C2 q0 z4 x9 M, Z. h& {+ E
}; 5 E+ q5 ?$ d8 G& s
3. 編寫設(shè)備ID表: N$ p" o: c( a+ n6 N; c- j6 L
static struct usb_device_id usb_kbd_id_table [] = {
{ USB_INTERFACE_INFO(3, 1, 1) },/*3,1,1分別表示接口類,接口子類,接口協(xié)議;3,1,1為鍵盤接口類;鼠標(biāo)為3,1,2*/
$ n* x- f$ j% a0 U
{ } /* Terminating entry */
8 S# f9 C/ \! ^5 g
};
MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);/*指定設(shè)備ID表*/ 3 n- {* {; E6 _3 O& q# s
4. 定義USB鍵盤結(jié)構(gòu)體:
struct usb_kbd {
struct input_dev *dev; /*定義一個(gè)輸入設(shè)備*/
8 i: g! U& F6 z2 F6 c
struct usb_device *usbdev;/*定義一個(gè)usb設(shè)備*/
unsigned char old[8]; /*按鍵離開時(shí)所用之數(shù)據(jù)緩沖區(qū)*/
struct urb *irq/*usb鍵盤之中斷請(qǐng)求塊*/, *led/*usb鍵盤之指示燈請(qǐng)求塊*/;
unsigned char newleds;/*目標(biāo)指定燈狀態(tài)*/
/ p' {# l$ d" k+ U! n, m8 P: j; @8 u
char name[128];/*存放廠商名字及產(chǎn)品名字*/
char phys[64];/*設(shè)備之節(jié)點(diǎn)*/
unsigned char *new;/*按鍵按下時(shí)所用之?dāng)?shù)據(jù)緩沖區(qū)*/
struct usb_ctrlrequest *cr;/*控制請(qǐng)求結(jié)構(gòu)*/
0 p1 Q' B8 H3 v8 D9 {; c# V4 Z$ t
unsigned char *leds;/*當(dāng)前指示燈狀態(tài)*/
dma_addr_t cr_dma; /*控制請(qǐng)求DMA緩沖地址*/
dma_addr_t new_dma; /*中斷urb會(huì)使用該DMA緩沖區(qū)*/
dma_addr_t leds_dma; /*指示燈DAM緩沖地址*/
8 X8 @, G2 N9 I' i6 z/ w! v
};
5. 編寫USB鍵盤驅(qū)動(dòng)結(jié)構(gòu)(任何一個(gè)LINUX下的驅(qū)動(dòng)都有個(gè)類似的驅(qū)動(dòng)結(jié)構(gòu)):
/*USB鍵盤驅(qū)動(dòng)結(jié)構(gòu)體*/
, C: l6 r. C& V3 r6 u
static struct usb_driver usb_kbd_driver = {
.name = "usbkbd",/*驅(qū)動(dòng)名字*/
.probe = usb_kbd_probe,/*驅(qū)動(dòng)探測(cè)函數(shù),加載時(shí)用到*/
1 A% |! S8 [$ N0 {, L! v4 Z! F
.disconnect = usb_kbd_disconnect,/*驅(qū)動(dòng)斷開函數(shù),在卸載時(shí)用到*/
! L4 E C/ O% `. t$ ?! o3 o% u. Y
.id_table = usb_kbd_id_table,/*驅(qū)動(dòng)設(shè)備ID表,用來指定設(shè)備或接口*/
' q* g' l! H2 {+ t3 \
};
, Z, F" Y' v$ K b
6. 編寫模塊加載函數(shù)(每個(gè)驅(qū)動(dòng)都會(huì)有一個(gè)加載函數(shù),由module_init調(diào)用):
/*驅(qū)動(dòng)程序生命周期的開始點(diǎn),向 USB core 注冊(cè)這個(gè)鍵盤驅(qū)動(dòng)程序。*/
static int __init usb_kbd_init(void)
{
# A" x8 L; p0 B. v" y" U
int result = usb_register(&usb_kbd_driver);/*注冊(cè)USB鍵盤驅(qū)動(dòng)*/
if (result == 0) /*注冊(cè)失敗*/
info(DRIVER_VERSION ":" DRIVER_DESC);
7 X$ [2 l5 R3 A0 h: f! I" X( E6 u
return result;
}
7. 編寫模塊卸載函數(shù)(每個(gè)驅(qū)動(dòng)都會(huì)有一個(gè)卸載函數(shù),由module_exit調(diào)用): , t" e1 X" f3 b) A
/* 驅(qū)動(dòng)程序生命周期的結(jié)束點(diǎn),向 USB core 注銷這個(gè)鍵盤驅(qū)動(dòng)程序。 */
static void __exit usb_kbd_exit(void)
% p1 Z! u. ~9 X2 `+ t6 T
{
printk("SUNWILL-USBKBD:usb_kbd_exit begin...\n");
usb_deregister(&usb_kbd_driver);/*注銷USB鍵盤驅(qū)動(dòng)*/
* @; I% {* c( [9 @
} 2 l! F j5 t& `; \ ?
8. 指定模塊初始化函數(shù)(被指定的函數(shù)在insmod驅(qū)動(dòng)時(shí)調(diào)用): b2 |. i4 J+ C3 A2 `% N
: e+ ^" z8 n) [+ P& }
module_init(usb_kbd_init);
9. 指定模塊退出函數(shù)(被指定的函數(shù)在rmmod驅(qū)動(dòng)時(shí)調(diào)用):
module_exit(usb_kbd_exit);
10. 編寫中斷請(qǐng)求處理函數(shù): ) i% U0 o, F: x1 g: o. v4 c
4 m4 i5 P% d. U: v
/*中斷請(qǐng)求處理函數(shù),有中斷請(qǐng)求到達(dá)時(shí)調(diào)用該函數(shù)*/
1 T* B5 M6 i- @
static void usb_kbd_irq(struct urb *urb, struct pt_regs *regs)
5 z9 Z- H& I# T3 c H" g
{
struct usb_kbd *kbd = urb->context;
9 {/ ^- ^. i2 R4 Z$ b% ?
int i;
: ]$ Y" W) H: I3 Y: M, e+ X. {0 |7 q
switch (urb->status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
case -ENOENT:
" ^- t/ Q/ q! R: q- x [
case -ESHUTDOWN:
return;
6 J& V# T" |" K! O$ ~
/* -EPIPE: should clear the halt */
default: /* error */
goto resubmit;
' x. f0 |2 \/ Y" |" K r
}
//input_regs(kbd->dev, regs);
( l9 K& G# K2 A; U; s) i, q. k
C* P5 E/ M. z) a! W3 a: C; u5 p5 ~! O9 M
/*不知道其用意, 注釋掉該部分仍可正常工作*/
2 n7 m9 O6 B' k0 t' r
for (i = 0; i < 8; i++)/*8次的值依次是:29-42-56-125-97-54-100-126*/
# S Y) m! d+ `4 {! X# N2 m% [1 ~0 Z$ l( A
{
input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
, X' ~6 h( y$ l7 h
}
/*若同時(shí)只按下1個(gè)按鍵則在第[2]個(gè)字節(jié),若同時(shí)有兩個(gè)按鍵則第二個(gè)在第[3]字節(jié),類推最多可有6個(gè)按鍵同時(shí)按下*/
+ S9 ?5 }+ W" X7 A5 }
for (i = 2; i < 8; i++) {
; l0 c, V& M6 n7 \
/*獲取鍵盤離開的中斷*/
if (kbd->old > 3 && memscan(kbd->new + 2, kbd->old, 6) == kbd->new + 8) {/*同時(shí)沒有該KEY的按下狀態(tài)*/
2 F3 e3 g8 X1 x% H7 i
if (usb_kbd_keycode[kbd->old])
) a, d$ X: V4 F! ] k. t9 j4 P( V
{
input_report_key(kbd->dev, usb_kbd_keycode[kbd->old], 0);
/ }9 Y) _4 b, _* C1 s* S/ g C, e4 d
}
else
info("Unknown key (scancode %#x) released.", kbd->old);
. s9 R$ x5 N' q
}
( L) k' C. C. C7 C4 P/ R
/*獲取鍵盤按下的中斷*/
/ c" I1 m1 S6 X0 }! a1 {% {
if (kbd->new > 3 && memscan(kbd->old + 2, kbd->new, 6) == kbd->old + 8) {/*同時(shí)沒有該KEY的離開狀態(tài)*/
if (usb_kbd_keycode[kbd->new])
; `/ S/ c5 h% h, T
{
' T y8 p/ p3 H) g' N1 p, B
input_report_key(kbd->dev, usb_kbd_keycode[kbd->new], 1);
- }. S, u" U$ v3 ~
}
2 \/ B( ~4 _6 |; l. X4 _
else
6 s2 a$ A5 ?, J' b7 y# t
info("Unknown key (scancode %#x) pressed.", kbd->new);
}
}
/*同步設(shè)備,告知事件的接收者驅(qū)動(dòng)已經(jīng)發(fā)出了一個(gè)完整的報(bào)告*/
& R% M$ i8 c& W) w
input_sync(kbd->dev);
memcpy(kbd->old, kbd->new, 8);/*防止未松開時(shí)被當(dāng)成新的按鍵處理*/
6 V$ l/ N0 r9 i1 S
resubmit:
i = usb_submit_urb (urb, GFP_ATOMIC);/*發(fā)送USB請(qǐng)求塊*/
if (i)
# F6 T# }' A+ C' v' ^
err ("can't resubmit intr, %s-%s/input0, status %d",
. Q" r- c% t- z0 ~2 S$ u
kbd->usbdev->bus->bus_name,
& M4 r1 H# Z/ a, u$ l
kbd->usbdev->devpath, i);
} ) M" s T9 C8 z% Q
11. 編寫事件處理函數(shù):
/*事件處理函數(shù)*/
3 [9 w, B6 ]8 D5 t; R* |
static int usb_kbd_event(struct input_dev *dev, unsigned int type,
4 @3 K) J; |. k
unsigned int code, int value)
# r8 N6 a. h0 K; M: n) J/ K' e
{
struct usb_kbd *kbd = dev->private;
if (type != EV_LED) /*不支持LED事件 */
return -1;
/*獲取指示燈的目標(biāo)狀態(tài)*/
kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
(!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
(!!test_bit(LED_NUML, dev->led));
# z- U5 G# d$ P+ t: v
if (kbd->led->status == -EINPROGRESS)
return 0;
7 b. w4 f3 o" g
/*指示燈狀態(tài)已經(jīng)是目標(biāo)狀態(tài)則不需要再做任何操作*/
0 d; ~- m: t$ F, l5 Y5 P1 ]
if (*(kbd->leds) == kbd->newleds)
, J" U C+ o9 ^1 \
return 0;
/ r; I2 R/ | G2 Y
*(kbd->leds) = kbd->newleds;
kbd->led->dev = kbd->usbdev;
2 V( K; p- {9 _* C/ R
/*發(fā)送usb請(qǐng)求塊*/
if (usb_submit_urb(kbd->led, GFP_ATOMIC))
6 X. `: n, p$ H
err("usb_submit_urb(leds) failed");
, F# N( c& y2 V; A
return 0;
: Z2 K0 Q' ^" ]' S: {
}
12. 編寫LED事件處理函數(shù):
/*接在event之后操作,該功能其實(shí)usb_kbd_event中已經(jīng)有了,該函數(shù)的作用可能是防止event的操作失敗,一般注釋掉該函數(shù)中的所有行都可以正常工作*/
static void usb_kbd_led(struct urb *urb, struct pt_regs *regs)
- @8 [0 V" Z8 }7 b& S2 `! c) S
{
struct usb_kbd *kbd = urb->context;
: P9 P6 Y3 `. f" M
if (urb->status)
warn("led urb status %d received", urb->status);
' Q: l8 [6 E! n" \: L: M; U3 w, q
if (*(kbd->leds) == kbd->newleds)/*指示燈狀態(tài)已經(jīng)是目標(biāo)狀態(tài)則不需要再做任何操作*/
return;
c& ]6 l' @5 y9 y( t, I
*(kbd->leds) = kbd->newleds;
( M$ p; s1 _$ f: b0 S* T
kbd->led->dev = kbd->usbdev;
if (usb_submit_urb(kbd->led, GFP_ATOMIC))
# Y0 z+ p1 T1 r' m
err("usb_submit_urb(leds) failed");
}
13. 編寫USB設(shè)備打開函數(shù): % L8 _# ~+ Q; h8 V! S& j
/*打開鍵盤設(shè)備時(shí),開始提交在 probe 函數(shù)中構(gòu)建的 urb,進(jìn)入 urb 周期。 */
0 o* G; B9 U- F- D7 {- r
static int usb_kbd_open(struct input_dev *dev)
( X' B5 S) F; k- {
{
0 F7 ^% g8 C: [# w6 E
struct usb_kbd *kbd = dev->private;
kbd->irq->dev = kbd->usbdev;
if (usb_submit_urb(kbd->irq, GFP_KERNEL))
return -EIO;
0 [& d( }( [% N/ K
return 0;
} , [8 \/ P' x9 _& |* ]0 W
14. 編寫USB設(shè)備關(guān)閉函數(shù)
/*關(guān)閉鍵盤設(shè)備時(shí),結(jié)束 urb 生命周期。 */
+ W/ T0 E+ j- J, e! J
static void usb_kbd_close(struct input_dev *dev)
{
( F' Z/ q( h; `/ z0 f0 Q1 _; e
struct usb_kbd *kbd = dev->private;
0 @( m1 I9 ]+ p* T7 |
usb_kill_urb(kbd->irq); /*取消kbd->irq這個(gè)usb請(qǐng)求塊*/
} 0 @* c% M% y; R; N; W- p
15. 創(chuàng)建URB * }: _6 i# P+ |/ f) e
/*分配URB內(nèi)存空間即創(chuàng)建URB*/
. D5 ~8 t6 g: j
static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
{
if (!(kbd->irq = usb_alloc_urb(0, GFP_KERNEL)))
return -1;
if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL)))
return -1;
: U5 y; v$ z9 G6 L$ `$ n
if (!(kbd->new = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &kbd->new_dma)))
& u) L! ~" E0 t, y) k* G
return -1;
# I" m* h0 n/ X
if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), GFP_ATOMIC, &kbd->cr_dma)))
9 R1 {# D4 N5 H, Y5 N' Q+ P# V8 H6 ~
return -1;
if (!(kbd->leds = usb_buffer_alloc(dev, 1, GFP_ATOMIC, &kbd->leds_dma)))
return -1;
return 0;
} & a. r$ G4 ]4 O8 e
16. 銷毀URB . i# s- u# u$ G8 \
/*釋放URB內(nèi)存空間即銷毀URB*/
8 b; X3 r9 ~/ }3 j
static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
{
/ _: t2 ~1 d6 A9 S
if (kbd->irq)
usb_free_urb(kbd->irq);
if (kbd->led)
usb_free_urb(kbd->led);
if (kbd->new)
1 H/ f4 b: b0 y3 k% e9 L
usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
/ @; f$ W4 z8 A4 v0 [" V+ s
if (kbd->cr)
usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);
6 {& E3 v* q. V2 v* y# u
if (kbd->leds)
usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
& l2 r% j7 Z6 `" p/ H
}
17. USB鍵盤驅(qū)動(dòng)探測(cè)函數(shù): 9 {3 `6 X& N+ I, \6 G3 C5 y
/*USB鍵盤驅(qū)動(dòng)探測(cè)函數(shù),初始化設(shè)備并指定一些處理函數(shù)的地址*/
static int usb_kbd_probe(struct usb_interface *iface,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(iface);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
. ~! k+ q3 h4 G' J. p/ I! s s
struct usb_kbd *kbd;
' W- S2 g" l7 r% Y9 I4 j* l
struct input_dev *input_dev;
1 O$ O# ^; S; ~. E
int i, pipe, maxp;
1 u0 j2 [) f+ @& L
/*當(dāng)前選擇的interface*/
interface = iface->cur_altsetting;
, E0 C) A: W- i2 h: Z- K. {8 o
/*鍵盤只有一個(gè)中斷IN端點(diǎn)*/
. H7 ]3 D U; c7 ^3 f) E
if (interface->desc.bNumEndpoints != 1)
return -ENODEV;
; F% V6 `. @- [- i* S/ h# W+ y/ f
/*獲取端點(diǎn)描述符*/
; f H$ Q5 q. d) j* r$ c
endpoint = &interface->endpoint[0].desc;
v0 Y- S* C+ ?+ B7 \4 H% x* {
if (!(endpoint->bEndpointAddress & USB_DIR_IN))
return -ENODEV;
. `: a$ m/ s# {2 R; v+ V
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
return -ENODEV;
3 |5 t" B8 N/ E
/*將endpoint設(shè)置為中斷IN端點(diǎn)*/
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
/*獲取包的最大值*/
! t4 D) w2 A" f3 e' W
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
2 A& t8 l1 m6 y( N: t1 @6 f/ I
kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
input_dev = input_allocate_device();
if (!kbd || !input_dev)
n A( g6 h d3 ^3 @, o2 z. [# Y- f
goto fail1;
4 f3 P8 p9 u4 i" i( _
if (usb_kbd_alloc_mem(dev, kbd))
goto fail2;
2 I5 k4 X. V' ~; S, X7 @
/* 填充 usb 設(shè)備結(jié)構(gòu)體和輸入設(shè)備結(jié)構(gòu)體 */
kbd->usbdev = dev;
kbd->dev = input_dev;
/*以"廠商名字 產(chǎn)品名字"的格式將其寫入kbd->name*/
if (dev->manufacturer)
+ y/ a6 z( T# y- L7 H8 B
strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
8 P4 ^( k3 Q/ |( }9 n! c
8 u" f& f+ \3 x/ p8 r+ d
if (dev->product) {
' S; _( i4 m; f
if (dev->manufacturer)
strlcat(kbd->name, " ", sizeof(kbd->name));
strlcat(kbd->name, dev->product, sizeof(kbd->name));
}
/*檢測(cè)不到廠商名字*/
+ j# S3 x0 d: i- W
if (!strlen(kbd->name))
v5 e+ m6 v7 h5 U$ b2 r, Q" I
snprintf(kbd->name, sizeof(kbd->name),
"USB HIDBP Keyboard %04x:%04x",
\+ q% m+ R3 E& d9 X2 [
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
7 J! A- D& w' k0 b3 R' b& O1 P
/*設(shè)備鏈接地址*/
; U: ^, j1 j! |) T4 g, P1 R/ N+ d! E
usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
strlcpy(kbd->phys, "/input0", sizeof(kbd->phys));
1 ]8 D# W1 Q0 u0 k# i
input_dev->name = kbd->name;
, r) \ N- r* D2 b0 V; [
; I2 w; @( \* @, ]
input_dev->phys = kbd->phys;
2 O* k) H* w8 o6 g. |2 ^0 q
/*
! k% }9 U+ w$ x7 ~6 @
* input_dev 中的 input_id 結(jié)構(gòu)體,用來存儲(chǔ)廠商、設(shè)備類型和設(shè)備的編號(hào),這個(gè)函數(shù)是將設(shè)備描述符
* 中的編號(hào)賦給內(nèi)嵌的輸入子系統(tǒng)結(jié)構(gòu)體
! {6 c- V3 y) p" S5 N
*/
: {% W( H# H' r1 E$ \* L/ \' A2 z
usb_to_input_id(dev, &input_dev->id);
3 [, a# {7 w4 v6 j5 h, E
/* cdev 是設(shè)備所屬類別(class device) */
. q, y" t. p+ ?0 Y
input_dev->cdev.dev = &iface->dev;
1 h! n0 q% ^6 x% m0 ^
/* input_dev 的 private 數(shù)據(jù)項(xiàng)用于表示當(dāng)前輸入設(shè)備的種類,這里將鍵盤結(jié)構(gòu)體對(duì)象賦給它 */
input_dev->private = kbd;
* Q* X# |# s4 n( W2 |
input_dev->evbit[0] = BIT(EV_KEY)/*鍵碼事件*/ | BIT(EV_LED)/*LED事件*/ | BIT(EV_REP)/*自動(dòng)重覆數(shù)值*/;
input_dev->ledbit[0] = BIT(LED_NUML)/*數(shù)字燈*/ | BIT(LED_CAPSL)/*大小寫燈*/ | BIT(LED_SCROLLL)/*滾動(dòng)燈*/ | BIT(LED_COMPOSE) | BIT(LED_KANA);
# ]+ D' g- O; S' A' W$ u7 p
for (i = 0; i < 255; i++)
# d" N0 G5 B; n% H" P7 E. O' M5 o
set_bit(usb_kbd_keycode, input_dev->keybit);
clear_bit(0, input_dev->keybit);
- X; L( q7 Q. c! W
- ]/ ?0 y' C7 d9 B: Z" w
input_dev->event = usb_kbd_event;/*注冊(cè)事件處理函數(shù)入口*/
input_dev->open = usb_kbd_open;/*注冊(cè)設(shè)備打開函數(shù)入口*/
) `4 c- M3 t+ q3 r' x' B: D
input_dev->close = usb_kbd_close;/*注冊(cè)設(shè)備關(guān)閉函數(shù)入口*/
2 }. l" B( I) Q9 m+ I, n: G
/*初始化中斷URB*/
) F- R% x( u( ]2 i
usb_fill_int_urb(kbd->irq/*初始化kbd->irq這個(gè)urb*/, dev/*這個(gè)urb要發(fā)送到dev這個(gè)設(shè)備*/, pipe/*這個(gè)urb要發(fā)送到pipe這個(gè)端點(diǎn)*/,
kbd->new/*指向緩沖的指針*/, (maxp > 8 ? 8 : maxp)/*緩沖長度*/,
! t2 g* U) T7 j6 D
usb_kbd_irq/*這個(gè)urb完成時(shí)調(diào)用的處理函數(shù)*/, kbd/*指向數(shù)據(jù)塊的指針,被添加到這個(gè)urb結(jié)構(gòu)可被完成處理函數(shù)獲取*/, endpoint->bInterval/*urb應(yīng)當(dāng)被調(diào)度的間隔*/);
3 q/ G# Q+ I7 k2 r
kbd->irq->transfer_dma = kbd->new_dma; /*指定urb需要傳輸?shù)腄MA緩沖區(qū)*/
4 ~0 D) y' K* ^, n
kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;/*本urb有一個(gè)DMA緩沖區(qū)需要傳輸*/
1 d+ ]/ |: U1 x$ b. G7 H
kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;/*操作的是類接口對(duì)象*/
( |4 A: X3 @9 o* o# D- v1 Y0 s
kbd->cr->bRequest = 0x09; /*中斷請(qǐng)求編號(hào)*/
kbd->cr->wValue = cpu_to_le16(0x200);
kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);/*接口號(hào)*/
6 V( k0 o2 Q4 }$ M
kbd->cr->wLength = cpu_to_le16(1);/*數(shù)據(jù)傳輸階段傳輸多少個(gè)bytes*/
5 b6 c0 J$ c3 X; t
/*初始化控制URB*/
usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
(void *) kbd->cr, kbd->leds, 1,
usb_kbd_led, kbd);
kbd->led->setup_dma = kbd->cr_dma;
$ d9 \( r3 \& o6 j
kbd->led->transfer_dma = kbd->leds_dma;
8 [/ v: p" l! i5 N3 P8 {/ H
kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP/*如果使用DMA傳輸則urb中setup_dma指針?biāo)赶虻木彌_區(qū)是DMA緩沖區(qū)而不是setup_packet所指向的緩沖區(qū)*/);
( ?9 \4 P: i. `
/*注冊(cè)輸入設(shè)備*/
input_register_device(kbd->dev);
) Y" y6 u4 K1 A0 v4 M
usb_set_intfdata(iface, kbd);/*設(shè)置接口私有數(shù)據(jù)*/
return 0;
' t: s8 V4 O4 Z1 X% u
fail2: usb_kbd_free_mem(dev, kbd);
fail1: input_free_device(input_dev);
) ~% P0 \, T, c8 j; y3 H
kfree(kbd);
return -ENOMEM;
} 6 N' ^+ s- f% }8 D
18. 編寫斷開連接的函數(shù): 7 L: s) y1 n+ s: g: K
/*斷開連接(如鍵盤設(shè)備拔出)的處理函數(shù)*/
2 V- F6 ?+ e1 B- ^, O
static void usb_kbd_disconnect(struct usb_interface *intf)
. {$ Q* n: Q2 A6 d
{
~1 e. ?7 p4 k9 b& _# I
struct usb_kbd *kbd = usb_get_intfdata (intf);/*獲取接口的私有數(shù)據(jù)給kbd*/
+ X: b A: E% @: w6 S# z2 T
usb_set_intfdata(intf, NULL);/*設(shè)置接口的私有數(shù)據(jù)為NULL*/
if (kbd) {
usb_kill_urb(kbd->irq);/*取消中斷請(qǐng)求*/
input_unregister_device(kbd->dev);/*注銷設(shè)備*/
. o; ^/ X9 G: r* C- X! e
usb_kbd_free_mem(interface_to_usbdev(intf), kbd);/*釋放內(nèi)存空間*/
% o# D- J8 m* t
kfree(kbd);
}
} $ N8 e, G, z3 ~$ c4 L
19. 編寫Makefile:
##############################
) B- T/ q/ m( E* | e
#usbkdb Makefile for linux
/ V2 W, _$ q/ Z# b& e$ F6 X
##############################
; i% d5 j0 M7 k W9 [; Q
obj-m:=usbkbd.o
7 l; F" C1 p# H: O) N* o" _1 V
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
6 w4 h* }) I, }4 Y2 P3 o. F3 A
PWD:=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules 4 o7 g9 m1 B) {3 r6 p: