Chinaunix首页 | 论坛 | 博客
  • 博客访问: 538062
  • 博文数量: 104
  • 博客积分: 4131
  • 博客等级: 上校
  • 技术积分: 1137
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-31 15:05
文章分类

全部博文(104)

文章存档

2011年(13)

2010年(23)

2009年(68)

我的朋友

分类: LINUX

2009-08-28 21:52:49

   一直在学习linux下设备驱动程序的编写,但是一直都是挑最简单的做。比如写makefile文件,设备号的分配,都是以最简单的形式来应付。静态实现设备号的分配有很多缺点,容易引起设备号冲突等。经过几天的突击终于实现了设备号的动态分配,现在来和大家分享以下(附有字符驱动源码)。
如下所示是简单字符驱动程序(baovar.c):
#include
#include
#include
#include
#include
#include
#include
#include"baovar.h"
MODULE_LICENSE("GPL");
static int MAJOR_NUM=0;//主设备号
 
ssize_t bao_read (struct file*,char*,size_t,loff_t*);
ssize_t bao_write (struct file*,const char*,size_t,loff_t*);
int bao_ioctl(struct inode *inode,struct file*filp,unsigned int cmd,unsigned long args);
int bao_open(struct inode *inode,struct file *filp);
int bao_release(struct inode *inode,struct file *filp);
 
//初始化file_operations
struct file_operations bao_fops=
{
 read:bao_read,
 write:bao_write,
 ioctl:bao_ioctl,
 open:bao_open,
 release:bao_release,
 owner:THIS_MODULE,
};
static int bao_var=0;//baovar设备的全局变量
static int bao_count=0;
static struct semaphore  sem;
static spinlock_t spin=SPIN_LOCK_UNLOCKED;
 
int __init bao_init(void)
{
 int ret;
 //注册设备驱动
 ret=register_chrdev(MAJOR_NUM,"baovar",&bao_fops);
 if(ret<0)
 {
  printk("baovar register failure\n");
  return ret;
 }
 else
 {
  printk("baovar register success\n");
  init_MUTEX(&sem);
 }
 if(MAJOR_NUM==0)
  MAJOR_NUM=ret;
 return 0;
}
 
void __exit bao_exit(void)
{
 int ret;
 
 //注销设备驱动
 ret=unregister_chrdev(MAJOR_NUM,"baovar");
 if(ret)
 {
  printk("baovar unregister failure\n");
 }
 else
 {
  printk("baovar unregister success\n");
 }
}
 
int bao_open(struct inode *inode,struct file *filp)
{
 //获得自旋锁
 spin_lock(&spin);
 //临界资源访问
 if(bao_count)
 {
  spin_unlock(&spin);
  return -EBUSY;
 }
 printk("baoopen\n");
 bao_count++;
 //释放自旋锁
 spin_unlock(&spin);
 return 0;
}
 
int bao_release(struct inode *inode,struct file *filp)
{
 bao_count--;
 printk("close->bao\n");
 return 0;
}
ssize_t bao_read(struct file*filp,char *buf,size_t len,loff_t *off)
{
 //获得信号量
 if(down_interruptible(&sem))
 {
  return -ERESTARTSYS;
 }
 //将baovar从内核空间复制到用户空间
 if(__copy_to_user(buf,&bao_var,sizeof(int)))
 {
  up(&sem);
  return -EFAULT;
 }
 up(&sem);
 return sizeof(int);
}
 
ssize_t bao_write(struct file*filp,const char *buf,size_t len,loff_t *off)
{
 //获得信号量
 if(down_interruptible(&sem))
 {
  return -ERESTARTSYS;
 }
 //将数据从用户空间复制到内核空间
 if(__copy_from_user(&bao_var,buf,sizeof(int)))
 {
  up(&sem);
  return -EFAULT;
 }
 //释放信号量
 up(&sem);
 return sizeof(int);
}
int bao_ioctl(struct inode *inode,struct file*filp,unsigned int cmd,unsigned long args)
{
 if(_IOC_TYPE(cmd)!=BAO_IOCTL){return -EINVAL;}
 if(_IOC_NR(cmd)>BAO_IOCTL_MAXNR){return -EINVAL;}
 
 int ret;
 switch(cmd)
 {
  case IOCTL_READ:
   return __put_user(bao_var, (int *) args);
  case IOCTL_WRITE:
   {ret = __get_user(bao_var, (int *) args);
              if (ret)
                 return ret;
              printk("bao_var = %d\n", bao_var);
              break; }
  default:printk("error\n");
   
 }
 return 1;
}
 
module_init(bao_init);
module_exit(bao_exit);
以下是头文件(baovar.h):
#include
#define BAO_IOCTL 't'
#define IOCTL_READ  _IOR(BAO_IOCTL, 0, int)
#define IOCTL_WRITE  _IOW(BAO_IOCTL, 1, int)
#define BAO_IOCTL_MAXNR 1
使MAJOR_NUM=0可以实现系统动态分配设备号,从255开始,从大到小搜索,直到找到未被使用的号。
使用的makefile文件如下:
CC=gcc
MODCFLAGS := -Wall -DMODULE -D__KERNEL__ -DLINUX -I/usr/src/linux-2.4/include
baovar.o :baovar.c
 $(CC) $(MODCFLAGS) -c baovar.c
clean:
 rm -f *.o
下面重点介绍shell文件的编写(脚本文件):
1.bao_load.sh文件
#!/bin/bash
#bao.sh
module="baovar"
device="baovar"
mode="664"
# Group: since distributions do it differently, look for wheel or use staff
if grep '^staff:' /etc/group > /dev/null; then
    group="staff"
else
    group="wheel"
fi
# invoke insmod with all arguments we got
# and use a pathname, as newer modutils don't look in . by default
/sbin/insmod ./$module.o $* || exit 1
cat /proc/devices
major=`cat /proc/devices | awk "" {print }"`
# Remove stale nodes and replace them, then give gid and perms
# Usually the script is shorter, it's simple that has several devices in it.
rm -f /dev/${device}
mknod /dev/${device} c $major 0
chgrp $group /dev/${device}
chmod $mode  /dev/${device}
echo "finish"
2.bao_unload.sh文件
#!/bin/sh
module="baovar"
device="baovar"
# invoke rmmod with all arguments we got
/sbin/rmmod $module $* || exit 1
# Remove stale nodes
rm -f /dev/${device}
echo "finish"
把这些文件放在同一文件夹下:
加载驱动:
在终端中输入:make
          :sh bao_load.sh
现在就可以使用字符驱动程序了
卸载驱动:sh bao-unload.sh
 
阅读(1765) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~