Linux驱动开发-混杂字符设备驱动模型笔记 4

时间:2021-08-31 23:37:10

混杂字符设备驱动模型

概念

  • 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);

}