混杂字符设备驱动模型
概念
- linux系统中,称以主设备号为“10”,但次设备号不同的字符设备为混杂设备
- 所有的混杂设备形成一个链表
- 对设备访问时,内核根据次设备号查找到相应的设备
结构描述
struct miscdevice {
int minor; /*次设备号*/
const char *name;/*设备名,驱动加载后会自动创建该设备文件*/
const struct file_operations *fops; /*文件操作*/
struct list_head list; /*以下结构体内核使用..*/
struct device *parent;
struct device *this_device;
const char *nodename;
mode_t mode;
};
如何使用混杂设备驱动模型
a) 初始化混杂设备结构体:struct miscdevice xxx = {...};
b) 注册混杂设备 : int misc_register(struct miscdevice * misc);
c) 注销:int misc_deregister(struct miscdevice *misc)
4、编程模型
#include<linux/module.h>
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/miscdevice.h>
#include<linux/ioctl.h>
#include<linux/fs.h>
#define MINOR 100
#define DEVICENAME "led"
/*硬件初始化*/
.....
/*文件操作*/
.....
struct file_operations ledfp =
{
.open = led_open,
.unlocked_ioctl = ledctl,
};
/*1、混杂设备声明*/
struct miscdevice led_misc= {
.minor = MINOR,
.name = DEVICENAME,
.fops = &ledfp,
};
static int led_miscInit(void)
{
int ret = 0;
/*2、混杂设备注册*/
ret = misc_register(&led_misc);
return ret ;
}
static void led_miscExit(void)
{
int ret = 0;
/*注销混杂设备*/
ret = misc_deregister(&led_misc);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("hntea");
module_init(led_miscInit);
module_exit(led_miscExit);
LED 混杂设备驱动编程实现
#include<linux/module.h>
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/miscdevice.h>
#include<linux/ioctl.h>
#include<linux/fs.h>
#include<linux/mm.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include "led_ioctl.h"
#define DEV_MINOR 100
#define DEVICENAME "led"
#define ON 1
#define OFF 0
#define LED_ON 0x00000018
#define LED_OFF 0X00000000
#define CON_ADDR 0xE0200060
#define DAT_ADDR 0xE0200064
/*************************************************
函数名: led_hardinit 实现
函数参数:
函数功能:led硬件初始化
*************************************************/
static void led_hardinit(void)
{
unsigned int tmp = 0;
unsigned int *led_config;
/*找出物理地址对应的虚拟地址*/
led_config = ioremap(CON_ADDR,4); /*该寄存器是32位数值*/
/*读取当前寄存器状态*/
tmp = ioread32(led_config);
tmp &= (~(0x11 << 11)); /*注意移位是二进制的...*/
tmp |= (0x11 << 11);
/*寄存器设置写回*/
iowrite32(tmp,led_config);
}
/*************************************************
函数名: led_switch 实现
函数参数:
函数功能:led 状态切换
*************************************************/
static int led_switch(unsigned char cmd)
{
unsigned int *led_data;
led_data = ioremap(DAT_ADDR,4);
switch(cmd)
{
case ON:
iowrite32(LED_ON,led_data);
break;
case OFF:
iowrite32(LED_OFF,led_data);
break;
default:
return -1;
break;
}
return 0;
}
/*-------------------------文件操作--------------------*/
int led_open (struct inode *inode, struct file *filp)
{
led_hardinit();
return 0;
}
static long ledctl (struct file *filp, unsigned int cmd, unsigned long arg)
{
/*命令解析*/
switch(cmd)
{
case TURNON_LED:
led_switch(ON);
break;
case TURNOFF_LED:
led_switch(OFF);
break;
default:
return -ENOTTY;
break;
}
return 0;
}
struct file_operations ledfp ={
.open = led_open,
.unlocked_ioctl = ledctl,
};
/*1、混杂设备声明*/
struct miscdevice led_misc= {
.minor = DEV_MINOR,
.name = DEVICENAME,
.fops = &ledfp,
};
static int led_miscInit(void)
{
int ret = 0;
/*2、混杂设备注册,这能在/dev目录下创建 以设备名为文件名的设备文件*/
ret = misc_register(&led_misc);
return ret ;
}
static void led_miscExit(void)
{
int ret = 0;
/*3、注销混杂设备*/
ret = misc_deregister(&led_misc);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("hntea");
module_init(led_miscInit);
module_exit(led_miscExit);
LED控制头文件
#define LED_MAGIC 'L' /*幻数*/
#define TURNON_LED _IOW(LED_MAGIC,1,int)
#define TURNOFF_LED _IOW(LED_MAGIC,0,int)
LED驱动测试
#include<sys/fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/ioctl.h>
#include<stdio.h>
#include "led_ioctl.h"
#define DEVICE_FILE "/dev/led"
int main(int arg,char **argv)
{
int fd = 0 ;
int cmd = 0;
int ret = 0;
unsigned int test = 0b11;
printf("test is :%x\n",(test<<3));
/*解析传递进来的参数*/
if(arg < 2)
{
printf("Please input : <cmd> <0/1>\n");
return -1;
}
/*格式化*/
cmd = atoi((argv[1]));
/*设备操作*/
if((fd = open(DEVICE_FILE,O_RDWR))< 0)
{
printf("File open err!\n");
}
switch(cmd)
{
case 0:
ret = ioctl(fd,TURNOFF_LED);
break;
case 1:
ret = ioctl(fd,TURNON_LED);
break;
default:
printf("Command er!\n");
return -1;
}
close(fd);
}