Chinaunix首页 | 论坛 | 博客
  • 博客访问: 21756
  • 博文数量: 4
  • 博客积分: 1499
  • 博客等级: 上尉
  • 技术积分: 50
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-14 20:32
文章分类

全部博文(4)

文章存档

2011年(1)

2010年(2)

2009年(1)

我的朋友

分类: LINUX

2010-01-15 20:49:22

    在linux写驱动要比windows下简单的多,不过刚开始驱动环境的搭建耗了我不少时间,下面主要说下我的第一个驱动的完整过程。
    一、下载内核源码.
    很简单,apt-get install linux-source-2.6.26,下载之后解压tar jxvf linux-source-2.6.26.tar.bz2。
    二、配置并编译内核
    配置使用默认的就可以,make oldconfig。然后是编译,make。编译的时间比较长。编译之后会在当前文件夹生成一个文件vmlinux。
    三、编译和安装模块
    make module, make module_install
    执行结束之后,会在/lib/modules下生成新的目录/lib/modules/2.6.26/。 在随后的编译模块文件时,要用到这个路径下的build目录。至此,内核编译完成。可以重启一下系统。
   
    这时候编译的时候就不会找不到delay.h之类的头文件了。下面写一个驱动的框架。
 

#ifndef __KERNEL__
#define __KERNEL__
#endif

#ifndef MODULE
#define MODULE
#endif

#define DEVICE_NAME "can_bus"

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/io.h>

typedef unsigned char BYTE;

int major;

ssize_t can_read (struct file *file,

                  char *buf,

                  size_t count,

                  loff_t *f_ops)
{
    printk ("can_read\n");
    return 0;
}

ssize_t can_write (struct file *file,

                   const char *buf,

                   size_t count,

                   loff_t *f_ops)
{
    printk ("can_write\n");
    return 0;
}

int can_ioctl (struct inode *inode,
               struct file *file,
               unsigned int ioctl_num,
               unsigned long ioctl_param)
{
    printk ("ioctl\n");
    return 0;
}

int can_open (struct inode *inode,
              struct file *file)
{
    printk ("open can bus\n");
    try_module_get (THIS_MODULE);
    return 0;
}

int can_release (struct inode *inode,
                 struct file *file)
{
    module_put (THIS_MODULE);
    return 0;
}

struct file_operations can_fops =
{
    open: can_open,
    read: can_read,
    write: can_write,
    ioctl: can_ioctl,
    release: can_release,
};

int can_init (void)
{
    int retval = 0;

    major = retval = register_chrdev (0, DEVICE_NAME, &can_fops);
    if (retval < 0)
    {
        printk ("%s: register_chrdev () failed with %d\n",
            DEVICE_NAME, retval);

        return -ENODEV;
    }
    printk ("can_bus major num = %d\n", major);
    return 0;
}

void can_cleanup (void)
{
    iounmap (io_base);
    unregister_chrdev (major, DEVICE_NAME);
    
}


MODULE_LICENSE ("GPL");

module_init (can_init);
module_exit (can_cleanup);

 

这是我写的CAN总线的驱动,摘了个框架出来,在2.6内核下,模块计数的加减要用try_module_get和module_put,然后就是makefile的编写

obj-m:=can_bus.o
KERNELDIR:=/lib/modules/2.6.26/build
PWD:=$(shell pwd)

modules:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
    rm *.o *.ko *.mod.c *.order *.symvers

 

然后make就可以了,写驱动程序的时候,如果定义一个没有形参的函数,括号里一定要写上void,否则会有一个警告,虽然没什么大碍,不过有警告很不爽,看来养成良好的变成习惯也很重要,make之后会生成一个can_bus.ko,下面的就简单了

1、安装模块insmod can_bus.ko

    如果要想看到输出信息,可以用cat /var/log/messages或者切换到文本界面,直接就能在控制台看到输出:can_bus major num = 249,这是我这里显示的,就是说生成的主设备号是249,用lsmod可以查看模块是否加载了


2、创建设备文件
    mknod /dev/can_bus c 249 0,上面提到的249就用到了,我一直在想,当我使用open打开can_bus设备的时候,怎么跟我的驱动关联起来,这个249就是关键了,刚开始的时候,我就随便写了个主设备号,结果怎么也打不开设备。

3、测试

    int fd;
    fd = open ("/dev/can_bus", O_RDWR);
    if (fd < 0)
    {
        printf ("open can_bus failed\n");
    }
    else
    {
        printf ("open can_bus success\n");
    }

如果成功打开就能看到控制台open can bus的输出,这时,一个完整的驱动就差不多了。要卸载模块,使用rmmod can_bus即可。

4、开机自动加载
    差不多就是还差一点,驱动不可能每次都要手动去加载,我想让驱动开机的时候自动加载,这就要修改rc.local文件,输入vim /etc/init.d/rc.local,在文件的最后两行添上
insmod /can/can_bus.ko
mknod /dev/can_bus c 249 0
我的can_bus.ko是放在/can目录下的,读者可自行修改,这下就完整了,重启电脑,在做下上面的测试,OK了,不用手动去加载了,大功告成。


 

阅读(725) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~