织梦CMS - 轻松建站从此开始!

罗索

Linux驱动开发入门

jackyhwei 发布于 2010-08-30 13:57 点击:次 
最近在学习Linux的驱动程序开发,连续啃了好几天书,也算是有了点最基本的认识,然后写了一个超级简单的驱动程序,JDEV,程序清单如下
TAG:

最近在学习Linux的驱动程序开发,连续啃了好几天书,也算是有了点最基本的认识,然后写了一个超级简单的驱动程序,JDEV,程序清单如下:

JDEV源代码:
jdev.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/timer.h> /* for timers */
#include <linux/fs.h>  /* file modes and device registration */
#include <linux/poll.h>  /* for poll */
#include <linux/wrapper.h> /* mem_map_reserve,mem_map_unreserve */
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
#include <linux/init.h>

#include <asm/io.h>

#if defined(CONFIG_SMP)
#define __SMP__
#endif

#define JDEV_MAJOR  43   //主设备号,表明是哪一类的设备。设备号的具体概念,参考Documentation/devices.txt
#define BUFF_LENGTH  128   //JDEV缓冲区大小

#define JDEV_IOCTL_BASE 0xbb   //IOCTL基本号
#define JDEV_GET_POOL  _IOR(JDEV_IOCTL_BASE, 1, unsigned int)  //取得缓冲区实际大小的IOCTL命令

static char *jdev_name = NULL;   //设备名称
static char jdev_buf[BUFF_LENGTH]; //JDEV缓冲区定义
static unsigned int dev_buf_count; //实际缓冲区大小

//MODULE_LICENSE("GPL");

//几个很重要的驱动函数声明
static ssize_t jdev_read(struct file *file, char *buf, size_t count, loff_t *offset);
static ssize_t jdev_write(struct file *file, const char *buf, size_t count, loff_t *offset);
static int jdev_open(struct inode *inode, struct file *file);
static int jdev_release(struct inode *inode, struct file *file);
static int jdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);

//驱动程序在Linux里面是以文件的形式来描述的,这里就是文件的操作函数定义。
static struct file_operations jdev_fops = {
 read:   jdev_read,
 write:  jdev_write,
 ioctl:  jdev_ioctl,
 open:   jdev_open,
 release: jdev_release,
};

//初始化驱动模块,加载的时候调用。
int init_module(void)
{
 int res;
 
 if (jdev_name == NULL)
  jdev_name = "jdev";
 
 //注册字符设备
 res = register_chrdev(JDEV_MAJOR, jdev_name, &jdev_fops);
 if (res) {
  printk("can't register device with kernel\n");
  return res;
 }
 
 printk("jdev module loaded\n");
 return 0;
}

//清理驱动模块,卸载的时候调用。
void cleanup_module(void)
{
 //取消注册字符设备
 unregister_chrdev(JDEV_MAJOR, "jdev");
 
 printk("jdev unloaded\n");
 return;
}

//打开设备,好像在读写,IOCTL的时候都会首先调用到。
static int jdev_open(struct inode *inode, struct file *file)
{
 MOD_INC_USE_COUNT;//设备打开引用计数
 printk("jdev open.\n");

 return 0;
}

//关闭设备,好像在读写,IOCTL完成的时候都会调用到。
static int jdev_release(struct inode *inode, struct file *file)
{
 MOD_DEC_USE_COUNT;//设备打开引用计数
 printk("jdev release\n");
 return 0;
}

//IOCTL接口,核心层和应用之间的一个桥梁。
static int jdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
    unsigned long arg)
{
 printk("jdev ioctl.\n");
 switch(cmd)
 {
  case JDEV_GET_POOL://取得BUF大小。
   printk("running command JDEV_GET_POOL. \n");
   if (put_user(dev_buf_count, (unsigned int *)arg))
    return -EFAULT;
   break;
  default:
   printk("error command number.\n");
 }
 
 return 0;
}

//JDEV读接口
static ssize_t jdev_read(struct file *file, char *buf, size_t count,
     loff_t *offset)
{
 printk("jdev read.\n");
 copy_to_user(buf, jdev_buf, count);
 return count;
}

//JDEV写接口
static ssize_t jdev_write(struct file *file, const char *buf, size_t count,
      loff_t *offset)
{
 if(count > BUFF_LENGTH)
 {
  printk("data size must less than 128 byte.\n");
  return 0;
 }
 copy_from_user(jdev_buf, buf, count);
 dev_buf_count = count;
 printk("jdev1 write count: %d, buf: %s.\n", dev_buf_count, jdev_buf);
 return count;
}


JDEV编译命令:
gcc -D__KERNEL__ -DMODULE -I/usr/src/linux-2.4/include -Wall -O2 -o jdev.o -c jdev.c
编译驱动的时候必须要安装内核代码,我的代码是装在/usr/src/linux-2.4/include

测试程序代码:
jdev_io.c

#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>

//IOCTL命令,和JDEV定义保持一致,其实应该用一个H文件来表示。
#define JDEV_IOCTL_BASE 0xbb
#define JDEV_GET_POOL  _IOR(JDEV_IOCTL_BASE, 1, unsigned int)

int main(int argc, char *argv[])
{
 int fd = open("/dev/jdev", O_RDWR);//打开设备
 unsigned int j = 0;

 if (fd == -1) {
  perror("open");
  return 1;
 }

 //取得缓冲区大小
 if (ioctl(fd, JDEV_GET_POOL, &j) == -1) {
  perror("ioctl");
  return 2;
 }
 
 //打印缓冲区大小
 printf("Get buffer size is %d.\n", j);

 return 0;
}

测试程序编译命令:
gcc jdev_io.c
生成测试程序a.out

安装及测试命令:
mknod /dev/jdev c 43 0
insmod jdev.o
cp test /dev/jdev
test是一个文本文件,里面有一点点测试文本。
./a.out

如果一切正常,就会输出:Get buffer size is XX.
之后rmmod jdev删除驱动模块

同时可以用dmesg看到JDEV中printk输出的调试信息。



参考资料:
Beginning Linux Programming(Third Edition)

(fanged)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201008/10057.html]
本文出处:fanged.ycool.com 作者:fanged
顶一下
(1)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容