FREE RTOS CƠ BẢN VỀ DRIVER TRÊN LINUX Bài viết này là bài mở đầu trong loạt bài viết về device driver trên Linux, giải thích các vấn đề cơ bản về driver thiết bị (device driver) trên Linux Vai trò của[.]
CƠ BẢN VỀ DRIVER TRÊN LINUX Bài viết mở đầu loạt viết device driver Linux, giải thích vấn đề driver thiết bị (device driver) Linux Vai trò driver Driver trình điều khiển có vai trị điều khiển, quản lý, giám sát thực thể quyền Bus driver làm việc với đường bus, device driver làm việc với thiết bị (chuột, bàn phím, hình, đĩa cứng, camera, …) Có thể lấy ví dụ tương tự vai trị phi công hệ thống bay tự động giám sát phi công, thành phần phần cứng điều khiển driver điều khiển phần cứng khác mà quản lý driver Trường hợp này, phần cứng có vai trị điều khiển gọi device controller Bản thân controller cần driver Ví dụ: hard disk controller, display controller, audio controller, … quản lý thiết bị kết nối với chúng, mà nói cách kỹ thuật IDE controller, PCI controller, USB controller, SPI controller, I2C controller, … Các khái niệm minh họa tổng quan hình sau: Các device controller thông thường kết nối với CPU thông qua đường bus (PCI, IDE, USB, SPI, …) Trong vi điều khiển, CPU device controller thường thiết kế chip Điều cho phép giảm kích thước giá thành, phù hợp với phát triển hệ thống nhúng Mà mặt nguyên tắc, khơng có khác biệt đối lớn driver hệ thống máy tính cá nhân Hai nhiệm vụ driver Các bus driver cung cấp giao diện đặc tả cho giao thức phần cứng tương ứng Nó nằm tầng mơ hình phân lớp phần mềm hệ điều hành Nằm device driver thực để vận hành thiết bị, mang đặc trưng thiết bị xác định Ngồi ra, mục đích quan trọng driver thiết bị cung cấp giao diện trừu tường hóa cho người sử dụng, tức cung cấp giao diện lên tầng hệ điều hành Một cách tổng quan, driver bao gồm phần quan trọng: a) giao tiếp với thiết bị (Devicespecific) b) giao tiếp với hệ điều hành (OS-specific) Thành phần giao tiếp với thiết bị (device-specific) driver giống tất hệ điều hành Nó hiểu giải mã thơng tin thiết bị (chi tiết kỹ thuật, kiểu thao tác, hiệu năng, cách lập trình giao tiếp với thiết bị, …) Thành phần giao tiếp với hệ điều hành (OS-specific) gắn kết chặt chẽ với chế hệ điều hành, khác driver Linux driver Windows, MacOS, … Mơ hình phân lớp theo chiều dọc Trên Linux, device driver cung cấp giao diện “system call” (giao diện gọi hàm hệ thống) đến tầng ứng dụng cho người dùng; coi ranh giới tầng nhân (kernel space) tầng người dùng (user space) Linux Mơ hình phân tầng hình vẽ Tùy thuộc vào đặc trưng của driver với hệ điều hành, driver Linux phân chia thành loại (phân cấp theo chiều dọc): - Packet-oriented or the network vertical (driver hướng gói liệu) - Block-oriented or the storage vertical (driver hướng khối liệu) - Byte-oriented or the character vertical (driver hướng byte/ký tự) Packet-oriented hay network driver gồm phần: a) network protocol stack b) network interface card (NIC) device drivers, đơn giản network device driver (có thể Ethernet, Wi-Fi, giao tiếp mạng khác,…) Block-oriented hay storage driver gồm phần: a) File-system drivers để giải mã định dạng khác phân vùng lưu trữ khác (FAT, ext, …) b) Block device drivers cho giao thức phần cứng ứng với thiết bị lưu trữ khác (IDE, SCSI, MTD, …) Các Byte-oriented hay character driver lại tiếp tục phân chia thành lớp (sub-classified) tty driver, input driver, console driver, frame-buffer drivers, sound driver, … (tương ứng với giao tiếp RS232, PS/2, VGA, I2C, SPI, …) VIẾT DRIVER ĐẦU TIÊN TRÊN LINUX Bài viết nằm loạt viết device driver Linux, trình bày cách nạp driver vào hệ thống thời điểm hệ thống thực thi mà không cần biên dịch, nạp lại nhân hệ điều hành (nạp động) làm quen với xây dựng driver Nạp động driver vào hệ thống Các driver nạp động vào hệ thống thường xây dựng dựa chế modules biên dịch tạo thành file với đuôi mở rộng ko (kernel object) Mỗi hệ thống Linux qui định nơi để chứa modules biên dịch có sẵn, thường tổ chức thư mục /lib/modules//kernel đó, / phiên nhân hệ thống Linux sử dụng (có thể lấy lệnh uname –r) Ví dụ xem thơng tin modules có sẵn hình Hình Xem module sẵn có Linux Để nạp động, gỡ modules, sử dụng lệnh sau (nằm thư mục /sbin, cần thực thi quyền root) § lsmod — Liệt kê modules nạp § insmod — Nạp module vào hệ thống (yêu cầu modules phụ thuộc có phải nạp trước) § modprobe — Nạp module vào hệ thống (Tự động tìm module phụ thuộc có để nạp) § rmmod — Gỡ module khỏi hệ thống Ví dụ sau minh họa thao tác lệnh để nạp driver liên quan đến hệ thống quản lý file FAT Các file modules cần nạp fat.ko, vfat.ko nằm thư mục fat đường dẫn /lib/modules/`uname -r`/kernel/fs Hình Các thao tác (nạp, gỡ) module Linux Module vfat phụ thuộc vào module fat, fat.ko cần nạp trước Việc thực tự động sử dụng lệnh modprobe Sử dụng lệnh rmmod để gỡ modules khỏi hệ thống (không cần phải xác định đuôi mở rộng ko) Viết driver Một driver khơng thể tự thực thi mà hoạt động tương tự thư viện nạp đăng ký hàm ứng dụng chạy Driver viết C, khơng có hàm main() Hơn nữa, driver nạp liên kết với hệ điều hành, nên cần biên dịch giống cách biên dịch nhân hệ điều hành, header files sử dụng mã nguồn driver mà nhân hệ điều hành cung cấp, hàm thư viện lập trình C (mà thường để thư mục /usr/include) Một điểm thú vị khác mã nguồn nhân lập trình theo kiểu hướng đối tượng C, mã nguồn driver tương tự Bất kỳ driver Linux có hàm tạo (constructor) hàm hủy (destructor) Hàm tạo driver gọi driver nạp vào nhân hệ thống, hàm hủy gọi gỡ driver khỏi hệ thống (dùng lệnh rmmod) Hai hàm giống hàm thông thường, ngoại trừ việc chúng cần có thị _init _exit tương ứng phải đăng macros module_init() module_exit(), (được định nghĩa tệp tiêu đề module.h) Sau mã nguồn cho driver đơn giản linux /* ofd.c – Our First Driver code */ #include #include #include static int init ofd_init(void) /* Constructor */ { printk(KERN_INFO "Hello: ofd registered"); return 0; } static void exit ofd_exit(void) /* Destructor */ { ký sử dụng printk(KERN_INFO "Goodbye: ofd unregistered"); } module_init(ofd_init); module_exit(ofd_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Anil Kumar Pugalia"); MODULE_DESCRIPTION("Our First Driver"); Mã nguồn driver lưu thành file ofd.c Chú ý mã nguồn không cho phép thư viện tầng ứng dụng stdio.h, thay sử dụng thư viện tầng nhân kernel.h Hàm printk() tương đương printf() nhiên liệu không xuất thiết bị chuẩn mà xuất log file kernel phải sử dụng công cụ đặc biệt để mở (Ví dụ lệnh dmesg công cụ Log File Viewer Ubuntu) Tệp tiêu đề version.h bao gồm thơng tin phiên module tương thích với nhân mà module nạp vào Các macros MODULE_* cung cấp thơng tin liên quan đến module, đóng vai trị chữ ký cho module Biên dịch driver Sau có mã nguồn C driver đơn giản trên, cần tiến hành biên dịch để tạo file module (có mở rộng ko, trường hợp file ofd.ko) Chúng ta sử dụng cách thức biên dịch tầng nhân để làm điều Cụ thể cần viết Makefile thực việc đăng ký thư viện biên dịch tầng nhân (kernel build system) từ mã nguồn nhân, đăng ký driver cần biên dịch Do vậy, trước chạy Makefile để biên dịch driver Linux, cần phải có mã nguồn nhân (kernel source) hệ thống tiếp nhận driver Giả sử mã nguồn nhân (kernel source) hệ thống tương ứng cài /usr/src/linux, (nếu khơng cần phải vị trí biến KERNEL_SOURCE Makefile) Sau có mã nguồn driver (ofd.c) Makefile, đặt thư mục, sử dụng lệnh make để build driver Quá trình biên dịch thành cơng tạo file ofd.ko để nạp vào hệ thống $ make make -C /usr/src/linux SUBDIRS= modules make[1]: Entering directory `/usr/src/linux' CC [M] /ofd.o Building modules, stage MODPOST modules CC ./ofd.mod.o LD [M] /ofd.ko make[1]: Leaving directory `/usr/src/linux' Nạp module ofd.ko vào hệ thống thực với quyền root (hoặc sudo) # su # insmod ofd.ko # lsmod | head -10