一个设备节点的属性有:
设备类型,读写权限,主设备号,次设备号等等。次设备号的作用是什么呢?
举个例子:
假如有两个串口,它们共用一个设备驱动(主设备号),当具体的操作的时候,如何判断操作的是哪一个串口呢?这就使用到了次设备号。
下面给出相关次设备号使用的相关代码:
功能如下:
1.次设备号为0的设备节点功能为操作所有的LED灯
2.测设备号为1,2,3,4分别代表各个单独的LED灯,可以对他们单独进行操作。
代码如下:
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/adb.h>
#include <linux/cuda.h>
#include <linux/pmu.h>
#include <linux/notifier.h>
#include <linux/wait.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/kthread.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/uaccess.h>
struct class *first_dev_class;
//struct device *first_dev;
struct device *led_devs[5];
volatile unsigned long *gpmcon = NULL;
volatile unsigned long *gpmdat = NULL;
int major;
int minor;
static int first_drv_open(struct inode *inode, struct file *file)
{
printk("first_drv_open!!\n");
minor = MINOR(inode->i_rdev);
switch(minor){
case 0:
{ //操作leds
printk("first_drv_open : minor == 0 !!\n");
*gpmcon &= ~(0x3 | 0x3 << 4 | 0x3 << 8 | 0x3 << 12);
*gpmcon |= (0x1 | 0x1 << 4 | 0x1 << 8 | 0x1 << 12);
break;
}
case 1:
{ //操作led1
printk("first_drv_open : minor == 1 !!\n");
*gpmcon &= ~(0x3 | 0x3 << 4 | 0x3 << 8 | 0x3 << 12);
*gpmcon |= 0x1;
break;
}
case 2:
{
*gpmcon &= ~(0x3 | 0x3 << 4 | 0x3 << 8 | 0x3 << 12);
*gpmcon |= 0x1 << 4;
break;
}
case 3:
{
*gpmcon &= ~(0x3 | 0x3 << 4 | 0x3 << 8 | 0x3 << 12);
*gpmcon |= 0x1 << 8;
break;
}
case 4:
{
*gpmcon &= ~(0x3 | 0x3 << 4 | 0x3 << 8 | 0x3 << 12);
*gpmcon |= 0x1 << 12;
break;
}
}
return 0;
}
static int first_drv_write(struct file *filp, char __user *buff,
size_t count, loff_t *offp)
{
printk("first_drv_write!!\n");
int val ;
minor = MINOR(filp->f_dentry->d_inode->i_rdev);
copy_from_user(&val,buff,count);
switch(minor){
case 0:
{
printk("first_drv_write minor == 0 !!\n");
if(val == 1){
//点灯
*gpmdat &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
}else if(val == 0){
//灭灯
*gpmdat |= (1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
}
break;
}
case 1:
{
printk("first_drv_write minor == 1 !!\n");
if(val == 1){
//点灯
*gpmdat &= ~(1 << 0);
}else if(val == 0){
//灭灯
*gpmdat |= (1 << 0);
}
break;
}
case 2:
{
if(val == 1){
//点灯
*gpmdat &= ~(1 << 1);
}else if(val == 0){
//灭灯
*gpmdat |= (1 << 1);
}
break;
}
case 3:
{
if(val == 1){
//点灯
*gpmdat &= ~(1 << 2);
}else if(val == 0){
//灭灯
*gpmdat |= (1 << 2);
}
break;
}
case 4:
{
if(val == 1){
//点灯
*gpmdat &= ~(1 << 3);
}else if(val == 0){
//灭灯
*gpmdat |= (1 << 3);
}
break;
}
}
return 0;
}
static struct file_operations first_drv_fops = {
.owner = THIS_MODULE,
.open = first_drv_open,
.write = first_drv_write,
};
static int __init first_drv_init(void)
{
printk("first_drv_init\n");
major = register_chrdev(0,"first_drv",&first_drv_fops);
first_dev_class = class_create(THIS_MODULE, "first_drv_class");
// first_dev= device_create(first_dev_class, NULL, MKDEV(major,0), NULL, "xyz");
led_devs[0] = device_create(first_dev_class, NULL, MKDEV(major,0),NULL,"leds");
for(minor = 1 ; minor < 5 ; minor++){
led_devs[minor] = device_create(first_dev_class, NULL, MKDEV(major,minor),NULL,"led%d",minor);
}
gpmcon = (volatile unsigned long *)ioremap(0x7F008820, 16);
gpmdat = gpmcon + 1;
// register_chrdev(111,"first_drv",&first_drv_fops);
return 0;
}
static void __exit first_drv_exit(void)
{
printk("first_drv_exit\n");
for(minor = 0 ; minor < 5 ; minor++){
device_destroy(first_dev_class, MKDEV(major,minor));
}
// device_destroy(first_dev_class, MKDEV(major,0));
class_destroy(first_dev_class);
unregister_chrdev(major,"first_drv");
iounmap(gpmcon);
}
module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");
测试程序:
#include <stdio.h>
#include <fcntl.h>
int main(int argc ,char **argv)
{
int fd ;
int val;
char *filename = argv[1];
fd = open(filename,O_RDWR);
if(fd < 0){
printf("Can not open devices\n");
return -1;
}
if(argc != 3){
printf("Usage : %s <leds/led1/led2/led3/led4> <on/off> \n",argv[0]);
return 0;
}
if(strcmp(argv[2],"on") == 0){
val = 1;
}else{
val = 0;
}
write(fd,&val,4);
return 0;
}
从上面的驱动程序可以看到,在open,read,write函数中获取次设备号的方法为:
open函数: 通过MINOR(inode->i_rdev);获取
read,write函数: 通过MINOR(filp->f_dentry->d_inode->i_rdev);获取