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);
#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");
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");
#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.杂项设备的注册:
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协议(开源协议)*/
/*提供接口函数给内核,在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
- linux内核驱动三类注册方式
- Linux内核驱动注册方式泛谈
- Linux内核设备驱动注册
- Linux驱动的注册方式
- 注册JDBC驱动的三种方式
- Jdbc注册驱动的三种方式
- 注册JDBC驱动的三种方式
- JDBC驱动注册的三种方式
- 注册JDBC驱动的三种方式
- 注册jdbc驱动的三种方式
- jdbc注册驱动三种方式
- JDBC注册驱动的三种方式
- 注册JDBC驱动的三种方式
- 注册JDBC驱动的三种方式
- jdbc注册驱动三种方式
- jdbc注册驱动的三种方式
- mysql注册驱动的三种方式
- 注册JDBC驱动的三种方式
- 递归算法
- 九度题目1202:排序
- 黑马程序员_初始化块、静态导入、包
- slf4j下log4j配置不起作用
- 写代码规范
- linux内核驱动三类注册方式
- Single Number II
- How to make your intermittent or flaky terminal services connection a little more stable
- usaco 2003 fall Cow Exhibition 奶牛展览会 题解
- Java Date类 日期、毫秒、天数之间的各种转换
- 进制转换
- vector,list,deque,map,capacity和size的区别等容器总结
- java引发的思考----自己是面向对象的程序设计员吗?
- 生成节点场景的方法