亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 22585 | 回復(fù): 9
打印 上一主題 下一主題

Linux下的硬件驅(qū)動(dòng)——USB設(shè)備(下)(驅(qū)動(dòng)開發(fā)部分) [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2003-07-18 16:20 |只看該作者 |倒序?yàn)g覽
趙明(carl__zhao@163.com)
聯(lián)想軟件設(shè)計(jì)中心嵌入式研發(fā)處系統(tǒng)設(shè)計(jì)工程師
2003年7月
USB骨架程序(usb-skeleton),是USB驅(qū)動(dòng)程序的基礎(chǔ),通過對(duì)它源碼的學(xué)習(xí)和理解,可以使我們迅速地了解USB驅(qū)動(dòng)架構(gòu),迅速地開發(fā)我們自己的USB硬件的驅(qū)動(dòng)。
前言
在上篇《Linux下的硬件驅(qū)動(dòng)--USB設(shè)備(上)(驅(qū)動(dòng)配制部分)》中,我們知道了在Linux下如何去使用一些最常見的USB設(shè)備。但對(duì)于做系統(tǒng)設(shè)計(jì)的程序員來說,這是遠(yuǎn)遠(yuǎn)不夠的,我們還需要具有驅(qū)動(dòng)程序的閱讀、修改和開發(fā)能力。在此下篇中,就是要通過簡單的USB驅(qū)動(dòng)的例子,隨您一起進(jìn)入U(xiǎn)SB驅(qū)動(dòng)開發(fā)的世界。
USB驅(qū)動(dòng)開發(fā)
在掌握了USB設(shè)備的配置后,對(duì)于程序員,我們就可以嘗試進(jìn)行一些簡單的USB驅(qū)動(dòng)的修改和開發(fā)了。這一段落,我們會(huì)講解一個(gè)最基礎(chǔ)USB框架的基礎(chǔ)上,做兩個(gè)小的USB驅(qū)動(dòng)的例子。
USB骨架
在Linux kernel源碼目錄中driver/usb/usb-skeleton.c為我們提供了一個(gè)最基礎(chǔ)的USB驅(qū)動(dòng)程序。我們稱為USB骨架。通過它我們僅需要修改極少的部分,就可以完成一個(gè)USB設(shè)備的驅(qū)動(dòng)。我們的USB驅(qū)動(dòng)開發(fā)也是從她開始的。
那些linux下不支持的USB設(shè)備幾乎都是生產(chǎn)廠商特定的產(chǎn)品。如果生產(chǎn)廠商在他們的產(chǎn)品中使用自己定義的協(xié)議,他們就需要為此設(shè)備創(chuàng)建特定的驅(qū)動(dòng)程序。當(dāng)然我們知道,有些生產(chǎn)廠商公開他們的USB協(xié)議,并幫助Linux驅(qū)動(dòng)程序的開發(fā),然而有些生產(chǎn)廠商卻根本不公開他們的USB協(xié)議。因?yàn)槊恳粋(gè)不同的協(xié)議都會(huì)產(chǎn)生一個(gè)新的驅(qū)動(dòng)程序,所以就有了這個(gè)通用的USB驅(qū)動(dòng)骨架程序, 它是以pci 骨架為模板的。
如果你準(zhǔn)備寫一個(gè)linux驅(qū)動(dòng)程序,首先要熟悉USB協(xié)議規(guī)范。USB主頁上有它的幫助。一些比較典型的驅(qū)動(dòng)可以在上面發(fā)現(xiàn),同時(shí)還介紹了USB urbs的概念,而這個(gè)是usb驅(qū)動(dòng)程序中最基本的。
Linux USB 驅(qū)動(dòng)程序需要做的第一件事情就是在Linux USB 子系統(tǒng)里注冊(cè),并提供一些相關(guān)信息,例如這個(gè)驅(qū)動(dòng)程序支持那種設(shè)備,當(dāng)被支持的設(shè)備從系統(tǒng)插入或拔出時(shí),會(huì)有哪些動(dòng)作。所有這些信息都傳送到USB 子系統(tǒng)中,在usb骨架驅(qū)動(dòng)程序中是這樣來表示的:
static struct usb_driver skel_driver = {
     name:        "skeleton",
     probe:       skel_probe,
     disconnect:  skel_disconnect,
     fops:        &skel_fops,
     minor:       USB_SKEL_MINOR_BASE,
     id_table:    skel_table,
};
變量name是一個(gè)字符串,它對(duì)驅(qū)動(dòng)程序進(jìn)行描述。probe 和disconnect 是函數(shù)指針,當(dāng)設(shè)備與在id_table 中變量信息匹配時(shí),此函數(shù)被調(diào)用。
fops和minor變量是可選的。大多usb驅(qū)動(dòng)程序鉤住另外一個(gè)驅(qū)動(dòng)系統(tǒng),例如SCSI,網(wǎng)絡(luò)或者tty子系統(tǒng)。這些驅(qū)動(dòng)程序在其他驅(qū)動(dòng)系統(tǒng)中注冊(cè),同時(shí)任何用戶空間的交互操作通過那些接口提供,比如我們把SCSI設(shè)備驅(qū)動(dòng)作為我們USB驅(qū)動(dòng)所鉤住的另外一個(gè)驅(qū)動(dòng)系統(tǒng),那么我們此USB設(shè)備的read、write等操作,就相應(yīng)按SCSI設(shè)備的read、write函數(shù)進(jìn)行訪問。但是對(duì)于掃描儀等驅(qū)動(dòng)程序來說,并沒有一個(gè)匹配的驅(qū)動(dòng)系統(tǒng)可以使用,那我們就要自己處理與用戶空間的read、write等交互函數(shù)。Usb子系統(tǒng)提供一種方法去注冊(cè)一個(gè)次設(shè)備號(hào)和file_operations函數(shù)指針,這樣就可以與用戶空間實(shí)現(xiàn)方便地交互。
USB骨架程序的關(guān)鍵幾點(diǎn)如下:
1.        USB驅(qū)動(dòng)的注冊(cè)和注銷
Usb驅(qū)動(dòng)程序在注冊(cè)時(shí)會(huì)發(fā)送一個(gè)命令給usb_register,通常在驅(qū)動(dòng)程序的初始化函數(shù)里。
當(dāng)要從系統(tǒng)卸載驅(qū)動(dòng)程序時(shí),需要注銷usb子系統(tǒng)。即需要usb_unregister 函數(shù)處理:
static void __exit usb_skel_exit(void)
{
   /* deregister this driver with the USB subsystem */
   usb_deregister(&skel_driver);
}
module_exit(usb_skel_exit);

當(dāng)usb設(shè)備插入時(shí),為了使linux-hotplug(Linux中PCI、USB等設(shè)備熱插拔支持)系統(tǒng)自動(dòng)裝載驅(qū)動(dòng)程序,你需要?jiǎng)?chuàng)建一個(gè)MODULE_DEVICE_TABLE。代碼如下(這個(gè)模塊僅支持某一特定設(shè)備):
/* table of devices that work with this driver */
static struct usb_device_id skel_table [] = {
    { USB_DEVICE(USB_SKEL_VENDOR_ID,
      USB_SKEL_PRODUCT_ID) },
    { }                      /* Terminating entry */
};

MODULE_DEVICE_TABLE (usb, skel_table);

USB_DEVICE宏利用廠商ID和產(chǎn)品ID為我們提供了一個(gè)設(shè)備的唯一標(biāo)識(shí)。當(dāng)系統(tǒng)插入一個(gè)ID匹配的USB設(shè)備到USB總線時(shí),驅(qū)動(dòng)會(huì)在USB core中注冊(cè)。驅(qū)動(dòng)程序中probe 函數(shù)也就會(huì)被調(diào)用。usb_device 結(jié)構(gòu)指針、接口號(hào)和接口ID都會(huì)被傳遞到函數(shù)中。
static void * skel_probe(struct usb_device *dev,
unsigned int ifnum, const struct usb_device_id *id)
驅(qū)動(dòng)程序需要確認(rèn)插入的設(shè)備是否可以被接受,如果不接受,或者在初始化的過程中發(fā)生任何錯(cuò)誤,probe函數(shù)返回一個(gè)NULL值。否則返回一個(gè)含有設(shè)備驅(qū)動(dòng)程序狀態(tài)的指針。通過這個(gè)指針,就可以訪問所有結(jié)構(gòu)中的回調(diào)函數(shù)。
在骨架驅(qū)動(dòng)程序里,最后一點(diǎn)是我們要注冊(cè)devfs。我們創(chuàng)建一個(gè)緩沖用來保存那些被發(fā)送給usb設(shè)備的數(shù)據(jù)和那些從設(shè)備上接受的數(shù)據(jù),同時(shí)USB urb 被初始化,并且我們?cè)赿evfs子系統(tǒng)中注冊(cè)設(shè)備,允許devfs用戶訪問我們的設(shè)備。注冊(cè)過程如下:

/* initialize the devfs node for this device
   and register it */
sprintf(name, "skel%d", skel->;minor);
skel->;devfs = devfs_register
              (usb_devfs_handle, name,
               DEVFS_FL_DEFAULT, USB_MAJOR,
               USB_SKEL_MINOR_BASE + skel->;minor,
               S_IFCHR | S_IRUSR | S_IWUSR |
               S_IRGRP | S_IWGRP | S_IROTH,
               &skel_fops, NULL);
如果devfs_register函數(shù)失敗,不用擔(dān)心,devfs子系統(tǒng)會(huì)將此情況報(bào)告給用戶。
當(dāng)然最后,如果設(shè)備從usb總線拔掉,設(shè)備指針會(huì)調(diào)用disconnect 函數(shù)。驅(qū)動(dòng)程序就需要清除那些被分配了的所有私有數(shù)據(jù)、關(guān)閉urbs,并且從devfs上注銷調(diào)自己。

/* remove our devfs node */
devfs_unregister(skel->;devfs);

現(xiàn)在,skeleton驅(qū)動(dòng)就已經(jīng)和設(shè)備綁定上了,任何用戶態(tài)程序要操作此設(shè)備都可以通過file_operations結(jié)構(gòu)所定義的函數(shù)進(jìn)行了。首先,我們要open此設(shè)備。在open函數(shù)中MODULE_INC_USE_COUNT 宏是一個(gè)關(guān)鍵,它的作用是起到一個(gè)計(jì)數(shù)的作用,有一個(gè)用戶態(tài)程序打開一個(gè)設(shè)備,計(jì)數(shù)器就加一,例如,我們以模塊方式加入一個(gè)驅(qū)動(dòng),若計(jì)數(shù)器不為零,就說明仍然有用戶程序在使用此驅(qū)動(dòng),這時(shí)候,你就不能通過rmmod命令卸載驅(qū)動(dòng)模塊了。


/* increment our usage count for the module */
MOD_INC_USE_COUNT;
++skel->;open_count;
/* save our object in the file's private structure */
file->;private_data = skel;

當(dāng)open完設(shè)備后,read、write函數(shù)就可以收、發(fā)數(shù)據(jù)了。
2.        skel的write、和read函數(shù)
他們是完成驅(qū)動(dòng)對(duì)讀寫等操作的響應(yīng)。
在skel_write中,一個(gè)FILL_BULK_URB函數(shù),就完成了urb 系統(tǒng)callbak和我們自己的skel_write_bulk_callback之間的聯(lián)系。注意skel_write_bulk_callback是中斷方式,所以要注意時(shí)間不能太久,本程序中它就只是報(bào)告一些urb的狀態(tài)等。
read 函數(shù)與write 函數(shù)稍有不同在于:程序并沒有用urb 將數(shù)據(jù)從設(shè)備傳送到驅(qū)動(dòng)程序,而是我們用usb_bulk_msg 函數(shù)代替,這個(gè)函數(shù)能夠不需要?jiǎng)?chuàng)建urbs 和操作urb函數(shù)的情況下,來發(fā)送數(shù)據(jù)給設(shè)備,或者從設(shè)備來接收數(shù)據(jù)。我們調(diào)用usb_bulk_msg函數(shù)并傳提一個(gè)存儲(chǔ)空間,用來緩沖和放置驅(qū)動(dòng)收到的數(shù)據(jù),若沒有收到數(shù)據(jù),就失敗并返回一個(gè)錯(cuò)誤信息。
3.        usb_bulk_msg函數(shù)
當(dāng)對(duì)usb設(shè)備進(jìn)行一次讀或者寫時(shí),usb_bulk_msg 函數(shù)是非常有用的; 然而, 當(dāng)你需要連續(xù)地對(duì)設(shè)備進(jìn)行讀/寫時(shí),建議你建立一個(gè)自己的urbs,同時(shí)將urbs 提交給usb子系統(tǒng)。
4.        skel_disconnect函數(shù)
當(dāng)我們釋放設(shè)備文件句柄時(shí),這個(gè)函數(shù)會(huì)被調(diào)用。MOD_DEC_USE_COUNT宏會(huì)被用到(和MOD_INC_USE_COUNT剛好對(duì)應(yīng),它減少一個(gè)計(jì)數(shù)器),首先確認(rèn)當(dāng)前是否有其它的程序正在訪問這個(gè)設(shè)備,如果是最后一個(gè)用戶在使用,我們可以關(guān)閉任何正在發(fā)生的寫,操作如下:


/* decrement our usage count for the device */
--skel->;open_count;
if (skel->;open_count <= 0) {
   /* shutdown any bulk writes that might be
      going on */
   usb_unlink_urb (skel->;write_urb);
   skel->;open_count = 0;
}
/* decrement our usage count for the module */
MOD_DEC_USE_COUNT;
最困難的是,usb 設(shè)備可以在任何時(shí)間點(diǎn)從系統(tǒng)中取走,即使程序目前正在訪問它。usb驅(qū)動(dòng)程序必須要能夠很好地處理解決此問題,它需要能夠切斷任何當(dāng)前的讀寫,同時(shí)通知用戶空間程序:usb設(shè)備已經(jīng)被取走。
如果程序有一個(gè)打開的設(shè)備句柄,在當(dāng)前結(jié)構(gòu)里,我們只要把它賦值為空,就像它已經(jīng)消失了。對(duì)于每一次設(shè)備讀寫等其它函數(shù)操作,我們都要檢查usb_device結(jié)構(gòu)是否存在。如果不存在,就表明設(shè)備已經(jīng)消失,并返回一個(gè)-ENODEV錯(cuò)誤給用戶程序。當(dāng)最終我們調(diào)用release 函數(shù)時(shí),在沒有文件打開這個(gè)設(shè)備時(shí),無論usb_device結(jié)構(gòu)是否存在、它都會(huì)清空skel_disconnect函數(shù)所作工作。
Usb 骨架驅(qū)動(dòng)程序,提供足夠的例子來幫助初始人員在最短的時(shí)間里開發(fā)一個(gè)驅(qū)動(dòng)程序。更多信息你可以到linux usb開發(fā)新聞組去尋找。
U盤、USB讀卡器、MP3、數(shù)碼相機(jī)驅(qū)動(dòng)
對(duì)于一款windows下用的很爽的U盤、USB讀卡器、MP3或數(shù)碼相機(jī),可能Linux下卻不能支持。怎么辦?其實(shí)不用傷心,也許經(jīng)過一點(diǎn)點(diǎn)的工作,你就可以很方便地使用它了。通常是此U盤、USB讀卡器、MP3或數(shù)碼相機(jī)在WindowsXP中不需要廠商專門的驅(qū)動(dòng)就可以識(shí)別為移動(dòng)存儲(chǔ)設(shè)備,這樣的設(shè)備才能保證成功,其他的就看你的運(yùn)氣了。
USB存儲(chǔ)設(shè)備,他們的read、write等操作都是通過上章節(jié)中提到的鉤子,把自己的操作鉤到SCSI設(shè)備上去的。我們就不需要對(duì)其進(jìn)行具體的數(shù)據(jù)讀寫處理了。
第一步:我們通過cat /proc/bus/usb/devices得到當(dāng)前系統(tǒng)探測到的USB總線上的設(shè)備信息。它包括Vendor、ProdID、Product等。下面是我買的一款雜牌CF卡讀卡器插入后的信息片斷:


T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#= 5 Spd=12 MxCh= 0
D: Ver= 1.10 Cls=00(>;ifc ) Sub=00 Prot=00 MxPS=8 #Cfgs= 1
P: Vendor=07c4 ProdID=a400 Rev= 1.13
S: Manufacturer=USB
S: Product=Mass Storage
C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=70mA
I: If#= 0 Alt= 0 #EPs= 2 Cls=08(vend.) Sub=06 Prot=50 Driver=usb-storage
E: Ad=81(I) Atr=02(Bulk) MxPS= 64 Ivl= 0ms
E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms

其中,我們最關(guān)心的是Vendor=07c4 ProdID=a400和Manufacturer=USB(果然是雜牌,廠商名都看不到)Product= Mass Storage。
對(duì)于這些移動(dòng)存儲(chǔ)設(shè)備,我們知道Linux下都是通過usb-storage.o驅(qū)動(dòng)模擬成scsi設(shè)備去支持的,之所以不支持,通常是usb-storage驅(qū)動(dòng)未包括此廠商識(shí)別和產(chǎn)品識(shí)別信息(在類似skel_probe的USB最初探測時(shí)被屏蔽了)。對(duì)于USB存儲(chǔ)設(shè)備的硬件訪問部分,通常是一致的。所以我們要支持它,僅需要修改usb-storage中關(guān)于廠商識(shí)別和產(chǎn)品識(shí)別列表部分。
第二部,打開drivers/usb/storage/unusual_devs.h文件,我們可以看到所有已知的產(chǎn)品登記表,都是以UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, vendor_name, product_name, use_protocol, use_transport, init_function, Flags)方式登記的。其中相應(yīng)的涵義,你就可以根據(jù)命名來判斷了。所以只要我們?nèi)缦绿钊胛覀冏约旱淖?cè),就可以讓usb-storage驅(qū)動(dòng)去認(rèn)識(shí)和發(fā)現(xiàn)它。

UNUSUAL_DEV(07c4, a400, 0x0000, 0xffff,
" USB ", " Mass Storage ",
US_SC_SCSI, US_PR_BULK, NULL,
US_FL_FIX_INQUIRY | US_FL_START_STOP |US_FL_MODE_XLATE )

注意:添加以上幾句的位置,一定要正確。比較發(fā)現(xiàn),usb-storage驅(qū)動(dòng)對(duì)所有注冊(cè)都是按idVendor, idProduct數(shù)值從小到大排列的。我們也要放在相應(yīng)位置。
最后,填入以上信息,我們就可以重新編譯生成內(nèi)核或usb-storage.o模塊。這時(shí)候插入我們的設(shè)備就可以跟其他U盤一樣作為SCSI設(shè)備去訪問了。
鍵盤飛梭支持
目前很多鍵盤都有飛梭和手寫板,下面我們就嘗試為一款鍵盤飛梭加入一個(gè)驅(qū)動(dòng)。在通常情況,當(dāng)我們插入U(xiǎn)SB接口鍵盤時(shí),在/proc/bus/usb/devices會(huì)看到多個(gè)USB設(shè)備。比如:你的USB鍵盤上的飛梭會(huì)是一個(gè),你的手寫板會(huì)是一個(gè),若是你的USB鍵盤有USB擴(kuò)展連接埠,也會(huì)看到。
下面是具體看到的信息

T:  Bus=02 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2
B:  Alloc= 11/900 us ( 1%), #Int=  1, #Iso=  0
D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
P:  Vendor=0000 ProdID=0000 Rev= 0.00
S:  Product=USB UHCI Root Hub
S:  SerialNumber=d800
C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=  0mA
I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl=255ms
T:  Bus=02 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#=  3 Spd=12  MxCh= 3
D:  Ver= 1.10 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
P:  Vendor=07e4 ProdID=9473 Rev= 0.02
S:  Manufacturer=ALCOR
S:  Product=Movado USB Keyboard
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
E:  Ad=81(I) Atr=03(Int.) MxPS=   1 Ivl=255ms
找到相應(yīng)的信息后就可開始工作了。實(shí)際上,飛梭的定義和鍵盤鍵碼通常是一樣的,所以我們參照drivers/usb/usbkbd..c代碼進(jìn)行一些改動(dòng)就可以了。因?yàn)闆]能拿到相應(yīng)的硬件USB協(xié)議,我無從知道飛梭在按下時(shí)通訊協(xié)議眾到底發(fā)什么,我只能把它的信息打出來進(jìn)行分析。幸好,它比較簡單,在下面代碼的usb_kbd_irq函數(shù)中if(kbd->;new[0] == (char)0x01)和if(((kbd->;new[1]>;>;4)&0x0f)!=0x7)就是判斷飛梭左旋。usb_kbd_irq函數(shù)就是鍵盤中斷響應(yīng)函數(shù)。他的掛接,就是在usb_kbd_probe函數(shù)中

FILL_INT_URB(&kbd->;irq, dev, pipe, kbd->;new, maxp >; 8 ? 8 : maxp,
                usb_kbd_irq, kbd, endpoint->;bInterval);

一句中實(shí)現(xiàn)。
從usb骨架中我們知道,usb_kbd_probe函數(shù)就是在USB設(shè)備被系統(tǒng)發(fā)現(xiàn)是運(yùn)行的。其他部分就都不是關(guān)鍵了。你可以根據(jù)具體的探測值(Vendor=07e4 ProdID=9473等)進(jìn)行一些修改就可以了。值得一提的是,在鍵盤中斷中,我們的做法是收到USB飛梭消息后,把它模擬成左方向鍵和右方向鍵,在這里,就看你想怎么去響應(yīng)它了。當(dāng)然你也可以響應(yīng)模擬成F14、F15等擴(kuò)展鍵碼。
在了解了此基本的驅(qū)動(dòng)后,對(duì)于一個(gè)你已經(jīng)拿到通訊協(xié)議的鍵盤所帶手寫板,你就應(yīng)該能進(jìn)行相應(yīng)驅(qū)動(dòng)的開發(fā)了吧。
程序見附錄1:鍵盤飛梭驅(qū)動(dòng)。
使用此驅(qū)動(dòng)要注意的問題:在加載此驅(qū)動(dòng)時(shí)你必須先把hid設(shè)備卸載,加載完usbhkey.o模塊后再加載hid.o。因?yàn)槿鬶id存在,它的probe會(huì)屏蔽系統(tǒng)去利用我們的驅(qū)動(dòng)發(fā)現(xiàn)我們的設(shè)備。其實(shí),飛梭本來就是一個(gè)hid設(shè)備,正確的方法,或許你應(yīng)該修改hid的probe函數(shù),然后把我們的驅(qū)動(dòng)融入其中。
參考資料
1.        《LINUX設(shè)備驅(qū)動(dòng)程序》
ALESSANDRO RUBINI著
LISOLEG 譯
2.        《Linux系統(tǒng)分析與高級(jí)編程技術(shù)》
周巍松 編著
3.        Linux Kernel-2.4.20源碼和文檔說明
附錄1:鍵盤飛梭驅(qū)動(dòng)

#include <linux/kernel.h>;
#include <linux/slab.h>;
#include <linux/module.h>;
#include <linux/input.h>;
#include <linux/init.h>;
#include <linux/usb.h>;
#include <linux/kbd_ll.h>;

/*
* Version Information
*/
#define DRIVER_VERSION ""
#define DRIVER_AUTHOR "TGE HOTKEY "
#define DRIVER_DESC "USB HID Tge hotkey driver"

#define USB_HOTKEY_VENDOR_ID 0x07e4
#define USB_HOTKEY_PRODUCT_ID 0x9473
//廠商和產(chǎn)品ID信息就是/proc/bus/usb/devices中看到的值

MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );

struct usb_kbd {
        struct input_dev dev;
        struct usb_device *usbdev;
        unsigned char new[8];
        unsigned char old[8];
        struct urb irq, led;
//        devrequest dr;     
//這一行和下一行的區(qū)別在于kernel2.4.20版本對(duì)usb_kbd鍵盤結(jié)構(gòu)定義發(fā)生了變化
      struct usb_ctrlrequest dr;
        unsigned char leds, newleds;
        char name[128];
        int open;
};
//此結(jié)構(gòu)來自內(nèi)核中drivers/usb/usbkbd..c

static void usb_kbd_irq(struct urb *urb)
{
        struct usb_kbd *kbd = urb->;context;
        int *new;
        new = (int *) kbd->;new;

        if(kbd->;new[0] == (char)0x01)
        {
                if(((kbd->;new[1]>;>;4)&0x0f)!=0x7)
                {
handle_scancode(0xe0,1);
handle_scancode(0x4b,1);
                handle_scancode(0xe0,0);
                handle_scancode(0x4b,0);
                }
                else
                {
                                handle_scancode(0xe0,1);
                handle_scancode(0x4d,1);
                handle_scancode(0xe0,0);
                handle_scancode(0x4d,0);
                }
        }
       
       
        printk("new=%x %x %x %x %x %x %x %x",
                kbd->;new[0],kbd->;new[1],kbd->;new[2],kbd->;new[3],
                kbd->;new[4],kbd->;new[5],kbd->;new[6],kbd->;new[7]);
               
}

static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum,
                           const struct usb_device_id *id)
{
        struct usb_interface *iface;
        struct usb_interface_descriptor *interface;
        struct usb_endpoint_descriptor *endpoint;
        struct usb_kbd *kbd;
        int  pipe, maxp;

        iface = &dev->;actconfig->;interface[ifnum];
        interface = &iface->;altsetting[iface->;act_altsetting];

        if ((dev->;descriptor.idVendor != USB_HOTKEY_VENDOR_ID) ||
                (dev->;descriptor.idProduct != USB_HOTKEY_PRODUCT_ID) ||
                (ifnum != 1))
        {
                return NULL;
        }
        if (dev->;actconfig->;bNumInterfaces != 2)
        {
                return NULL;       
        }

        if (interface->;bNumEndpoints != 1) return NULL;

        endpoint = interface->;endpoint + 0;

        pipe = usb_rcvintpipe(dev, endpoint->;bEndpointAddress);
        maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));

        usb_set_protocol(dev, interface->;bInterfaceNumber, 0);
        usb_set_idle(dev, interface->;bInterfaceNumber, 0, 0);

        printk(KERN_INFO "GUO: Vid = %.4x, Pid = %.4x, Device = %.2x, ifnum = %.2x, bufCount = %.8x\\n",
        dev->;descriptor.idVendor,dev->;descriptor.idProduct,dev->;descriptor.bcdDevice, ifnum, maxp);

        if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL;
        memset(kbd, 0, sizeof(struct usb_kbd));

        kbd->;usbdev = dev;

        FILL_INT_URB(&kbd->;irq, dev, pipe, kbd->;new, maxp >; 8 ? 8 : maxp,
                usb_kbd_irq, kbd, endpoint->;bInterval);

        kbd->;irq.dev = kbd->;usbdev;

        if (dev->;descriptor.iManufacturer)
                usb_string(dev, dev->;descriptor.iManufacturer, kbd->;name, 63);

        if (usb_submit_urb(&kbd->;irq)) {
                kfree(kbd);
                return NULL;
        }
       
        printk(KERN_INFO "input%d: %s on usb%d:%d.%d\\n",
                 kbd->;dev.number, kbd->;name, dev->;bus->;busnum, dev->;devnum, ifnum);

        return kbd;
}

static void usb_kbd_disconnect(struct usb_device *dev, void *ptr)
{
        struct usb_kbd *kbd = ptr;
        usb_unlink_urb(&kbd->;irq);
        kfree(kbd);

}

static struct usb_device_id usb_kbd_id_table [] = {
        { USB_DEVICE(USB_HOTKEY_VENDOR_ID, USB_HOTKEY_PRODUCT_ID) },
        { }                                                /* Terminating entry */
};

MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);

static struct usb_driver usb_kbd_driver = {
        name:                "Hotkey",
        probe:                usb_kbd_probe,
        disconnect:        usb_kbd_disconnect,
        id_table:        usb_kbd_id_table,
        NULL,
};

static int __init usb_kbd_init(void)
{
        usb_register(&usb_kbd_driver);
        info(DRIVER_VERSION ":" DRIVER_DESC);
        return 0;
}

static void __exit usb_kbd_exit(void)
{
        usb_deregister(&usb_kbd_driver);
}

module_init(usb_kbd_init);
module_exit(usb_kbd_exit);

論壇徽章:
0
2 [報(bào)告]
發(fā)表于 2003-07-19 15:33 |只看該作者

Linux下的硬件驅(qū)動(dòng)——USB設(shè)備(下)(驅(qū)動(dòng)開發(fā)部分)

好文章!

論壇徽章:
0
3 [報(bào)告]
發(fā)表于 2003-07-21 16:18 |只看該作者

Linux下的硬件驅(qū)動(dòng)——USB設(shè)備(下)(驅(qū)動(dòng)開發(fā)部分)

好帖,但看不太懂

論壇徽章:
0
4 [報(bào)告]
發(fā)表于 2004-05-09 21:31 |只看該作者

Linux下的硬件驅(qū)動(dòng)——USB設(shè)備(下)(驅(qū)動(dòng)開發(fā)部分)

真是強(qiáng)人

論壇徽章:
0
5 [報(bào)告]
發(fā)表于 2004-08-13 11:18 |只看該作者

Linux下的硬件驅(qū)動(dòng)——USB設(shè)備(下)(驅(qū)動(dòng)開發(fā)部分)

后面的usb的例子寫得還好,就是如果讀者沒有看過控制臺(tái)驅(qū)動(dòng)的話,會(huì)很模糊,不過中國的網(wǎng)絡(luò)資源也只能到這個(gè)深度了. 總的來說還可以

論壇徽章:
0
6 [報(bào)告]
發(fā)表于 2004-08-13 11:25 |只看該作者

Linux下的硬件驅(qū)動(dòng)——USB設(shè)備(下)(驅(qū)動(dòng)開發(fā)部分)

寫的不好,沒有吃透usb驅(qū)動(dòng)的內(nèi)核源代碼。還有控制臺(tái)的驅(qū)動(dòng),不過中國的網(wǎng)絡(luò)資源就是這樣,這也算值的一看的了

論壇徽章:
0
7 [報(bào)告]
發(fā)表于 2005-10-18 16:40 |只看該作者

Linux下的硬件驅(qū)動(dòng)——USB設(shè)備(下)(驅(qū)動(dòng)開發(fā)部分)

作個(gè)記號(hào),并收藏之!
看來要反復(fù)多看...

論壇徽章:
0
8 [報(bào)告]
發(fā)表于 2006-05-13 17:54 |只看該作者
強(qiáng)。。。。。。。。。。。。。。。。!

論壇徽章:
0
9 [報(bào)告]
發(fā)表于 2011-03-09 12:54 |只看該作者
好貼,學(xué)習(xí)之,收藏先

論壇徽章:
0
10 [報(bào)告]
發(fā)表于 2011-03-25 11:37 |只看該作者
好貼,大體明白USB的框架了
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP