linux内核驱动三类注册方式

来源:互联网 发布:c4d软件下载 编辑:程序博客网 时间:2024/04/28 21:53
1.   2.6之后的注册方式:

#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>

//#define DEVICE_NAME     "leds"      /* 驱动名称 */
//#define LEDS_MAJOR       231        /* 次设备号 */

//-------------------------------------------------------------------------
#define CHAR_DEV_DEVICE_NAME   "cdev_leds"   // 设备名

struct class *char_dev_class;  // class结构用于自动创建设备结点
static int major = 0;

static struct cdev char_dev_devs;// 定义一个cdev结构

static unsigned long led_table [] = {
     S3C2410_GPB(5),
     S3C2410_GPB(6),
     S3C2410_GPB(7),
     S3C2410_GPB(8),
};

static unsigned int led_cfg_table [] = {
     S3C2410_GPIO_OUTPUT,
     S3C2410_GPIO_OUTPUT,
     S3C2410_GPIO_OUTPUT,
     S3C2410_GPIO_OUTPUT,
};
    
/*驱动程序,提供这个接口*/
static int sbc2440_leds_ioctl(
    struct inode *inode, /*内核里面的两个结构体*/
    struct file *file,
    unsigned int cmd, /*开关灯*/
    unsigned long arg)/*第几个灯*/
{
     switch (cmd) {
     case 0:   /*空,不执行*/
     case 1:
          if (arg >=4) {
               return -EINVAL;/*返回错误*/
          }
          s3c2410_gpio_setpin(led_table[arg], !cmd);/*条件具备(arg小于4时候执行本函数)把第几个脚设置低电平,灯亮*/
          return 0;
     default:
          return -EINVAL;
     }
}

// 设备建立子函数,被char_dev_init函数调用
static void char_dev_setup_cdev(struct cdev *dev, int minor, struct file_operations *fops)
{
     int err, devno = MKDEV(major, minor);

     cdev_init(dev, fops);
     dev->owner = THIS_MODULE;
     dev->ops = fops;//这句可以不写,已经在cdev_init()函数里实现了。

     err = cdev_add(dev, devno, 1);  //注册设备
     if ( err )
     {
          printk(KERN_NOTICE "Error %d adding char_dev %d\n", err, minor);
     }

}

//  file_operations 结构体设置,该设备的所有对外接口在这里明确,此处只写出了几常用的
static struct file_operations char_dev_fops =
{
     .owner = THIS_MODULE,
              /*     .open  = char_dev_open,      // 打开设备
                  .release = char_dev_release, // 关闭设备
                  .read  = char_dev_read,      // 实现设备读功能
                  .write = char_dev_write,     // 实现设备写功能 */
        .ioctl = sbc2440_leds_ioctl,     //实现设备控制功能
};

//   设备初始化
static int char_dev_init(void)
{
     int result;
     dev_t dev = MKDEV(major, 0);

     if ( major )
     {
          // 给定设备号注册
          result =DEV_DEV
 register_chrdev_region(dev, 1, CHAR_ICE_NAME);
     }

     else
     {
          // 动态分配设备号并注册
          result = alloc_chrdev_region(&dev, 0, 1, CHAR_DEV_DEVICE_NAME);
          major = MAJOR(dev);
     }


     char_dev_setup_cdev(&char_dev_devs, 0, &char_dev_fops);
     printk("The major of the char_dev device is %d\n", major);

//==== 有中断的可以在此注册中断:request_irq,并要实现中断服务程序 ===//

// 创建设备结点
     char_dev_class = class_create(THIS_MODULE,CHAR_DEV_DEVICE_NAME);

     if (IS_ERR(char_dev_class))
     {
          printk("Err: failed in creating class.\n");

          return 0;
     }
     device_create(char_dev_class, NULL, dev, NULL, CHAR_DEV_DEVICE_NAME);
     return 0;
}

// 设备注销
static void char_dev_cleanup(void)
{
     cdev_del(&char_dev_devs);//字符设备的注销*/
     unregister_chrdev_region(MKDEV(major, 0), 1);//设备号的注销
     device_destroy(char_dev_class,MKDEV(major,0));
     class_destroy(char_dev_class);


//========  有中断的可以在此注销中断:free_irq  ======//

     printk("char_dev device uninstalled\n");
}

module_init(char_dev_init);   //模块初始化接口
module_exit(char_dev_cleanup);//模块注销接口

// 以下两句不能省略,否则编译不通过
MODULE_AUTHOR("www.arm.com");
MODULE_LICENSE("GPL");


2.早期注册设备:

/*MODULE_LICENSE(),MODULE_AUTHOR(),module_init(),module_exit(),MODULE_DESCRIPTION()*/
#include <linux/module.h>

/* register_chrdev(),unregister_chrdev(),struct file_operations */
#include <linux/fs.h>

/*定义设备名*/
#define DEV_NAME   "first_chardev"

int major = 0;

int first_chardev_open (struct inode *inode, struct file *file)
{
     printk(KERN_EMERG"open() call\r\n");

     return 0 ;
}


ssize_t first_chardev_read (struct file *file, char __user *buf, size_t size, loff_t * off)
{
     printk(KERN_EMERG"read() call\r\n");
     return size;
}


ssize_t first_chardev_write (struct file *file, const char __user *buf, size_t size, loff_t *off)
{
     printk(KERN_EMERG"write() call\r\n");

     return size;

}

int first_chardev_ioctrl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
     printk(KERN_EMERG"ioctl() call\r\n");    
     return 0;
}
int first_chardev_close (struct inode *inode, struct file *file)
{
     printk(KERN_EMERG"release() call\r\n");    

     return 0;
}
loff_t first_chardev_llseek(struct file *file, loff_t loff, int origin )
{
       printk(KERN_EMERG"llseek() call\r\n");       
     printk(KERN_EMERG"loff:%d; origin:%d\r\n",loff,origin);    
     return loff;
}

static const struct file_operations  first_chardev_fops=
{
     .open = first_chardev_open,
     .release = first_chardev_close,
     .read = first_chardev_read,
     .write = first_chardev_write,
     .ioctl = first_chardev_ioctrl,
     .llseek = first_chardev_llseek,
};

static  int __init  first_chardev_init(void)
{
    printk(KERN_EMERG"module init now!\r\n");

     major = register_chrdev(major,DEV_NAME,&first_chardev_fops);    //注册设备     printk(KERN_EMERG"major:%d\r\n",major);
    
     return 0;
}


static __exit void  first_chardev_exit(void)
{
     printk(KERN_EMERG"module remove now!\r\n");
     unregister_chrdev(major,DEV_NAME);                 //注销设备
}

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ARM Inc.");
module_init(first_chardev_init);
module_exit(first_chardev_exit);
MODULE_DESCRIPTION("this is simlpe fist driver test!\r\n");



3.杂项设备的注册:

/*提供接口函数给内核,在dev目录下生成设备节点*/
static struct file_operations dev_fops = {
     .owner     =     THIS_MODULE,/*初始化加载模式  就是个声明,模块加1*/
     .ioctl     =     sbc2440_leds_ioctl,/*控制函数*/

                   };
/*注册(报到)*/
static struct miscdevice misc = {
     .minor = LEDS_MAJOR, /*次设备号    .minor是结构题里面的一个元素(变量)  */
     .name  = DEVICE_NAME,/*设备号*/
     .fops  = &dev_fops,/*功能函数  &取地址*/


                            };
/*初始化,内存优化*/
static int __init dev_init(void)//(开机运行一次)
{
     int ret;

     int i;

     for (i = 0; i < 4; i++) {
          s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);/*gpio口配置,设置输入输出        内核自带函数  ,四个I/O设置输出   */
          s3c2410_gpio_setpin(led_table[i], 1);/*设为高电平,所有灯关掉*/
     }

     ret = misc_register(&misc);/*杂选设备注册,主设备号固定,注册函数*/

     printk (DEVICE_NAME"\tinitialized\n");

     return ret;
}
/*退出函数*/
static void __exit dev_exit(void)/*__编译器用的 __exit编译器规定要加的*/
{
     misc_deregister(&misc);/*释放注册*/
}

module_init(dev_init);/*声明初始化函数(从哪里进来)初始化加载用的*/
module_exit(dev_exit);/*声明退出函数*/
MODULE_LICENSE("GPL");/*声明遵循GPL协议(开源协议)*/
MODULE_AUTHOR("ARM Inc.");/*
0 0
原创粉丝点击