- Linux設備驅動開發詳解:基于最新的Linux4.0內核
- 宋寶華
- 1009字
- 2018-12-31 20:25:17
1.6.2 Linux下的LED驅動
在Linux下,可以使用字符設備驅動的框架來編寫對應于代碼清單1.3的LED設備驅動(這里僅僅是為了方便講解,內核中實際實現了一個提供sysfs節點的GPIO LED驅動,位于drivers/leds/leds-gpio.c中),操作硬件的LightInit()、LightOn()、LightOff()函數仍然需要,但是,遵循Linux編程的命名習慣,重新將其命名為light_init()、light_on()、light_off()。這些函數將被LED設備驅動中獨立于設備并針對內核的接口進行調用,代碼清單1.4給出了Linux下的LED驅動,此時讀者并不需要能讀懂這些代碼。
代碼清單1.4 Linux操作系統下的LED驅動
1 #include .../* 包含內核中的多個頭文件 */ 2 /* 設備結構體 */ 3 struct light_dev { 4 struct cdev cdev; /* 字符設備cdev結構體 */ 5 unsigned char vaule; /* LED亮時為1,熄滅時為0,用戶可讀寫此值 */ 6 }; 7 struct light_dev *light_devp; 8 int light_major = LIGHT_MAJOR; 9 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); 10 MODULE_LICENSE("Dual BSD/GPL"); 11 /* 打開和關閉函數 */ 12 int light_open(struct inode *inode, struct file *filp) 13 { 14 struct light_dev *dev; 15 /* 獲得設備結構體指針 */ 16 dev = container_of(inode->i_cdev, struct light_dev, cdev); 17 /* 讓設備結構體作為設備的私有信息 */ 18 filp->private_data = dev; 19 return 0; 20 } 21 int light_release(struct inode *inode, struct file *filp) 22 { 23 return 0; 24 } 25 /* 讀寫設備:可以不需要 */ 26 ssize_t light_read(struct file *filp, char __user *buf, size_t count, 27 loff_t *f_pos) 28 { 29 struct light_dev *dev = filp->private_data; /* 獲得設備結構體 */ 30 if (copy_to_user(buf, &(dev->value), 1)) 31 return -EFAULT; 32 return 1; 33 } 34 ssize_t light_write(struct file *filp, const char __user *buf, size_t count, 35 loff_t *f_pos) 36 { 37 struct light_dev *dev = filp->private_data; 38 if (copy_from_user(&(dev->value), buf, 1)) 39 return -EFAULT; 40 /* 根據寫入的值點亮和熄滅LED */ 41 if (dev->value == 1) 42 light_on(); 43 else 44 light_off(); 45 return 1; 46 } 47 /* ioctl函數 */ 48 int light_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, 49 unsigned long arg) 50 { 51 struct light_dev *dev = filp->private_data; 52 switch (cmd) { 53 case LIGHT_ON: 54 dev->value = 1; 55 light_on(); 56 break; 57 case LIGHT_OFF: 58 dev->value = 0; 59 light_off(); 60 break; 61 default: 62 /* 不能支持的命令 */ 63 return -ENOTTY; 64 } 65 return 0; 66 } 67 struct file_operations light_fops = { 68 .owner = THIS_MODULE, 69 .read = light_read, 70 .write = light_write, 71 .ioctl = light_ioctl, 72 .open = light_open, 73 .release = light_release, 74 }; 75 /* 設置字符設備cdev結構體 */ 76 static void light_setup_cdev(struct light_dev *dev, int index) 77 { 78 int err, devno = MKDEV(light_major, index); 79 cdev_init(&dev->cdev, &light_fops); 80 dev->cdev.owner = THIS_MODULE; 81 dev->cdev.ops = &light_fops; 82 err = cdev_add(&dev->cdev, devno, 1); 83 if (err) 84 printk(KERN_NOTICE "Error %d adding LED%d", err, index); 85 } 86 /* 模塊加載函數 */ 87 int light_init(void) 88 { 89 int result; 90 dev_t dev = MKDEV(light_major, 0); 91 /* 申請字符設備號 */ 92 if (light_major) 93 result = register_chrdev_region(dev, 1, "LED"); 94 else { 95 result = alloc_chrdev_region(&dev, 0, 1, "LED"); 96 light_major = MAJOR(dev); 97 } 98 if (result < 0) 99 return result; 100 /* 分配設備結構體的內存 */ 101 light_devp = kmalloc(sizeof(struct light_dev), GFP_KERNEL); 102 if (!light_devp) { 103 result = -ENOMEM; 104 goto fail_malloc; 105 } 106 memset(light_devp, 0, sizeof(struct light_dev)); 107 light_setup_cdev(light_devp, 0); 108 light_gpio_init(); 109 return 0; 110 fail_malloc: 111 unregister_chrdev_region(dev, light_devp); 112 return result; 113 } 114 /* 模塊卸載函數 */ 115 void light_cleanup(void) 116 { 117 cdev_del(&light_devp->cdev); /* 刪除字符設備結構體 */ 118 kfree(light_devp); /* 釋放在light_init中分配的內存 */ 119 unregister_chrdev_region(MKDEV(light_major, 0), 1); /* 刪除字符設備 */ 120 } 121 module_init(light_init); 122 module_exit(light_cleanup);
上述代碼的行數與代碼清單1.3已經不能相比了,除了代碼清單1.3中的硬件操作函數仍然需要外,代碼清單1.4中還包含了大量暫時陌生的元素,如結構體file_operations、cdev,Linux內核模塊聲明用的MODULE_AUTHOR、MODULE_LICENSE、module_init、module_exit,以及用于字符設備注冊、分配和注銷的函數register_chrdev_region()、alloc_chrdev_region()、unregister_chrdev_region()等。我們也不能理解為什么驅動中要包含light_init()、light_cleanup()、light_read()、light_write()等函數。
此時,我們只需要有一個感性認識,那就是,上述暫時陌生的元素都是Linux內核為字符設備定義的,以實現驅動與內核接口而定義的。Linux對各類設備的驅動都定義了類似的數據結構和函數。
推薦閱讀
- Linux網絡管理與配置(第2版)
- Linux運維實戰:CentOS7.6操作系統從入門到精通
- WordPress Mobile Web Development:Beginner's Guide
- 深入Linux內核架構與底層原理(第2版)
- 數據中心系統工程及應用
- 8051軟核處理器設計實戰
- 突破平面3ds Max動畫設計與制作
- AutoCAD 2014中文版從入門到精通
- 新編電腦辦公(Windows 10+ Office 2013版)從入門到精通
- Linux軟件管理平臺設計與實現
- μC/OS-III內核實現與應用開發實戰指南:基于STM32
- Hadoop Real-World Solutions Cookbook
- VMware vSphere 5.1 Cookbook
- Administering ArcGIS for Server
- Instant Responsive Web Design