linux驱动学习——怎么自动创建设备文件

linux驱动学习——怎么自动创建设备文件 

本文转载自边缘之火 《linux驱动学习——怎么自动创建设备文件》

               在学习linux驱动开发中,我们可以将驱动编进内核,也可以编成模块,在编成模块时,我们希望模块加载时,设备文件可以自动创建,这样我们在开机脚本文件中进行模块加载,同时会创建设备文件。以后就直接可以操作这个设备了。

                当然,有两种方法可以实现,比如led的驱动,可以将它注册为misc设备,这样也就不用手动创建设备文件了,但如果不使用misc设备,怎么办?

               这就要使用第二种方法了,看下面的led驱动

 #include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/gpio.h>


#define DEVICE_NAME     "sxwleds"  /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */
#define LED_MAJOR       0    /* 主设备号 */

/* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */
#define IOCTL_LED_ON    0
#define IOCTL_LED_OFF   1

unsigned int led_major=LED_MAJOR;
struct class *sxw_class;

/* 用来指定LED所用的GPIO引脚 */
static unsigned long led_table [] = {
 S3C2410_GPB(5),
 S3C2410_GPB(6),
 S3C2410_GPB(7),
 S3C2410_GPB(8),
};

/* 用来指定GPIO引脚的功能:输出 */
static unsigned int led_cfg_table [] = {
 S3C2410_GPIO_OUTPUT,
 S3C2410_GPIO_OUTPUT,
 S3C2410_GPIO_OUTPUT,
 S3C2410_GPIO_OUTPUT,
};

/* 应用程序对设备文件/dev/leds执行open(...)时,
 * 就会调用s3c24xx_leds_open函数
 */
static int s3c24xx_leds_open(struct inode *inode, struct file *file)
{
    int i;
   
    for (i = 0; i < 4; i++) {
        // 设置GPIO引脚的功能:本驱动中LED所涉及的GPIO引脚设为输出功能
        s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
    }
    return 0;
}

/* 应用程序对设备文件/dev/leds执行ioclt(...)时,
 * 就会调用s3c24xx_leds_ioctl函数
 */
static int s3c24xx_leds_ioctl(
    struct inode *inode,
    struct file *file,
    unsigned int cmd,
    unsigned long arg)
{
    if (arg > 4) {
        return -EINVAL;
    }
   
    switch(cmd) {
    case IOCTL_LED_ON:
        // 设置指定引脚的输出电平为0
        s3c2410_gpio_setpin(led_table[arg], 0);
        return 0;

    case IOCTL_LED_OFF:
        // 设置指定引脚的输出电平为1
        s3c2410_gpio_setpin(led_table[arg], 1);
        return 0;

    default:
        return -EINVAL;
    }
}

/* 这个结构是字符设备驱动程序的核心
 * 当应用程序操作设备文件时所调用的open、read、write等函数,
 * 最终会调用这个结构中指定的对应函数
 */
static struct file_operations s3c24xx_leds_fops = {
    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open   =   s3c24xx_leds_open,    
    .ioctl  =   s3c24xx_leds_ioctl,
};

/*
 * 执行“insmod s3c24xx_leds.ko”命令时就会调用这个函数
 */
static int __init s3c24xx_leds_init(void)
{
    int ret;
   
    /* 注册字符设备驱动程序
     * 参数为主设备号、设备名字、file_operations结构;
     * 这样,主设备号就和具体的file_operations结构联系起来了,
     * 操作主设备为LED_MAJOR的设备文件时,就会调用s3c24xx_leds_fops中的相关成员函数
     * LED_MAJOR可以设为0,表示由内核自动分配主设备号
     */
    ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &s3c24xx_leds_fops);
    if (ret < 0) {
      printk(DEVICE_NAME " can't register major number\n");
      return ret;
    }
    led_major=ret;
   
    printk(DEVICE_NAME " initialized---- MAJOR is %d\n",led_major);
    sxw_class = class_create(THIS_MODULE,"sxw_class");
    if(IS_ERR(sxw_class))
    {
 printk("Err: failed in creating sxw_class.\n");
 return -1;
    }
    device_create(sxw_class,NULL,MKDEV(led_major,0),NULL,"sxwleds");
    return 0;
}

/*
 * 执行”rmmod s3c24xx_leds.ko”命令时就会调用这个函数
 */
static void __exit s3c24xx_leds_exit(void)
{
    /* 卸载驱动程序 */
    device_destroy(sxw_class,MKDEV(led_major,0));
    class_destroy(sxw_class); 
    unregister_chrdev(led_major, DEVICE_NAME);
}

/* 这两行指定驱动程序的初始化函数和卸载函数 */
module_init(s3c24xx_leds_init);
module_exit(s3c24xx_leds_exit);

/* 描述驱动程序的一些信息,不是必须的 */
MODULE_AUTHOR("http://www.100ask.net");             // 驱动程序的作者
MODULE_DESCRIPTION("S3C2410/S3C2440 LED Driver");   // 一些描述信息
MODULE_LICENSE("GPL");                              // 遵循的协议

               上面的驱动程序中,加红的部分就是和自动创建设备文件相关的代码,device_create()这个函数用来创建一个名为“sxwleds”的字符设备。

                 之后,只要加载这个模块,就会在/dev/自动创建一个名为sxwleds的设备,为什么会自动创建,对于2.6的内核,是由用户空间的udev决定的。这方面的资料也很多,不再赘述。


你可能感兴趣的:(linux驱动学习——怎么自动创建设备文件)