代码改变世界

驱动编写及编译例子

2013-09-15 12:31  minus01  阅读(296)  评论(0编辑  收藏  举报

通用驱动程序基于globalmem共享内存的驱动编写write、read、ioctl、lseek函数globalmem.c

  1 #include <linux/module.h>
  2 #include <linux/types.h>
  3 #include <linux/fs.h>
  4 #include <linux/errno.h>
  5 #include <linux/mm.h>
  6 #include <linux/sched.h>
  7 #include <linux/init.h>
  8 #include <linux/cdev.h>
  9 #include <asm/io.h>
 10 #include <asm/system.h>
 11 #include <asm/uaccess.h>
 12 
 13 #define GLOBALMEM_SIZE 0x1000  /*全局内存最大4KB*/
 14 #define MEM_CLEAR 0x1 /*清零全局内存*/
 15 #define GLOBALMEM_MAJOR 250 /*预设的globalmem的主设备号*/
 16 
 17 static int globalmem_major = GLOBALMEM_MAJOR;
 18 /*globalmem设备结构体*/
 19 struct globalmem_dev {
 20 struct cdev cdev; /*cdev结构体*/
 21 unsigned char mem[GLOBALMEM_SIZE]; /*全局内存*/
 22  };
 23 
 24 struct globalmem_dev *globalmem_devp; /*设备结构体指针*/
 25 /*文件打开函数*/
 26 int globalmem_open(struct inode *inode, struct file *filp)
 27 {
 28 /*将设备结构体指针赋值给文件私有数据指针*/
 29   filp->private_data = globalmem_devp;
 30   return 0;
 31 }
 32 /*文件释放函数*/
 33 int globalmem_release(struct inode *inode, struct file *filp)
 34 {
 35  return 0;
 36 }
 37 
 38 /* ioctl设备控制函数 */
 39 static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned
 40   int cmd, unsigned long arg)
 41 {
 42  struct globalmem_dev *dev = filp->private_data;/*获得设备结构体指针*/
 43 
 44   switch (cmd) {
 45   case MEM_CLEAR:
 46      memset(dev->mem, 0, GLOBALMEM_SIZE);
 47      printk(KERN_INFO "globalmem is set to zero\n");
 48      break;
 49 
 50    default: 
 51      return - EINVAL;
 52   }
 53 
 54   return 0;
 55 }
 56 
 57 /*读函数*/
 58 static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size,
 59   loff_t *ppos)
 60 {
 61   unsigned long p = *ppos;
 62   unsigned int count = size;
 63   int ret = 0;
 64 struct globalmem_dev *dev = filp->private_data;/*获得设备结构体指针*/
 65 
 66 /*分析和获取有效的写长度*/
 67   if (p >= GLOBALMEM_SIZE)
 68      return 0;
 69   if (count > GLOBALMEM_SIZE - p)
 70      count = GLOBALMEM_SIZE - p;
 71 
 72 /*内核空间→用户空间*/
 73   if (copy_to_user(buf, (void *)(dev->mem + p), count)) {
 74      ret = - EFAULT;
 75   } else {
 76      *ppos += count;
 77      ret = count;
 78 
 79      printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p);
 80   }
 81 
 82   return ret;
 83 }
 84 
 85 /*写函数*/
 86 static ssize_t globalmem_write(struct file *filp, const char _ _user *buf,
 87   size_t size, loff_t *ppos)
 88 {
 89   unsigned long p = *ppos;
 90   unsigned int count = size;
 91   int ret = 0;
 92 struct globalmem_dev *dev = filp->private_data;/*获得设备结构体指针*/
 93 
 94 /*分析和获取有效的写长度*/
 95   if (p >= GLOBALMEM_SIZE)
 96      return 0;
 97   if (count > GLOBALMEM_SIZE - p)
 98      count = GLOBALMEM_SIZE - p;
 99 
100  /*用户空间→内核空间*/
101    if (copy_from_user(dev->mem + p, buf, count))
102       ret = - EFAULT;
103    else {
104       *ppos += count;
105       ret = count; 
106  
107       printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p);
108    }
109  
110    return ret;
111  }
112  
113  /* seek文件定位函数 */
114  static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
115  {
116    loff_t ret = 0;
117    switch (orig) {
118  case 0: /*相对文件开始位置偏移*/
119       if (offset < 0)  {
120         ret = - EINVAL;
121         break;
122       }
123       if ((unsigned int)offset > GLOBALMEM_SIZE) {
124         ret = - EINVAL;
125         break;
126       }
127       filp->f_pos = (unsigned int)offset;
128       ret = filp->f_pos;
129       break;
130  case 1: /*相对文件当前位置偏移*/
131       if ((filp->f_pos + offset) > GLOBALMEM_SIZE) {
132         ret = - EINVAL;
133         break;
134       }
135       if ((filp->f_pos + offset) < 0) {
136         ret = - EINVAL;
137         break;
138       }
139       filp->f_pos += offset;
140       ret = filp->f_pos;
141       break;
142    default:
143       ret = - EINVAL;
144       break;
145    }
146    return ret;
147  }
148  
149  /*文件操作结构体*/
150  static const struct file_operations globalmem_fops = {
151    .owner = THIS_MODULE,
152    .llseek = globalmem_llseek,
153    .read = globalmem_read,
154    .write = globalmem_write,
155    .ioctl = globalmem_ioctl,
156    .open = globalmem_open,
157    .release = globalmem_release,
158  };
159  
160  /*初始化并注册cdev*/ 
161  static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
162  {
163    int err, devno = MKDEV(globalmem_major, index);
164  
165    cdev_init(&dev->cdev, &globalmem_fops);
166    dev->cdev.owner = THIS_MODULE;
167    err = cdev_add(&dev->cdev, devno, 1);
168    if (err)
169       printk(KERN_NOTICE "Error %d adding globalmem %d", err, index);
170  }
171  
172  /*设备驱动模块加载函数*/
173  int globalmem_init(void)
174  {
175    int result;
176    dev_t devno = MKDEV(globalmem_major, 0);
177  
178  /* 申请设备号*/
179    if (globalmem_major)
180       result = register_chrdev_region(devno, 1, "globalmem");
181  else { /* 动态申请设备号 */
182       result = alloc_chrdev_region(&devno, 0, 1, "globalmem");
183       globalmem_major = MAJOR(devno);
184    }
185    if (result < 0)
186       return result;
187  
188  /* 动态申请设备结构体的内存*/
189    globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
190  if (!globalmem_devp) { /*申请失败*/
191       result = - ENOMEM;
192       goto fail_malloc;
193    }
194  
195    memset(globalmem_devp, 0, sizeof(struct globalmem_dev));
196  
197    globalmem_setup_cdev(globalmem_devp, 0);
198    return 0;
199  
200  fail_malloc:
201    unregister_chrdev_region(devno, 1);
202    return result;
203  }
204  
205  /*模块卸载函数*/
206  void globalmem_exit(void)
207  {
208  cdev_del(&globalmem_devp->cdev); /*注销cdev*/
209  kfree(globalmem_devp); /*释放设备结构体内存*/
210  unregister_chrdev_region(MKDEV(globalmem_major, 0), 1);/*释放设备号*/
211  }
212  
213  MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
214  MODULE_LICENSE("Dual BSD/GPL");
215   
216  module_param(globalmem_major, int, S_IRUGO);
217  
218  module_init(globalmem_init);
219  module_exit(globalmem_exit);

驱动编译Makefile:

 1 $(warning KERNELRELEASE=$(KERNELRELEASE))
 2 
 3 ifeq ($(KERNELRELEASE),)
 4 
 5 KERNELDIR ?= /home/tom/fs2416/linux-2.6.39-FS2416
 6 PWD := $(shell pwd)
 7 
 8 modules:
 9     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
10 
11 modules_install:
12     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
13 
14 clean:
15     rm -rf *.o core *.ko *~ .depend .*.cmd *.mod.c .tmp_versions Module* modules*
16 
17 .PHONY:
18     modules modules_install clean
19 
20 else
21     obj-m := globalmem.o
22 endif

其中:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules 的操作:$(MAKE) -C $(KERNELDIR)进入内核源码目录下执行主Makefile,其中会定义KERNELRELEASE常量;M=$(PWD) modules进入当前目录,执行当前目录下的Makefile,生产模块;
-C是表示进入$(KERNELDIR)目录执行makefile,M指定要生成的外部模块的目录。

Use make M=dir to specify directory of external module to build