一个简单的Linux驱动示例
2016-04-05 19:55
405 查看
本文参考百度文库“linux驱动开发入门”点击打开链接和转载博文:点击打开链接。
一、基本知识
Linux设备驱动分为:字符设备、块设备和网络设备。原理图如下:
二、示例
示例主要转载自博客园的博客,见上。只是我采用的的Linux内核版本比那篇博文的新,有小许改动,粘贴代码如下:
内核版本:
ry@ubuntu:/$ uname -a
Linux ubuntu 3.16.0-30-generic #40~14.04.1-Ubuntu SMP Thu Jan 15 17:43:14 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
文件:hello_mod.c
头文件:hello_mod_ioctl.h
Makefile文件:(注意:Makefile的'M'要大写)
以上三个文件即为驱动代码
另外,再给一个应用层测试代码,并共用驱动的头文件
hello_mod_test.c文件:
最后,安装原博客编译和查看结果。
需要注意的是,需要到“/var/log/”目录下着“syslog”文件。
一、基本知识
Linux设备驱动分为:字符设备、块设备和网络设备。原理图如下:
二、示例
示例主要转载自博客园的博客,见上。只是我采用的的Linux内核版本比那篇博文的新,有小许改动,粘贴代码如下:
内核版本:
ry@ubuntu:/$ uname -a
Linux ubuntu 3.16.0-30-generic #40~14.04.1-Ubuntu SMP Thu Jan 15 17:43:14 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
文件:hello_mod.c
/* * ===================================================================================== * * Filename: hello.c * * Description: hello_mod * * Version: 1.0 * Created: 01/28/2011 05:07:55 PM * Revision: none * Compiler: gcc * * Author: Tishion (shion), tishion@163.com * Company: LIM * * ===================================================================================== */ #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/semaphore.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/ioctl.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/string.h> #include "hello_mod_ioctl.h" #define MAJOR_NUM 250 #define MINOR_NUM 0 #define IN_BUF_LEN 256 #define OUT_BUF_LEN 512 MODULE_AUTHOR("Tishion"); MODULE_DESCRIPTION("Hello_mod driver by tishion"); static struct class * hello_class; static struct cdev hello_cdev; static dev_t devnum = 0; static char * modname = "hello_mod"; static char * devicename = "hello"; static char * classname = "hello_class"; static int open_count = 0; static struct semaphore sem; static DEFINE_SPINLOCK(spin); static char * inbuffer = NULL; static char * outbuffer = NULL; static lang_t langtype; static int hello_mod_open(struct inode *, struct file *); static int hello_mod_release(struct inode *, struct file *); static ssize_t hello_mod_read(struct file *, char *, size_t, loff_t *); static ssize_t hello_mod_write(struct file *, const char *, size_t, loff_t *); static long hello_mod_ioctl(struct file *, unsigned int, unsigned long); struct file_operations hello_mod_fops = { .owner = THIS_MODULE, .open = hello_mod_open, .read = hello_mod_read, .write = hello_mod_write, .unlocked_ioctl = hello_mod_ioctl, .release = hello_mod_release, }; static int hello_mod_open(struct inode *inode, struct file *pfile) { printk("+hello_mod_open()!/n"); spin_lock(&spin); if(open_count) { spin_unlock(&spin); return -EBUSY; } open_count++; spin_unlock(&spin); printk("-hello_mod_open()!/n"); return 0; } static int hello_mod_release(struct inode *inode, struct file *pfile) { printk("+hello_mod_release()!/n"); open_count--; printk("-hello_mod_release()!/n"); return 0; } static ssize_t hello_mod_read(struct file *pfile, char *user_buf, size_t len, loff_t *off) { printk("+hello_mod_read()!/n"); if(down_interruptible(&sem)) { return -ERESTARTSYS; } memset(outbuffer, 0, OUT_BUF_LEN); printk(" +switch()/n"); switch(langtype) { case english: printk(" >in case: english/n"); sprintf(outbuffer, "Hello! %s.", inbuffer); break; case chinese: printk(" >in case: chinese/n"); sprintf(outbuffer, "你好! %s.", inbuffer); break; case pinyin: printk(" >in case: pinyin/n"); sprintf(outbuffer, "ni hao! %s.", inbuffer); break; default: printk(" >in case: default/n"); break; } printk(" -switch()/n"); if(copy_to_user(user_buf, outbuffer, len)) { up(&sem); return -EFAULT; } up(&sem); printk("-hello_mod_read()!/n"); return 0; } static ssize_t hello_mod_write(struct file *pfile, const char *user_buf, size_t len, loff_t *off) { printk("+hello_mod_write()!/n"); if(down_interruptible(&sem)) { return -ERESTARTSYS; } if(len > IN_BUF_LEN) { printk("Out of input buffer/n"); return -ERESTARTSYS; } if(copy_from_user(inbuffer, user_buf, len)) { up(&sem); return -EFAULT; } up(&sem); printk("-hello_mod_write()!/n"); return 0; } static long hello_mod_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg) { int err = 0; printk("+hello_mod_ioctl()!/n"); printk(" +switch()/n"); switch(cmd) { case HELLO_IOCTL_RESETLANG: printk(" >in case: HELLO_IOCTL_RESETLANG/n"); langtype = english; break; case HELLO_IOCTL_GETLANG: printk(" >in case: HELLO_IOCTL_GETLANG/n"); err = copy_to_user((int *)arg, &langtype, sizeof(int)); break; case HELLO_IOCTL_SETLANG: printk(" >in case: HELLO_IOCTL_SETLANG/n"); err = copy_from_user(&langtype,(int *)arg, sizeof(int)); break; default: printk(" >in case: default/n"); err = ENOTSUPP; break; } printk(" -switch()/n"); printk("-hello_mod_ioctl()!/n"); return err; } static int __init hello_mod_init(void) { int result; printk("+hello_mod_init()!/n"); devnum = MKDEV(MAJOR_NUM, MINOR_NUM); result = register_chrdev_region(devnum, 1, modname); if(result < 0) { printk("hello_mod : can't get major number!/n"); return result; } cdev_init(&hello_cdev, &hello_mod_fops); hello_cdev.owner = THIS_MODULE; hello_cdev.ops = &hello_mod_fops; result = cdev_add(&hello_cdev, devnum, 1); if(result) printk("Failed at cdev_add()"); hello_class = class_create(THIS_MODULE, classname); if(IS_ERR(hello_class)) { printk("Failed at class_create().Please exec [mknod] before operate the device/n"); } else { device_create(hello_class, NULL, devnum,NULL, devicename); } open_count = 0; langtype = english; inbuffer = (char *)kmalloc(IN_BUF_LEN, GFP_KERNEL); outbuffer = (char *)kmalloc(OUT_BUF_LEN, GFP_KERNEL); sema_init(&sem, 1); printk("-hello_mod_init()!/n"); return 0; } static void __exit hello_mod_exit(void) { printk("+hello_mod_exit!/n"); kfree(inbuffer); kfree(outbuffer); cdev_del(&hello_cdev); device_destroy(hello_class, devnum); class_destroy(hello_class); unregister_chrdev_region(devnum, 1); printk("-hello_mod_exit!/n"); return ; } module_init(hello_mod_init); module_exit(hello_mod_exit); MODULE_LICENSE("GPL");
头文件:hello_mod_ioctl.h
/* * ===================================================================================== * * Filename: hello_mod_ioctl.h * * Description: define the cmd supported by hello_mod * * Version: 1.0 * Created: 06/19/2011 10:24:20 PM * Revision: none * Compiler: gcc * * Author: Tishion (shion), tishion@163.com * Company: LIM * * ===================================================================================== */ #ifndef __HELLO_MOD_IOCTL_H__ #define __HELLO_MOD_IOCTL_H__ #define HELLO_MAGIC 12 #define HELLO_IOCTL_RESETLANG _IO(HELLO_MAGIC,0) //set langtype = english #define HELLO_IOCTL_GETLANG _IOR(HELLO_MAGIC,1,int) //get langtype #define HELLO_IOCTL_SETLANG _IOW(HELLO_MAGIC,2,int) //set langtype typedef enum _lang_t { english, chinese, pinyin }lang_t; #endif
Makefile文件:(注意:Makefile的'M'要大写)
#********************************************** # Makefile linux 2.6 Module # This makefile is written for Ubuntu 10.10 # It may not perfomance without erros on the # other version or distributions. #********************************************** # BY:tishion # Mail:tishion@163.com # 2011/06/19 #********************************************** obj-m += hello_mod.o CURRENT_PATH := $(shell pwd) LINUX_KERNEL := $(shell uname -r) LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL) all: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules clean: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean install: insmod hello_mod.ko unistall: rmmod hello_mod
以上三个文件即为驱动代码
另外,再给一个应用层测试代码,并共用驱动的头文件
hello_mod_test.c文件:
/* * ===================================================================================== * * Filename: hell_mod_test.c * * Description: hell_mod test app * * Version: 1.0 * Created: 06/20/2011 01:44:11 AM * Revision: none * Compiler: gcc * * Author: Tishion (shion), tishion@163.com * Company: LIM * * ===================================================================================== */ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <linux/ioctl.h> #include <string.h> #include <errno.h> #include "../hello_mod_ioctl.h" int main() { char outbuf[512]; char * myname = "tishion"; lang_t langtype = english; int fd = open("/dev/hello", O_RDWR, S_IRUSR|S_IWUSR); if(fd != -1) { write(fd, myname, strlen(myname)+1); langtype = chinese; ioctl(fd, HELLO_IOCTL_SETLANG, &langtype); read(fd, outbuf, 512); printf("langtype=chinese:%s/n", outbuf); memset(outbuf, 0, 512); langtype = pinyin; ioctl(fd, HELLO_IOCTL_SETLANG, &langtype); read(fd, outbuf, 512); printf("langtype=pinyin:%s/n", outbuf); memset(outbuf, 0, 512); ioctl(fd, HELLO_IOCTL_RESETLANG, &langtype); read(fd, outbuf, 512); printf("langtype=english:%s/n", outbuf); } else { perror("Failed at open():"); } return 0; }
最后,安装原博客编译和查看结果。
需要注意的是,需要到“/var/log/”目录下着“syslog”文件。
相关文章推荐
- Linux内核分析 读书笔记 (第三章)
- Linux内核启动过程
- Linux替换文本字符串(Vim编辑器中使用)
- Linux系统的命令源代码的获取方法
- linux串口测试程序
- U盘启动pe+CDlinux最简单方法
- LINUX的XEN和KVM到底区别在什么地方?
- Linux GRUB legacy
- linux配置ftp服务器
- linux环境下的伪分布式的hadoop基本搭建
- 对Linux 七个运行级别的详解
- linux环境下的jdk安装配置
- 怎样配置vi编辑器
- corosync
- centos 安装 mongdb
- Scripts after the Linux server installation
- linux文件系统介绍
- I.MX6 Linux 自动获取AR1020 event input节点
- Linux文件重点概念
- Linux Web服务器网站故障分析常用的命令