混杂字符设备驱动模型

Hntea bio photo By Hntea

概念

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

};

如何使用混杂设备驱动模型

  1. 初始化混杂设备结构体:struct miscdevice xxx = {...};

  2. 注册混杂设备 : int misc_register(struct miscdevice * misc);

  3. 注销:int misc_deregister(struct miscdevice *misc)

##编程模型

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

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

}