I. Lập trình mã lệnh trong character driver:
2. Cấu trúc chương trình character device driver dạng 2:
Cấu trúc chương trình character device driver dạng 2 cũng tương tự như dạng 1, nhưng điểm khác biệt là kỹ thuật tạo và đăng ký thiết bị mới vào hệ thống. Để thuận tiện cho việc tham khảo chúng tôi không ngại nhắc lại những bước tương tự và giải thích những điều mới khi tiếp xúc với câu lệnh.
/*Bước 1: Khai báo những thư viện cần thiết cho các lệnh dùng trong chương trình driver*/ #include <linux/module.h> #include <linux/errno.h> #include <linux/init.h> #include <asm/uaccess.h> #include <asm/atomic.h> #include <linux/miscdevice.h>
/*Bước 2: Định nghĩa những hằng số cần dùng trong chương trình driver*/
#define ... ...
/*Bước 3: Khai báo số định danh thiết bị, các biến phục vụ đồng bộ hóa dữ liệu*/ /*Biến lưu số major của thiết bị*/
static int dev_major;
/*Khai báo biến atomic_t dùng đồng bộ hóa tài nguyên driver thiết bị*/ /*Cách đồng bộ hóa tài nguyên của thiết bị:
Trước khi mở thao tác với driver thiết bị, kỹ thuật atomic sẽ kiểm tra xem thiết bị đã được mở hay chưa, nếu thiết bị đã được mở (nhận biết bằng số counter) thì khơng cho phép truy cập đến thiết bị này, thông báo lỗi cho người sử dụng. Ngược lại, cho phép mở thiết bị, thực thi những câu lệnh tiếp theo trong hệ thống. Cụ thể là:
- Khi thiết bị được mở, chúng ta giảm biến kiểu atomic_t một đơn vị, lúc này giá trị biến kiểu atomic_t bằng 0. Trong q trình mở, hay đóng đều phải có sự so sánh biến atomic_t.
- Chỉ đóng driver thiết bị khi biến kiểu atomic_t bằng 1. Chỉ mở khi biến kiểu atomic_t bằng 0.
- Đóng thiết bị, thực hiện tăng biến kiểu atomic_t. Mở thiết bị, thực hiện giảm biến kiểu atomic_t.*/
static atomic_t device_open_cnt = ATOMIC_INIT(1);
/*Bước 4: Khai báo các biến dùng trong chương trình driver*/
...
/*Bước 5: Khai báo và định nghĩa các hàm, chương trình con cần sử dụng trong quá trình lập trình driver*/
...
/*Bước 6: Khai báo và định nghĩa hàm open, là hàm được thực thi khi thực hiện lệnh open() trong user application*/
static int device_open (struct inode *inode, struct file *file) {
/*Khai báo biến lưu mã lỗi trả về*/
int result = 0;
/*Khai báo biến lưu số minor của thiết bị, đồng thời cập nhật số minor của thiết bị trong hệ thống*/
unsigned int device_minor = MINOR (inode->i_rdev);
/*Thực hiện kiểm tra biến atomic_t trong quá trình mở thiết bị nhiều lần*/
if (!atomic_dec_and_test(&device_open_cnt)) {
/*Tăng biến kiểu atomic_t*/
tomic_inc(&device_open_cnt);
/*In ra thông báo thiết bị muốn mở đang bận*/
printk(KERN_ERR DRVNAME ": Device with minor ID %d already in use\n", dev_minor);
return -EBUSY; }
/*Thực hiện những công việc tiếp theo nếu mở tập tin thiết bị thành công*/
...
/*Trả về mã lỗi cuối cùng nếu q trình thực thi khơng bị lỗi*/
return result; }
/*Bước 7: Khai báo và định nghĩa hàm close(), được thực hiện khi thực thi hàm close trong user application*/
static int device_close (struct inode *inode, struct file *file) {
/*Thực hiện đồng bộ hóa counter trước khi tăng*/
smp_mb_before_atomic_inc();
/*Tăng biến đếm atomic khi đóng tập tin thiết bị*/
atomic_inc(&device_open_cnt);
/*Trả về mã lỗi 0 cho hàm close()*/
return 0; }
/*Bước 8: Khai báo và cập nhật cấu trúc lệnh file_operations cho thiết bị*/
struct file_operations device_fops = {
/*Gán hàm device_read của thiết bị vào giao diện chuẩn, nếu sử dụng*/
.read = device_read,
/*Gán hàm device_write của thiết bị vào giao diện chuẩn, nếu sử dụng*/
.write = device_write,
/*Gán hàm device_open của thiết bị vào giao diện chuẩn open*/
.open = device_open,
/*Gán hàm device_release của thiết bị vào giao diện chuẩn release*/
.release = device_release, };
static struct misdevice device_dev = {
/*Thực hiện kỹ thuật lấy số minor dộng cho thiết bị bằng hằng số định nghĩa sẵn trong thư viện linux/miscdevice.h*/
.minor = MISC_DYNAMIC_MINOR,
/*Cập nhật tên cho thiết bị*/
.name = “device”,
/*Cập nhật cấu trúc lệnh đã được định nghĩa*/
.fops = device_fops, };
/*Bước 10: Khai báo định nghĩa hàm init thực hiện khi cài đặt driver vào hệ thống*/ /*Tương tự như trong dạng 1, tuy nhiên với kỹ thuật mới này, trong hàm init chúng ta không cần phải lấy số định danh thiết bị, khởi tạo vùng nhớ cho driver, cài đặt driver vào hệ thống. Tất cả những công việc này được thực hiện bởi một hàm duy nhất đó là misc_register()*/
static int __init device_mod_init(void) {
/*Những lệnh cần thực hiện khi cài đặt driver vào hệ thống*/
...
/*Thực hiện đăng ký driver vào hệ thống, kết hợp trả về mã lỗi*/
return misc_register(&devive_dev); }
/*Bước 11: Khai báo và định nghĩa hàm exit()*/
static void __exit device_mod_exit (void) {
/*Thực hiện những công việc khôi phục hệ thống trước khi driver bị tháo gỡ*/
...
/*Tháo gỡ thiết bị mang tên là device_dev*/
misc_deregister (&device_dev); }
/*Bước 12: Gắn các hàm exit và init vào hệ thống driver*/
module_init (device_mod_init); module_exit (device_mod_exit);
/*Bước 13: Cập nhật các thông tin cá nhân cho driver*/
MODULE_LICENSE("Bản quyền driver thông thường là GPL"); MODULE_AUTHOR("Tên người viết driver");
MODULE_DESCRIPTION("Mô tả khái quát thông tin về driver");