TỔNG QUAN VỀ USB
Giới thiệu về USB
USB (Universal Serial Bus) là một chuẩn kết nối có dây trong máy tính, sử dụng nhằm kết nối giữa các điểm kỹ thuật của máy tính với các thiết bị ngoại vi Vào cuối năm
1994 đã được đề xuất bởi Intel, Compaq, IBM, Microsoft và các công ty khác Bây giờ, USB trở thành một giao diện mở rộng máy tính tiêu chuẩn của thế kỷ XXI và phiên bản 3.1 đã được tung ra thị trường.
USB có thể kết nối với 127 thiết bị bên ngoài mà không làm giảm băng thông. USB đòi hỏi sự hỗ trợ của phần cứng máy chủ, hệ điều hành và thiết bị ngoại vi để làm việc đúng cách Giao diện USB cũng có thể đạt được kết nối hai máy tính thông qua cáp chuyên dụng và tạo ra giao diện bổ sung nhiều hơn thông qua Hub Nó có nhiều tính năng như tốc độ truyền tải nhanh, sử dụng thuận tiện, dễ tháo lắp, kết nối linh hoạt, cung cấp điện độc lập, …Nó đóng một vai trò quan trọng trong việc kết nối máy tính với gần như tất cả các thiết bị bên ngoài, chẳng hạn như chuột, bàn phím, máy in, máy quét, máy ảnh, sạch, MP3, điện thoại di động, máy ảnh kỹ thuật số, …
Hình 1: Đầu USB và cổng cắm USB
Chuẩn tín hiệu
Chuẩn USB sử dụng 4 đường tín hiệu trong đó có 2 đường cấp nguồn DC (VBUS- 5V và GND) 2 đường còn lại là một cặp tín hiệu vi sai (D+ và D-) cho phép truyền dữ liệu Cặp dây tín hiệu này được nối xoắn ở bên trong nên có khả năng chống nhiễu tốt. Lưu ý: cổng USB trên máy tính cho phép cấp nguồn nuôi ra bên ngoài với dòng lên tới 500mA Như vậy, các thiết bị sử dụng ít điện năng như chuột, thẻ nhớ USB đều có thể lấy trực tiếp nguồn từ cổng USB của máy tính mà không cần dùng thêm nguồn ngoài.
Mô hình mạng
Các thiết bị hoạt động theo chuẩn USB được kết nối với nhau theo đồ hình mạng hình sao phân cấp Trung tâm của mỗi hình sao này là các Hub Các thiết bị USB được chia làm 3 loại chính: USB Host, USB Bus, USB Hub.
Hình 3: Mô hình mạng của các thiết bị hoạt động theo chuẩn USB
USB Host: thiết bị đóng vai trò điều khiển toàn bộ mạng USB (có thể lên tới tối đa 126 thiết bị) Ví dụ như trên máy tính, USB Host được gắn trên mainboard Để giao tiếp và điều khiển các USB device, USB Host controller cần được thiết kế tích hợp với USB RootHub (Hub mức cao nhất) Vai trò của thiết bị USB Host như sau:
Trao đổi dữ liệu với các USB Device. Điều khiển USB Bus.
Quản lý các thiết bị cắm vào hay rút ra khỏi Bus USB qua quá trình điểm danh (Enumeration).
Phân xử, quản lý luồng dữ liệu trên Bus, đảm bảo các thiết bị đều có cơ hội trao đổi dữ liệu tùy thuộc vào cấu hình của mỗi thiết bị.
Ngày nay bộ điều khiển máy chủ USB được tích hợp trên hầu hết các chipset bo mạch chủ Các bo mạch cũ không được trang bị bộ điều khiển như vậy có thể được nâng cấp bằng PCI cards với các bộ điều khiển máy chủ đó Tất cả các bộ điều khiển này tương thích với tiêu chuẩn Open Host Controller Interface (OHCI của Compaq, Microsoft và National Semiconductor) hoặc Universal Host Controller Interface (UHCI by Intel [7]) Cả hai loại đều có khả năng tương đương nhau và thiết bị USB không phải quan tâm đến bộ điều khiển máy chủ Về cơ bản phần cứng của UHCI đơn giản hơn và do đó nó cần driver phức tạp hơn, có thể khiến CPU quá tải.
USB Device: là các thiết bị đóng vai trò như các slave giao tiếp với USB Host.
Các thiết bị này hoàn toàn đóng vai trò bị động, không bao giờ được tự ý gửi gói tin lên USB Host hay gửi gói tin giữa các USB Device với nhau, tất cả đều phải thông qua quá trình điều phối của USB Host Chức năng của thiết bị USB Device như sau:
Trao đổi dữ liệu với USB Host
Phát hiện gói tin hay yêu cầu từ USB Host theo giao thức USB.
Có nhiều loại thiết bị USB khác nhau vì chúng có thể được sử dụng cho những mục đích khác nhau Đầu tiên, một thiết bị có thể tự cấp nguồn, chạy bằng nguồn bus hoặc cả hai USB có thể tự cấp nguồn điện lên tới 500mA cho các thiết bị của nó Nếu chỉ có các thiết bị chạy bằng nguồn bus, sự tiêu hao năng lượng tối đao có thể bị vượt quá và do đó cần phải có các thiết bị cấp nguồn Chúng cần phải có nguồn cung cấp năng lượng riêng Các thiết bị hỗ trợ cả hai loại nguồn có thể chuyển sang chế độ tự cấp nguồn khi gắn nguồn điện bên ngoài.
Ngay cả tốc độ giao tiếp tối đa cũng có thể khác nhau đối với từng thiết bị USB cụ thể Thông số kĩ thuật USB quyết định giữa các thiết bị tốc độ thấp và tốc độ cao Các thiết bị tốc độ thấp (như chuột, bàn phím, cần điều khiển, …) giao tiếp với tốc độ 1,5Mbit/s với khả năng hạn chế Các thiết bị tốc độ cao (như hệ thống âm thanh và video) có thể sử dụng tới 90% tốc độ 12Mbit/s, tức là khoảng 10Mbit/s bao gồm cả chi phí giao thức.
USB Hub: đóng vai trò như các Hub trong mạng Ethernet của chúng ta Cấp nguồn cho các thiết bị USB Về mặt vật lí tồn tại một số cổng USB ở bảng điều khiển phía sau của máy tính Các cổng này có thể được sử dụng để gắn các thiết bị thông thường hoặc một hub Hub là một thiết bị USB giúp mở rộng số lượng cổng (2-8) để kết nối các thiết bị USB khác Số lượng thiết bị có thể gắn tối đa được giảm theo số lượng hub trên từng bus Hub là thiết bị tự cấp nguồn/chạy bằng nguồn bus tốc độ cao.
Thông thường, các cổng vật lí của bộ điều khiển máy chủ được xử lý bởi một virtual root hub Hub này được mô phỏng bởi driver của trình điều khiển thiết bị giúp thống nhất cấu trúc liên kết bus Vì vậy, mọi cổng có thể được xử lý theo cùng một cách bởi driver của hệ thống con USB
Quá trình hoạt động của chuẩn USB
Quá trình hoạt động của chuẩn USB được chia làm hai giai đoạn chính:
Quá trình điểm danh: là quá trình USB Host phát hiện các thiết bị cắm vào (Plug in) hoặc rút ra (Plug out) khỏi đường USB Bus Mỗi khi một thiết bị tham gia vào Bus USB, USB Host sẽ tiến hành (Detect device) đọc các thông tin mô tả (description) của USB Device, từ đó thiết lập địa chỉ (NodeID) và chế độ hoạt động tương ứng cho thiết bị USB Device Các địa chỉ sẽ được đánh từ 1->126 nên về lý thuyết, chuẩn USB cho phép kết nối 126 thiết bị vào đường Bus Khi thiết bị rút ra khỏi đường Bus, địa chỉ này sẽ được thu hồi.
Quá trình truyền dữ liệu: để hiểu quá trình truyền dữ liệu này, chúng ta phải hiểu được hai khái quan trọng nhất trong chuẩn USB, đó là khái niệm Interface và Endpoint(chỉ thiết bị USB device mới có Endpoint, USB Host không có Endpoint) Một thiết bịUSB sẽ có thể có nhiều Interface, một Interface có thể sử dụng nhiều Endpoint VD: Thẻ nhớ USB chỉ sử dụng 1 Interface theo chuẩn USB Mass storage, interface này sử dụng 3Endpoint Bộ USB 3G sử dụng các Interface khác nhau như: CD Room, Mass storage vàCommunication, mỗi interface lại sử dụng nhiều Endpoint khác nhau.
Như vậy, đứng ở góc độ mức hệ thống, các Interface chính là các dịch vụ khác nhau mà thiết bị đó cung cấp còn các Endpoint chính là các cổng cần thiết cho mỗi dịch vụ Tương ứng với khái niệm trong kiến trúc TCP/IP, ví dụ giao thức FTP là giao thức sử dụng để truyền file sẽ sử dụng hai cổng 20,21 Trong khi đó giao thức HTTP lại sử dụng port 80, giao thức Telnet sử dụng port 23.
Thực tế các Endpoint cũng như các Port trong chuẩn TCP/IP đóng vai trò như các bộ đệm truyền/nhận dữ liệu Nhờ việc sử dụng nhiều bộ đệm mà các quá trình truyền thông được tiến hành song song và cho tốc độ cao hơn, bên cạnh đó giúp cho việc phân tách các dịch vụ khác nhau Với chuẩn USB, các thiết bị được thiết kế với tối đa là 16 Enppoint Các Endpoint được phân loại theo hướng truyền dữ liệu nhìn từ phía USB Host Cụ thể:
Các Endpoint truyền dữ liệu từ USB Device tới USB Host là endpoint IN Các Endoint truyền dữ liệu từ USB Host tới USB Device là endpoint OUT Đề truyền được dữ liệu theo chuẩn USB, các thiết bị USB Device phải được kết nối với USB Host thông qua các Pipe (đường ống) Mỗi Pipe sẽ nối một Endpoint củaUSB Device với USB Host.
Chế độ truyền
Chuẩn USB cung cấp cho chúng ta tổng cộng là 4 chế độ truyền, đáp ứng nhiều mục đích khác nhau tùy thuộc vào cơ chế truyền cũng như tốc độ mà người thiết kế mong muốn.
Truyền điều khiển (Control transfer): là chế độ truyền được tất cả các thiết bị
USB hỗ trợ để truyền các thông tin điều khiển với tốc độ tương đối chậm.
Truyền ngắt (Interrupt transfer): sử dụng cho các thiết bị cần truyền một lượng dữ liệu nhỏ, tuần hoàn theo thời gian ví dụ như chuột, bàn phím Khi đó, ví dụ cứ 10s một lần USB Host sẽ gửi request xuống và USB Device sẽ trả dữ liệu về cho USB Host (với trường hợp Interrupt In Endpoint).
Truyền theo khối (Bulk transfer): sử dụng cho các thiết bị cần truyền một lượng dữ liệu lớn, yêu cầu độ chính xác tuyệt đối, không có ràng buộc quá chặt chẽ về thời gian thực ví dụ như thẻ nhớ USB, máy in Cái này tương tự như giao thức TCP trong mạng Ethernet
Truyền đẳng thời (Isochronos transfer): sử dụng cho các thiết bị cần truyền một lượng dữ liệu lớn với tốc độ rất nhanh, đảm bảo ràng buộc về thời gian thực tuy nhiên chấp nhận hy sinh độ chính xác ở một mức nhất định như các thiết bị nghe nhạc, xem phim kết nối theo chuẩn USB Chuẩn này tương tự giao thức UDP trong mạng Ethernet.
Mô tả thiết bị
Bất cứ khi nào một thiết bị USB được gắn vào bus, nó sẽ được liệt kệ bởi hệ thống con USB – tức là một số thiết bị được gán và sau đó thiết bị mô tả sẽ đọc Một thiết bị mô tả như vậy là một cấu trúc dữ liệu chứa thông tin về thiết bị và các thuộc tính của thiết bị. Tiêu chuẩn USB xác định hệ thống phân cấp của các mô tả.
Hình 4: Mô tả thiết bị USB
1.6.1 Mô tả chuẩn (Standard Descriptions)
Device Descriptor: mô tả thông tin chung của các thiết bị USB Nó bao gồm tất cả thông tin và cấu hình của thiết bị Một thiết bị USB chỉ có 1 mô tả thiết bị.Configuration Descriptor (Bộ mô tả cấu hình): cung cấp thông tin cấu hình của một thiết bị cụ thể Một thiết bị USB có một hoặc nhiều cấu hình Mỗi cấu hình có một hoặc nhiều interface và mỗi interface có thể có 0 hoặc nhiều endpoint.Endpoint có thể được chia sẻ giữa các giao diện là một phần của các cấu hình khác nhau mà không có hạn chế
Interface Description (Bộ mô tả giao diện): mô tả một giao diện cụ thể trong cấu hình Một cấu hình cung cấp một hoặc nhiều interface, mỗi giao diện có 0 hoặc nhiều endpoint mô tả một tập hợp các endpoint trong cấu hình
Entpoint Descriptor (Bộ mô tả endpoint): chứa thông tin theo yêu cầu của máy chủ lưu trữ xác định các yêu cầu băng thông của từng endpoint Một endpoint biểu thị cho nguồn dữ liệu logic hoặc bộ góp của thiết bị USB Endpoint 0 được sử dụng cho tất cả cả các lần truyền điều khiển tiêu chuẩn và không bao giờ có mô tả cho endpoint này
String Descriptor (Bộ mô tả chuỗi): là tùy chọn và cung cấp thông tin bổ sung ở định dạng Unicode có thể đọc được Chúng có thể được sử dụng cho tên nhà cung thiết bị hoặc số seri.
Lớp HID bao gồm chủ yếu các thiết bị được con người sử dụng để điều khiển hoạt động của các hệ thống máy tính Ví dụ điển hình của các thiết bị lớp HID bao gồm: Bàn phím và thiết bị trỏ, thiết bị chuột, cần điều khiển, …
Bảng điều khiển phía trước: núm, công tắc, nút, thanh trượt, …
Các điều khiển có thể được tìm thấy trên các thiết bị như: điện thoại, điều khiển từ xa, trò chơi hoặc thiết bị mô phỏng như: găng tay, vô lăng, bàn đạp bánh lái, …
VIẾT DRIVER CHO USB
Kiến trúc của hệ điều hành Linux
Hình 5: Kiến trúc của hệ điều hành
- Kernel: Đây là phần quan trọng và được ví như trái tim của hệ điều hành, phần kernel chứa các module, thư viện để quản lý và giao tiếp với phần cứng và các ứng dụng
- Shell: Shell là một chương trình có chức năng thực thi các lệnh từ người dùng hoặc từ các ứng dụng - tiện ích yêu cầu chuyển đến cho Kernel xử lý.
- Applications: Là các ứng dụng và tiện ích mà người dùng cài đặt trên Server Ví dụ: ftp, samba, Proxy, …
Hình 6: Kiến trúc của Linux kernel
Dựa vào chức năng của hệ điều hành, Linux Kernel chia thành 6 thành phần:
Process Management: có nhiệm vụ quản lý tiến trình
Memory Management: có nhiệm vụ quản lý bộ nhớ
Device Management: có nhiệm vụ quản lý thiết bị
File system Management: quản lý dữ liệu trên thiết bị lưu trữ (ổ cứng) Network Management: quản lý gói tin theo mô hình TCP/IP
System call interface: cung cấp dịch vụ sử dụng phần cứng cho các tiến trình
2.1.2.Quản lý thiết bị (Device management) a Định nghĩa Driver:
Máy tính có 2 phần cơ bản: phần cứng và phần mềm Để kết nối phần cứng và phần mềm người ta cần 1 “cầu nối”, đó chính là driver Driver là môi trường cho phép các chương trình máy tính, hệ điều hành và các ứng dụng khác tương tác với một thiết bị phần cứng Ví dụ, một chiếc máy tính đơn thuần không thể biết cách làm thể nào để sử dụng toàn bộ tính năng của card video – nó cần một driver để làm điều đó.
Các thiết bị phần cứng mà hệ điều hành không xác định hoặc có các tính năng mà hệ điều hành không xác định được đều yêu cầu driver Tùy thuộc vào từng loại thiết bị cũng như mục đích sử dụng, ta có một số driver quan trọng với hệ điều hành như sau:
- Driver âm thanh: hỗ trợ cho âm thanh và loa của máy tính.
- Driver Bios: là hệ thống đầu vào đầu ra giúp hỗ trợ các bo mạch chủ của máy tính.
- Driver Chipset (Intel Chipset driver): giúp vi xử lý hoạt động nhanh hơn, tốt hơn.
- Driver Graphics (Graphics driver): đây là driver đối với màn máy tính.
- Driver Mouse and Keyboard: giúp hỗ trợ chuột và bàn phím của máy tính.
- Driver mạng (LAN driver): giúp hỗ trợ cho mạng dây.
- Driver WiFi (Wireless driver): giúp máy tính kết nối WiFi hoạt động tốt.
- Driver camera (camera driver): giúp hỗ trợ chụp ảnh trên máy tính.
Tóm lại, driver giúp các chương trình và phần cứng giao tiếp được với nhau.Cũng như các chương trình máy tính cần có các bản cập nhật và gói dịch vụ để sửa lỗi, bổ sung thêm tính năng mới… driver cần được cập nhật thường xuyên. b Quản lí thiết bị
Quản lý thiết bị bao gồm các “driver” và mỗi driver chịu trách nhiệm điều khiển, giám sát, trao đổi dữ liệu với một thiết bị
Quản lí thiết bị qua Driver là một trình điều khiển có vai trò điều khiển, quản lý, giám sát một thực thể nào đó Một thành phần phần cứng có thể được điều khiển bởi một driver hoặc được điều khiển bởi một thành phần phần cứng khác có driver của thành phần phần cứng đó quản lý Tại đây, Driver gồm các lệnh có chức năng giúp CPU tương tác với thiết bị như chuột, bàn phím Tuy nhiên các thiết bị này sẽ không được trực tiếp nối với CPU, do đó các thiết bị này sẽ được kết nối với CPU thông qua 1 thiết bị khác được gọi là device controller và mỗi device controller sẽ có driver của riêng mình Đứng từ góc độ của CPU, bộ điều khiển cũng chỉ là một thiết bị Do đó, cần có driver hướng dẫn CPU làm việc với bộ điều khiển Driver này được gọi là bus driver Còn driver hướng dẫn CPU làm việc với thiết bị thì được gọi là device driver
Hình 7: Tương tác giữa thiết bị và driver
Các device controller thông thường được kết nối với CPU thông qua đường bus (PCI, IDE, USB, SPI, …) Trong vi điều khiển, CPU và các device controller thường được thiết kế trên một chip Điều này cho phép giảm kích thước và giá thành, phù hợp với phát triển hệ thống nhúng Mà về mặt nguyên tắc, sẽ không có gì khác biệt đối lớn đối với các driver trên các hệ thống máy tính cá nhân.
Các bus driver cung cấp giao diện đặc tả cho các giao thức phần cứng tương ứng Nó nằm ở tầng dưới cùng trong mô hình phân lớp phần mềm của hệ điều hành Nằm trên nó là các device driver thực sự để vận hành các thiết bị, mang đặc trưng của từng thiết bị xác định Ngoài ra, mục đích quan trọng của các driver thiết bị là cung cấp một giao diện trừu tường hóa cho người sử dụng, tức là cung cấp một giao diện lên tầng trên của hệ điều hành Một cách tổng quan, một driver sẽ bao gồm 2 phần quan trọng: a) giao tiếp với thiết bị (Device-specific) b) giao tiếp với hệ điều hành (OS-specific)
- OS specific: Thành phần này cung cấp cho hệ điều hành các dịch vụ đọc/ghi dữ liệu của thiết bị Điều này cho phép chúng ta xây dựng hệ điều hành độc lập với cấu trúc của thiết bị
- Device specific: Thành phần này chứa các lệnh hướng dẫn CPU điều khiển thiết bị, giám sát thiết bị, trao đổi dữ liệu với thiết bị Thành phần này chứa các lệnh hướng dẫn CPU điều khiển thiết bị, giám sát thiết bị, trao đổi dữ liệu với thiết bị Chúng ta sử dụng datasheet của thiết bị để xây dựng thành phần này Datasheet là một tài liệu được cung cấp bởi nhà sản xuất thiết bị Nó mô tả sơ đồ khối chức năng, nguyên lý hoạt động, hiệu suất hoạt động, đặc tính điện của thiết bị và đặc biệt là bản đồ thanh ghi (register map)
Bus driver cung cấp interface thể hiện cho các phần cứng tương ứng Nó nằm ở tầng cuối cùng trong mô hình phân lớp hệ điều hành Dưới bus driver là hardware và trên nó là device driver
- Protocol abstraction: Thành phần này che giấu đi sự phức tạp của các giao thức trên bus, cung cấp các dịch vụ cho device driver sử dụng Ví dụ như đọc/ghi một thanh ghi nào đó của thiết bị
- Protocol specific: Thành phần này chứa các lệnh hướng dẫn CPU làm việc với bộ điều khiển, giúp đọc/ghi dữ liệu trên bus Nó cũng được xây dựng dựa trên datasheet của bộ điều khiển
2.1.5 Mô hình phân lớp hệ thống USB trên Linux
Khi có một thiết bị usb hợp lệ được cắm vào hệ thống Linux, cho dù nó có driver hay không thì nó cũng vẫn được nhận diện (detect) bởi phần cứng ở tầng nhân (kernel space) của hệ thống Linux mà đã được hỗ trợ giao thức usb Hệ thống có thể làm điều này là bởi vì khả năng của chính bản thân giao thức usb đã được thiết kế trong đặc tả của nó Cụ thể, việc phát hiện ra thiết bị usb cắm vào được thực hiện bởi chip usb host controller (là thiết bị chủ động đường bus của giao thức usb) USB host controller này sẽ thu thập và diễn giải các thông tin ở tầng vật lý (low-level) đến các thông tin đặc tả giao thức USB ở tầng trên (high-level) Các thông tin về thiết bị theo khuôn dạng qui định của giao thức USB lại tiếp tục được đưa vào tầng usb core tổng quát (generic usb core) trong tầng nhân (được điều khiển bởi usbcore driver) Chính điều này giúp cho các thiết bị usb được hệ thống nhận diện ở tầng nhân, mặc dù nó có thể chưa có một driver cụ thể nào cho chức năng của nó.
Sau quá trình diễn ra ở tầng nhân này, sẽ đến nhiệm vụ của các drivers hoặc interfaces hoặc applications (cái mà phụ thuộc vào các bản Linux khác nhau) để tiếp tục nhận dạng ra thiết bị ở tầng người dùng.
Hình 8: Sơ đồ hoạt động Driver trong Linux
Quy trình viết driver chung
Tìm hiểu thông tin về thiết bị
Khai báo cấu trúc dữ liệu liên quan đến thiết bị Đăng ký và hủy đăng kí Driver cho thiết bị
Khai báo danh sách các thiết bị có thể được điều khiển bởi Driver
Thăm dò thiết bị probe()
Truyền thông với thiết bị
Hủy kết nối với thiết bị
Tìm hiểu thông tin về thiết bị Đầu tiên cần có thông tin về Firmware trên thiết bị Các thông tin cần thiết bao gồm: idVendor, idProduct, số lượng Configuration, số lượng Interface trong từng Configuration, số lượng và loại Endpoint trong từng Interface Những thông tin này có thể tìm trong tài liệu đi kèm thiết bị Hoặc cũng có một vài công cụ giúp xác định thông tin về thiết bị usb như USB Snoopy, USB Control Center (của Cypress) trên Windows, hoặc lệnh lsusb trên Linux
Khai báo danh sách các thiết bị có thể được điều khiển bởi Driver
Khi viết một USB Driver cần chỉ định xem Driver này sẽ được sử dụng cho các thiết bị hoặc các lớp thiết bị nào Cấu trúc usb_device_id cung cấp một kiểu thiết bị, nó có thể là một thiết bị cụ thể cũng có thể là một lớp thiết bị Có một số macro để khởi tạo cấu trúc này Ví dụ sử dụng macro USB_INTERFACE_INFO (USB_INTERFACE_CLASS_HID,
USB_INTERFACE_SUBCLASS_BOOT,USB_INTERFACE_PROTOCOL_KEYBOAR D) để tạo ra một cấu trúc usb_device_id
Khai báo cấu trúc dữ liệu liên quan tới thiết bị
Trong quá trình thăm dò thiết bị, có rất nhiều thông tin về thiết bị ta truy nhập được và cần phải lưu lại để sử dụng về sau Các thông tin cần thiết bao gồm: thiết bị cụ thể (được xác định bởi cấu trúc usb_device), thông tin các Configuration, Interface, Endpoint của thiết bị Tùy theo đặc điểm của từng phần cứng cụ thể mà ta định nghĩa một cấu trúc dữ liệu phù hợp Đăng kí và hủy đăng kí Driver cho thiết bị USB Device Để tầng USB Core có thể nhận ra Driver, cần phải đăng kí Driver sử dụng trong hàm khởi tạo Driver Tham số cần truyền cho hàm này là một con trỏ tới cấu trúc usb_driver Cấu trúc này chứa các thông tin về Driver đang viết bao gồm: (1) tên của Driver, (2) con trỏ tới bảng chứa các thiết bị sẽ đ ợc điều khiển bởi Driver đã được khaiƣ báo, (3) một con trỏ tới một hàm thăm dò, hàm này sẽ được gọi khi thiết bị được kết nối tới hệ thống để xác định các Endpoint, cấp phát bộ nhớ…(4) Một con trỏ tới một hàm ngắt kết nối, hàm này sẽ đ ợc gọi khi thiết bị đ ợc gỡ bỏ ra khỏi hệ thốngƣ ƣ
Thực hiện thăm dò thiết bị với hàm probe()
Khi thiết bị được kết nối tới hệ thống, hàm thăm dò của Driver sẽ được gọi với một con trỏ trỏ tới cấu trúc usb_interface mô tả Interface đ ợc chọn trên thiết bị do tầngƣ lõi USB truyền tới Hàm thăm dò sẽ thực hiện các công việc được lấy ra địa chỉ các Endpoint cần dùng và kích thước các bộ đệm cho thiết bị, cấp phát bộ đệm, lưu lại các thông tin như địa chỉ Endpoint, kích thước bộ đệm, địa chỉ bộ đệm…, đăng kí lớp thiết bị cho Driver
Truyền thông với thiết bị Để đọc ghi dữ liệu từ thiết bị USB ta phải lấy các thông tin từ thiết bị và thiết lập dữ liệu cho cấu trúc file Cấu trúc file được định nghĩa trong là một cấu trúc quan trọng trong không gian nhân của Linux rất cần thiết cho việc viết Driver của USB. Sau đó, hệ điều hành sẽ thực hiện đọc, ghi dữ liệu từ thiết bị sử dụng các hàm read() và write()
Hủy kết nối tới thiết bị bằng hàm disconnect().
Khi thiết bị được gỡ bỏ ra khỏi hệ thống, hàm ngắt kết nối được gọi Hàm disconnect sẽ thực hiện hai công việc chính là hủy các dữ liệu về thiết bị đã lưu trữ từ hàm thăm dò bằng cách thiết lập giá trị NULL cho interface và hủy đăng kí lớp thiết bị.
3 Quy trình viết Driver Keyboard trên Linux
2.1.1 Định nghĩa mảng bảng mã bàn phím
Mỗi phím được xác định bởi một số thứ tự gọi là scan code (scan code là một giá trị 8 bit).
Khi một phím được nhận xuống, bàn phím thông báo và chuyển scan code của phím ấy cho computer.
Nếu phím đã được nhấn xuống và giữ im (không buông tay) sau một thời gian (initial delay), bàn phím sẽ tiếp tục chuyển scan code của phím ấy cho computer theo một tốc độ xác định (repeat rate).
Ta gọi scan code trong trường hợp này là Pressed – key.
Khi phím được ngưng nhấn (buông tay), bàn phím sẽ chuyển scan code của phím ấy cho computer sau khi cộng thêm 128 (dựng bit số 7).
Ta gọi scan code trong trường hợp này là Released – key.
Hình 9: Bảng mã scan code
Từ bảng mã scan code, định nghĩa ra được mảng chứa bảng mã bàn phím (key code) như sau: static const unsigned char usb_kbd_keycode[256] = {
2.3.2 Khai báo danh sách các thiết bị có thể được điều khiển bởi Driver
Khi viết một USB Driver cần chỉ định xem driver này sẽ được sử dụng cho các thiết bị hoặc các lớp thiết bị nào Cấu trúc usb_device_id cung cấp một kiểu thiết bị, nó có thể là một thiết bị cụ thể cũng có thể là một lớp thiết bị Có một số macro để khởi tạo cấu trúc này Ví dụ sử dụng macro USB_INTERFACE_INFO (USB_INTERFACE_CLASS_HID,
USB_INTERFACE_SUBCLASS_BOOT,USB_INTERFACE_PROTOCOL_KEYBOAR D) để tạo ra một cấu trúc usb_device_id
Sau khi đã tạo ra một cấu trúc usb_device_id ta cần phải khai báo cấu trúc này với USB Core, để làm việc này ta sử dụng macro:
MODULE_DEVICE_TABLE(usb, usb_device_id[]); Ở đây ta khai báo một struct usb_device_id có chứa thông tin như sau:
- USB_INTERFACE_PROTOCOL_KEYBOARD = 1 static struct usb_device_id usb_kbd_id_table [] = {
{USB_INTERFACE_INFO (3, 1, 1)},/* 3,1,1 represent the interface class, interface subclass, interface protocol; 3,1,1 is the keyboard
MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
2.3.3 Khai báo cấu trúc dữ liệu liên quan tới thiết bị
Trong quá trình thăm dò thiết bị, có rất nhiều thông tin về thiết bị ta truy nhập được và cần phải lưu lại để sử dụng về sau Các thông tin cần thiết bao gồm: thiết bị cụ thể (được xác định bởi cấu trúc usb_device), thông tin các Configuration, Interface, Endpoint của thiết bị Tùy theo đặc điểm của từng phần cứng cụ thể mà ta định nghĩa một cấu trúc dữ liệu phù hợp Ở đây định nghĩa một cấu trúc bàn phím USB như sau: struct usb_kbd { struct input_dev *dev; struct usb_device *usbdev; unsigned char old[8]; struct urb *irq; char name[128]; char phys[64]; unsigned char *new; dma_addr_t new_dma;
- struct input_dev *dev: con trỏ dùng để mô tả 1 thiết bị đầu vào.
- struct usb_device *usbdev: con trỏ dùng để trỏ tới thiết bị đã gửi URB đi.
- unsigned char old[8]: dữ liệu được nhận trong quá trình từ irq URB đại diện cho những phím nào đã được nhấn Bằng cách so sánh các danh sách các phím được nhấn hiện tại, chúng ta có thể các phím đã được nhấn.
- struct urb *irq: con trỏ kiểu URB – USB request block URB để nhận danh sách các phím được nhận khi nhấn một phím mới hoặc một phím đã được nhả ra.
- char name[128]: tên bàn phím.
- char phys[64]: đường dẫn vật lý của bàn phím.
- unsigned char *new: biến dữ liệu làm bộ đêm cho irq URB.
- dma_addr_t new_dma: biến dữ liệu theo cơ cơ chế DMA, là địa chỉ DMA cho irq URB.
2.3.4 Xử lý yêu cầu ngắt
Hàm xử lý yêu cầu ngắt, được gọi khi có yêu cầu ngắt Gửi URB ngắt trong usb_kbd_open(), khi URB đã được xử lý, lời gọi này sẽ được gọi lại và gửi URB một lần nữa static void usb_kbd_irq(struct urb *urb)
/* Lấy ra private object, được lữu trữ con URB context với usb_fill_int_urb() trong usb_kbd_probe() */ struct usb_kbd *kbd = urb->context; int i; switch (urb->status) { case 0:/* thành công */ break; case -ECONNRESET:/* hủy kết nối */ case -ENOENT: case -ESHUTDOWN: return;
/* -EPIPE: xóa lỗi tạm dừng */ default:/* lỗi */ goto resubmit;
- *kbd: con trỏ mô tả thiết bị kiểu usb_kbd như đã được định nghĩa ở khởi tạo.
- Status là 1 biến kiểu nguyên thuộc struct urb Khi quá trình URB được xử lý hoặc hoàn tất, status sẽ được cập nhật giá trị tương ứng với trạng thái hiện tại của URB. Giá trị biến status sau đó sẽ được truyền vào hàm xử lý ngắt, 1 cấu trúc điều kiện sẽ kiểm tra giá trị biến này.
TH1: Nếu status = 0, tức là quá trình truyền URB thành công.
KẾT QUẢ
Phần code nhóm bọn em dựa trên kết quả chương trình usb_kb_driver.c của Venkat Prashanth B U Tổng hợp các hàm trên chúng em viết một file usbkb_driver bằng lệnh: gedit usbkb_driver.c Để biên dịch (build) một Linux kernel module, sử dụng phương pháp Kbuild. Theo phương pháp này, cần tạo ra 2 file: một file có tên là Makefile, file còn lại có tên là Kbuild
File Makefile có mã nguồn như sau:
KDIR = /lib/modules/`uname -r`/build all: make -C $(KDIR) M=`pwd` clean: make -C $(KDIR) M=`pwd` clean
Tiếp theo, tạo ra file Kbuild nằm trong cùng thư mục với Makefile có mã nguồn như sau:
EXTRA_CFLAGS = -Wall obj-m = usbkb_driver.o
- Biến obj-m chỉ ra rằng: object file sẽ được biên dịch theo kiểu kernel module
- Cờ -Wall cho phép trình biên dịch hiển thị tất cả các bản tin cảnh báo trong quá trình biên dịch Để tạo ra kernel module, gõ lệnh make Khi gõ lệnh "make", tiến trình make sẽ dựa vào Makefile và Kbuild để biên dịch mã nguồn, tạo ra kernel module
Kết quả sau khi make file:
Hình 10: Kết quả make fileSau khi make file sẽ tạo ra file usbkb_driver.ko (ko là viết tắt của kernel object),đây chính là kernel module Để biết các thông tin về module, ta sử dụng lệnh modinfo
Hình 11: Thông tin của module Để lắp module vào trong kernel, ta sử dụng insmod Sau khi lắp xong dùng lệnh lsmod để kiểm tra xem module đã được load thành công hay chưa Tiếp theo, ta sẽ sử dụng lệnh dmesg để theo dõi quá trình hoạt động của module
Hình 12: Quá trình đăng ký của module
Sau khi cài driver để kiểm tra xem driver đã chạy được chưa ta vào thư mục /sys/bus/usb/drivers/usbhid/ để xem number device, ở đây number device là 1-2:1.0 Sau đó ta dùng lệnh echo -n "1-2:1.0" > sudo /sys/bus/usb/drivers/usbhid/unbind để hủy liên kết với driver usbhid có sẵn mặc định trong Ubuntu, rồi dùng lệnh echo -n "1-2:1.0"
> sudo /sys/bus/usb/drivers/usbhid/bind để liên kết với driver usbhid ta vừa cài vào Sau đó dùng lệnh sudo rmmod usbhid để gỡ driver usbhid mặc định rồi nhấn thử một vài phím trên bàn phím USB để xem có hoạt động với driver vừa cài không.
Hình 13: Hủy liên kết với driver usbhid và liên kết với driver usbkbd
Hình 14: Gỡ driver usbhid mặc định Lúc này ta khi ta nhấn phím trên bàn phím USB vẫn hoạt động bình thường chứng tỏ driver đã hoạt động thành công.
Qua quá trình tìm hiểu, nghiên cứu và thực hiện đề tài, chúng em đã hiểu thêm về các kiến thức cần thiết và bổ ích trong cả học tập cũng như công việc sau này, đặc biệt như Ubuntu, giao thức usb, quy trình viết driver cho usb, cách biên dịch module kernel,
Nhóm chúng em xin gửi lời cảm ơn chân thành đến TS Nguyễn Thanh Bình đã hướng dẫn, cung cấp các kiến thức cơ bản cũng như đưa ra tiến trình tìm hiểu đề tài cụ thể để nhóm chúng em có thể hoàn thành được mục tiêu của bài tập lớn Trong quá trình thực hiện đề tài, nhóm chúng em đã cố gắng nhưng cũng không thể tránh khỏi những thiếu sót Chúng em rất mong nhận được chỉ dẫn và góp ý của thầy để đề tài ngày càng hoàn thiện hơn
Chúng em xin chân thành cảm ơn!