Chinaunix首页 | 论坛 | 博客
  • 博客访问: 588335
  • 博文数量: 187
  • 博客积分: 10025
  • 博客等级: 上将
  • 技术积分: 2990
  • 用 户 组: 普通用户
  • 注册时间: 2007-06-18 17:40
文章分类

全部博文(187)

文章存档

2010年(1)

2009年(23)

2008年(163)

我的朋友

分类: LINUX

2008-09-22 14:58:18

读Linux设备驱动第三版一书 练习笔记
 
思路:注册一个设备,当用户调用读取操作时返回给用户当前的进程列表
 
hello.c //源文件
 
#include       //指定初始化和清理函数Module init和Module exit宏       
#include     //moudle.h 包含了大量加载模块需要的函数和符号的定义
#include    //内核代码的 printk,输出优先级等内核代码
#include      //kmalloc,kfree需要这个文件引入
#include     //进程数据结构和操作 
#include     //错误代码
#include        //文件操作;file_operation 结构,struct file,inode
#include      //字符设备结构,注册与销毁设备操作
#include     //dev_t 内核里代表设备号的类型.int MAJOR(dev_t dev)等
#include     //copy_to_user和copy_from_user
MODULE_AUTHOR("UserName");
MODULE_LICENSE("GPL");

static int hello_major = 0;              //设备文件主编号
static int hello_minor = 0;              // 设备文件次编号
static char *dev_name = "hello";         //显示的设备名称前缀
static int dev_count = 4;                //设备数量
static struct cdev **pDev = NULL;         //设备结构 集合
 
int hello_proc_open(struct inode *inode, struct file *filp);
ssize_t hello_proc_read(struct file *filp, char __user *buf, size_t count,loff_t *f_pos);
ssize_t hello_proc_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
 
static struct file_operations hello_proc_ops = {
 .owner   = THIS_MODULE,                          //所属模块
 .open    = hello_proc_open,                      //systemcall open
 .read    = hello_proc_read,                      //systemcall read
 .write =   hello_proc_write                      //systemcall write
};                                        //这里只进行打开,读取和写入操作示例

static int __init hello_init(void)
{
   dev_t dev = 0;
   int result = 0;
  // char* buf = NULL;
   int index;
   printk(KERN_ALERT "hello,kernel world\n");
   /*buf = kmalloc(BUFSIZE,0);
   if(buf != NULL)
   {
        memset(buf,0,BUFSIZE);
     memcpy(buf,"kmalloc memory successfully\n",strlen("kmalloc memory successfully\n")); 
     printk(KERN_ALERT "%s\n", buf);
     kfree(buf);
     printk(KERN_ALERT "kfree memory successfully\n");
   }   */
   //获取字符设备主编号
   if (hello_major) {                                         
     dev = MKDEV(hello_major, hello_minor);                       
    register_chrdev_region(dev, dev_count, dev_name);
   }
   else {
     result = alloc_chrdev_region(&dev, hello_minor, dev_count,dev_name);
     hello_major = MAJOR(dev);
   }
   if (result < 0) {
      printk(KERN_WARNING "%s: can't get major %d\n", dev_name,hello_major);
      return result;
   }
//为设备申结构请内存空间
  pDev = kmalloc(dev_count * sizeof(struct cdev*), GFP_KERNEL);
  //注册每个设备
  for (index = 0; index< dev_count; index++)
  {
   int err;
   int devno = MKDEV(hello_major, hello_minor + index);    //取得设备编号
   //cdev_init(pDev[index], &hello_proc_ops);
   pDev[index] = cdev_alloc();                           //建立设备
   pDev[index]->owner = THIS_MODULE;
   pDev[index]->ops = &hello_proc_ops;
   err = cdev_add (pDev[index], devno, 1);               //注册设备
   if (err)
    printk(KERN_NOTICE "Error %d adding hello%d\n", err, index);
   else
   printk(KERN_NOTICE "Success %d adding hello%d\n", err, index);
  }
  return 0;
}
static void __exit hello_exit(void)
{
 int i;
 dev_t devno = MKDEV(hello_major, hello_minor);
 /* Get rid of our char dev entries */
 if (pDev) {
  for (i = 0; i < dev_count; i++) {
   cdev_del(pDev[i]);                                 //删除设备
  }
  kfree(pDev);                                       //释放设备结构所占内存
 }
  unregister_chrdev_region(devno, dev_count);       //释放设备编号
  printk(KERN_ALERT "GoodBy Kernel World\n");
}

int hello_proc_open(struct inode *inode, struct file *filp)
{
  return 0;
}
ssize_t hello_proc_read(struct file *filp, char __user *buf, size_t count,loff_t *f_pos)
{
   int len = 0;
   unsigned long offset = 0;
   int remain = 0;
   struct task_struct *task;                         //进程或称任务结构
   for_each_process(task){                           //遍历当前的所有进程
      printk("[%s]%d\n",task->comm,task->pid);
   len = strlen(task->comm);
   remain = len;
   while (remain != 0)
   {
    remain = copy_to_user(buf + offset + len - remain ,task->comm + len - remain,remain);                                    //将进程名拷贝到用户空间  
   }
   offset += len;
   remain = 1;
   while (remain != 0)
   {
    remain = copy_to_user(buf + offset + 1-remain,"\n", remain);
   }
   offset += 1;
    }
 remain = 1;
 while (remain != 0)
 {
  remain =  copy_to_user(buf + offset + 1-remain,"\0",remain);
 }
 printk("write to user count = [%lu]\n",offset + 1);
    return offset + 1;
}
ssize_t hello_proc_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
 return 0;
}
module_init(hello_init);
module_exit(hello_exit);
 
 
 
Makefile
 
# Comment/uncomment the following line to disable/enable debugging
#DEBUG = y

# Add your debugging flag (or not) to CFLAGS
ifeq ($(DEBUG),y)
  DEBFLAGS = -O -g -Dhello_DEBUG # "-O" is needed to expand inlines
else
  DEBFLAGS = -O2
endif
CFLAGS += $(DEBFLAGS)
CFLAGS += -I$(LDDINC)
ifneq ($(KERNELRELEASE),)
# call from kernel build system
#hello-objs := hello.o
obj-m := hello.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD       := $(shell pwd)
modules:
 $(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD)/../include modules
endif
 
clean:
 rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
depend .depend dep:
 $(CC) $(CFLAGS) -M *.c > .depend

ifeq (.depend,$(wildcard .depend))
include .depend
endif
 
加载hello设备脚本 hello_load

# invoke insmod with all arguments we got
# and use a pathname, as insmod doesn't look in . by default
/sbin/insmod ./$module.ko $* || exit 1
# retrieve major number
major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices)
# Remove stale nodes and replace them, then give gid and perms
# Usually the script is shorter, it's hello that has several devices in it.
rm -f /dev/${device}[0-3]
mknod /dev/${device}0 c $major 0
mknod /dev/${device}1 c $major 1
mknod /dev/${device}2 c $major 2
mknod /dev/${device}3 c $major 3
ln -sf ${device}0 /dev/${device}
chgrp $group /dev/${device}[0-3]
chmod $mode  /dev/${device}[0-3]
 
卸载hello设备脚本 hello_unload
 
#!/bin/sh
module="hello"
device="hello"
# invoke rmmod with all arguments we got
/sbin/rmmod $module $* || exit 1
# Remove stale nodes
rm -f /dev/${device} /dev/${device}[0-3]
 
 
测试代码test.c:
 
#include
#include
#include
#include
#include
int main()
{
 int fd = 0;
 char buf[65535];
 if((fd = open("/dev/hello1", O_CREAT|O_RDWR, 0644)) > 0)
 {
  printf("open success.\n");
  read(fd,buf,65535);
  printf("%s\n",buf);
  close(fd);
 }
 else
 {
  printf("open failed.\n");
 }
 return 0;
}
 
 
测试步骤:
编译后运行脚本hello_load,然后运行test,最后运行脚本 hello_unload,千万不要测试诸如cp /dev/hello1 a.txt, 因为该例子不完全,会导致无限循环。
 
阅读(1287) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~