一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

[轉(zhuǎn)貼] 編寫Linux下的USB鍵盤驅(qū)(一) - linux - cheney1982

 昵稱1542620 2010-05-29
[轉(zhuǎn)貼] 編寫Linux下的USB鍵盤驅(qū)(一)
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:

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    年轻女房东2中文字幕| 日韩精品视频香蕉视频| 国产在线一区中文字幕| 国内精品一区二区欧美| 精品高清美女精品国产区| 亚洲精品中文字幕一二三| 九九热在线视频观看最新| 国产a天堂一区二区专区| 美日韩一区二区精品系列| 99久久婷婷国产亚洲综合精品 | 国产视频在线一区二区| 日韩精品小视频在线观看| 日韩成人午夜福利免费视频| 激情爱爱一区二区三区| 91久久精品中文内射| 五月天丁香婷婷一区二区| 九九热在线视频精品免费| 一区二区三区人妻在线| 欧洲日韩精品一区二区三区| 一级片黄色一区二区三区| 在线免费国产一区二区| 极品少妇嫩草视频在线观看| 日韩欧美在线看一卡一卡| 亚洲熟女诱惑一区二区| 国产级别精品一区二区视频 | 欧美激情一区二区亚洲专区| 99在线视频精品免费播放| 国产一区日韩二区欧美| 91精品欧美综合在ⅹ| 午夜精品成年人免费视频| 午夜福利直播在线视频| 91久久精品中文内射| 中文字幕人妻综合一区二区| 日本一区不卡在线观看| 91亚洲国产日韩在线| 精品女同在线一区二区| 国产一区二区三区丝袜不卡| 91精品国自产拍老熟女露脸| 黄色美女日本的美女日人| av在线免费播放一区二区| 色丁香之五月婷婷开心|