linux ioctl驱动作用及程序示例

前言

linux操作系统的目标之一是向用户掩盖系统硬件设备的特殊性。驱动程序调用步骤:应用程序、库、内核、驱动、硬件。

linux嵌入式系统设备,例如:触摸屏、按键、 IIC总线、 LCD等是字符设备,他们特点是按字节流进行先后顺序读写操作设备的。

块设备可以随机访问设备内存的任意地址,硬盘、SD卡、NAND FLASH是块设备的代表。NAND Flash中的代码执行是通过将内容映射到RAM来实现的,这与直接从NOR Flash执行代码不同。记忆卡、体积小巧的U盘容量大。NAND Flash 的I/O接口并没有随机存取外部地址总线,它必须以区块性的方式进行读取。

NOR的特点是芯片内执行,应用程序可以直接在flash 闪存内运行,不必再把代码读到系统RAM中。NOR Flash需要很长的时间进行抹写,但是它提供完整的寻址与数据总线,并允许随机存取存储器上的任何区域,这使的它非常适合取代老式的ROM芯片。当时ROM芯片主要用来存储几乎不需更新的代码,例如电脑的BIOS或机上盒的固件。

网络设备指的是网卡一类使用socket套接字进行通信的设备。本文以字符设备为例讲述相关知识。

cat /proc/devices查看系统字符和块设备,在我们编写此类驱动insmod安装后,在该文件即可查看该驱动设备号信息。

Character devices:
  1 mem
  4 /dev/vc/0
  4 tty
  4 ttyS
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  7 vcs
 10 misc
 13 input
 29 fb
 99 ppdev
128 ptm
136 pts
162 raw
180 usb
188 ttyUSB
189 usb_device
202 cpu/msr
203 cpu/cpuid
226 drm
242 dimmctl
243 ndctl
244 aux
245 virtio-portsdev
246 hidraw
247 usbmon
248 bsg
249 hmm_device
250 watchdog
251 iio
252 rtc
253 dax
254 tpm

Block devices:
259 blkext
  9 md
252 device-mapper
253 virtblk
254 mdp

misc驱动

Linux里面的misc杂项设备是主设备号为10的驱动设备,它的注册跟使用比较的简单,所以比较适用于功能简单的设备。随着 Linux字符设备驱动的不断增加,设备号变得越来越紧张,尤其是主设备号。

miscdevice是一个结构体,定义在文件 include/linux/miscdevice.h 中,内容如下:

struct miscdevice  {
	int minor;										/* 子设备号 */						
	const char *name;								/* 设备名字 */
	const struct file_operations *fops;				/* 设备操作集 */
	struct list_head list;
	struct device *parent;
	struct device *this_device;
	const struct attribute_group **groups;
	const char *nodename;
	umode_t mode;
};

使用 misc_register 函数向系统中注册一个 MISC 设备

相当于字符设备驱动中我们会使用如下几个函数完成设备创建过程

alloc_chrdev_region(); /* 申请设备号 */
cdev_init(); /* 初始化 cdev */
cdev_add(); /* 添加 cdev */
class_create(); /* 创建类 */
device_create(); /* 创建设备 */

调用 misc_deregister 函数来注销掉 MISC 设备

相当于注销设备驱动删除此前创建的 cdev、设备等等内容

cdev_del(); /* 删除 cdev */
unregister_chrdev_region(); /* 注销设备号 */
device_destroy(); /* 删除设备 */
class_destroy(); /* 删除类 */

ioctl

ioctl是一种系统调用,用于在用户空间和内核空间之间传递控制命令。在Linux驱动程序中,ioctl通常用于实现设备驱动程序的控制接口。

驱动程序中的ioctl函数原型:

int ioctl(struct file *filp, unsigned int cmd, unsigned long arg);

filp是一个指向文件结构体的指针。

cmd是要执行的命令。

arg是命令的参数。

驱动程序中的ioctl函数根据不同的cmd值,执行不同的操作。例如,可以使用ioctl函数来设置设备的工作模式、获取设备的状态等。

在用户空间,可以通过调用ioctl系统调用来与驱动程序交互。具体的使用方式和参数可以在ioctl的man页中查看。

驱动程序中的ioctl函数的实现通常需要处理文件结构体、命令和参数。可以根据具体的需求来实现不同的功能。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "demo.h"

MODULE_AUTHOR("fgj");
MODULE_LICENSE("Dual BSD/GPL");

struct simple_dev *simple_devices;
static unsigned char simple_inc=0;
static u8 demoBuffer[256];

int simple_open(struct inode *inode, struct file *filp)
{
	struct simple_dev *dev;

	if(simple_inc>0)return -ERESTARTSYS;
	simple_inc++;

	dev = container_of(inode->i_cdev, struct simple_dev, cdev);
	filp->private_data = dev;

	return 0;
}

int simple_release(struct inode *inode, struct file *filp)
{
	simple_inc--;
	return 0;
}

int simple_ioctl(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg)
{
	switch(cmd)
	{
		case COMMAND1:
			memset(demoBuffer,0x31,256);
			break;
		case COMMAND2:
			memset(demoBuffer,0x32,256);
			break;
		default:
			return -EFAULT;
			break;
	}
    return 0;
}

struct file_operations simple_fops = {
	.owner =    THIS_MODULE,
	.ioctl =    simple_ioctl,
	.open =     simple_open,
	.release =  simple_release,
};

/*******************************************************
                MODULE ROUTINE
*******************************************************/
void simple_cleanup_module(void)
{
	dev_t devno = MKDEV(simple_MAJOR, simple_MINOR);

	if (simple_devices) 
	{
		cdev_del(&simple_devices->cdev);
		kfree(simple_devices);
	}
    unregister_chrdev_region(devno,1);
}

int simple_init_module(void)
{
	int result;
	dev_t dev = 0;

	dev = MKDEV(simple_MAJOR, simple_MINOR);
	result = register_chrdev_region(dev, 1, "DEMO");
	if (result < 0) 
	{
		printk(KERN_WARNING "DEMO: can't get major %d\n", simple_MAJOR);
		return result;
	}

	simple_devices = kmalloc(sizeof(struct simple_dev), GFP_KERNEL);
	if (!simple_devices)
	{
		result = -ENOMEM;
		goto fail;
	}
	memset(simple_devices, 0, sizeof(struct simple_dev));

	cdev_init(&simple_devices->cdev, &simple_fops);
	simple_devices->cdev.owner = THIS_MODULE;
	simple_devices->cdev.ops = &simple_fops;
	result = cdev_add (&simple_devices->cdev, dev, 1);
	if(result)
	{
		printk(KERN_NOTICE "Error %d adding DEMO\n", result);
		goto fail;
	}

	return 0;

fail:
	simple_cleanup_module();
	return result;
}

module_init(simple_init_module);
module_exit(simple_cleanup_module);

#ifndef _simple_H_
#define _simple_H_

#include  /* needed for the _IOW etc stuff used later */

/********************************************************
 * Macros to help debugging
 ********************************************************/
#undef PDEBUG             /* undef it, just in case */
#ifdef simple_DEBUG
#ifdef __KERNEL__
#    define PDEBUG(fmt, args...) printk( KERN_DEBUG "DEMO: " fmt, ## args)
#else//usr space
#    define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
#endif
#else
#  define PDEBUG(fmt, args...) /* not debugging: nothing */
#endif

#undef PDEBUGG
#define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */

//设备号
#define simple_MAJOR 224
#define simple_MINOR 0
#define COMMAND1 1
#define COMMAND2 2

//设备结构
struct simple_dev 
{
	struct cdev cdev;	  /* Char device structure		*/
};

//函数申明
ssize_t simple_read(struct file *filp, char __user *buf, size_t count,
                   loff_t *f_pos);
ssize_t simple_write(struct file *filp, const char __user *buf, size_t count,
                    loff_t *f_pos);
loff_t  simple_llseek(struct file *filp, loff_t off, int whence);
int     simple_ioctl(struct inode *inode, struct file *filp,
                    unsigned int cmd, unsigned long arg);


#endif /* _simple_H_ */

你可能感兴趣的:(linux内核,linux,内核,c语言)