[Embedded Linux driver development] a special episode, ioctl system call detailed analysis

  Weary traveling not Lian, a temporary thing we know the victims.
  Step three hundred and hurt the country, eight thousand miles disabled people hanging outside.
  Autumn Hill sword solitary tears, sunset flags generals altar.
  Overseas dust atmosphere is still unknown information, please see Jun Mo made lightly.
            - Li mouth accounted Septasyllabic


A, ioctl system calls

  ioctl system call is mainly used for hardware control capabilities increase system calls, it can build your own commands, can accept parameters. Ioctl by controlling the hardware I / O, () system call to design some control commands to achieve different hardware controlled by an ioctl command must be different in the drive.

  Iotcl function prototype kernel space below, defined ioctl command passed cmd, arg data transfer. After the driver and to give a command cmd arg parameter determination must first be parsed command and parameter parsing ioctl command macro definition with no problem before subsequent handling.

int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
  • file represents a file descriptor, cmd indicates a command, arg represents the parameters associated with the command, as to what the meaning of the expression of specific parameters, entirely defined by driver writers.

ioctl function is shown below the prototype user space,

int ioctl (int fd, unsigned long cmd, ...)
  • fd is the device file is opened, the operation of the device is the command cmd "..." represents a variable number of parameter table, usually char * argp defined, if the command does not require cmd parameter, NULL is passed to.
1.1 ioctl command constituted

  ioctl operation associated with the hardware platform, the driver using the ioctl need to include <linux / ioctl.h> file. Each ioctl command cmd is actually a 32-bit integer, and the meanings of the fields shown in the following table.

Here Insert Picture Description
  For example, 0x82187201, its binary table below. So meaning: Read: _IOR; 536 parameter length; magic number 114, ASCII is r, a function number.

Field 31~30 29~16 15~8 7~0
Binary 10 00 0010 0001 1000 0111 0010 0000 0001

  In fact, this command is <linux / msdos_fs.h> in VFAT_IOCTL_READDIR_BOTH command:#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct __fat_dirent[2])

1.2 ioctl command structure

  Ioctl command for the drive configuration, the first to select a magic number of available signatures is driven as the driving, driven to distinguish different commands. Kernel has been used a lot of magic number, in order to prevent conflict, it is best not to use the magic number of these systems have been occupied as a signature drive. The magic number has been used for a list see the kernel source directory Documentation/ioctl/ioctl-number.txtfiles. On different platforms, the use of the magic number is different, in order to prevent conflict, the magic number may be selected to use with other platforms. After the magic number is selected, this can be defined:

#define LED_IOC_MAGIC 'Z'

  bit ioctl command field [31:30] indicates a direction commands, respectively indication _IO, _IOW, _IOR and _IOWR
these macros, different configurations for each command, particularly in the table below:

command description
_IO(type,nr) No configuration parameters command number
_IOW(type,nr,size) Configuration command to write data to the driver number
_IOR(type,nr,size) Drive configured for reading data from the command number
_IOWR(type,nr,size) Construction of two-way transmission command number

  These macro definitions, type magic number, nr is a functional number , size is the data size. For example, an LED driver configured ioctl command, since the control data transmission without LED, can be defined:

#define SET_LED_ON _IO(LED_IOC_MAGIC, 0)
#define SET_LED_OFF _IO(LED_IOC_MAGIC, 1)

  If you want to drive the write ioctl an int type data, it can be defined:

#define CHAR_WRITE_DATA _IOW(CHAR_IOC_MAGIC, 2, int)

  Similar, int type data read from the drive, it is defined as:

#define CHAR_READ_DATA _IOR(CHAR_IOC_MAGIC, 3, int)

  Note: with a driven ioctl command definition, regardless of whether the data transmission and data transmission direction is the same, the number of each command are not the same.

  After the desired part entirely defined command, the need to define the maximum number of a command, to prevent the introduction parameter exceeds the number range.

1.3 ioctl command parsing

  The driver must parse the incoming commands, including transport direction, the type of command, the command number and a parameter big
small, respectively, can be accomplished by the macro defined in the following table:

Macro definition description
_IOC_DIR (No) Parsing command transmission direction
_IOC_TYPE(nr) Parse command type
_IOC_NR (No) Parse command No.
_IOC_SIZE(nr) Analytical parameters Size

  If the command parsing errors found, you can return -ENOTTY, such as:

if (_IOC_TYPE(cmd) != LED_IOC_MAGIC) {
	return -ENOTTY;
}
if (_IOC_NR(cmd) >= LED_IOC_MAXNR) {
	return -ENOTTY;
}

Second, programming

  The driving example is based industrial motherboard EPC-28x (processor i.MX28x). The board provides a hardware Error indicator, controlled by the processor GPIO1_23, low lighting. EPC-28x is achieved BSP underlying interface GPIO transplant, can be called directly gpio_direction_output, gpio_set_value operator interface and other functions.
  i.MX28 processor family into the IO port 7 BANK, GPIO ID = BANK x 32 + N, for example, the arrangement order number GPIO1_23 is 1 x 32 + 23, is equal to 55.
  In addition, the processor The i.MX28x pins generally have multiple functions, functions as a GPIO pin to a need to set the pin functions multiplexed. This part of the code is not reflected in this example, the need to set up the BSP code in advance.

Listing 0.1 - Header

  The LED driving device, the method implemented using the ioctl, first need to define ioctl operation command. 0.1 program code in Listing 2 defines the operation command: LED_ON and LED_OFF.

#ifndef _LED_DRV_H
#define _LED_DRV_H

#define LED_IOC_MAGIC 'L'
#define LED_ON _IO(LED_IOC_MAGIC, 0)
#define LED_OFF _IO(LED_IOC_MAGIC, 1)

#define LED_IOCTL_MAXNR 2

#endif /*_LED_DRV_H*/
Listing 0.2 - Drivers

  The characteristics of the LED device, the driver only need to implement open, release and ioctl three methods will therefore not be assigned to other members not implemented in the fops. Due to relate to specific hardware platform is required to operate the hardware resources, and therefore must be included in the driver header file associated with the platform, such as hardware.h, gpio.h like.

  In open and release method, the LED corresponding to the output of the GPIO port and the LED is set to be off. In the ioctl command passed in, respectively, the LED control input port high or low, to achieve the purpose of turning on and off the LED.

  In addition, due to changes in the different versions of ioctl possible, to do so is compatible processing. In this driving example, also realized that, with reference to the code lines 39 to 43 and 74 to 78 rows. To achieve the kernel version identification, packet requires <linux / version.h> in the header file. Listing 0.2 is an implementation example of the LED drive, drive is not complicated, not to do too much to explain.

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/version.h>

#include <asm/mach/arch.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
#include <asm/gpio.h>

#include "led_drv.h"

static int major;
static int minor;
struct cdev *led; /* cdev 数据结构 */
static dev_t devno; /* 设备编号 */
static struct class *led_class;

#define DEVICE_NAME "led"

#define GPIO_LED_PIN_NUM 55 /* gpio 1_23 */

static int led_open(struct inode *inode, struct file *file )
{
	try_module_get(THIS_MODULE);
	gpio_direction_output(GPIO_LED_PIN_NUM, 1);
	return 0;
}

static int led_release(struct inode *inode, struct file *file )
{
	module_put(THIS_MODULE);
	gpio_direction_output(GPIO_LED_PIN_NUM, 1);
	return 0;
}

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
	int led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
#else
	static int led_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
#endif
{
	if (_IOC_TYPE(cmd) != LED_IOC_MAGIC) {
		return -ENOTTY;
	}

	if (_IOC_NR(cmd) > LED_IOCTL_MAXNR) {
		return -ENOTTY;
	}

	switch(cmd) {
	case LED_ON:
		gpio_set_value(GPIO_LED_PIN_NUM, 0);
		break;
	
	case LED_OFF:
		gpio_set_value(GPIO_LED_PIN_NUM, 1);
		break;
	
	default:
		gpio_set_value(27, 0);
		break;
	}
	
	return 0;
}

struct file_operations led_fops = {
	.owner = THIS_MODULE,
	.open = led_open,
	.release = led_release,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
	unlocked_ioctl = led_ioctl
#else
	ioctl = led_ioctl
#endif
};

static int __init led_init(void)
{
	int ret;
	
	gpio_free(GPIO_LED_PIN_NUM);
	if (gpio_request(GPIO_LED_PIN_NUM, "led_run")) {
		printk("request %s gpio faile \n", "led_run");
		return -1;
	}

	ret = alloc_chrdev_region(&devno, minor, 1, "led"); /* 从系统获取主设备号 */
	major = MAJOR(devno);
	if (ret < 0) {
		printk(KERN_ERR "cannot get major %d \n", major);
		return -1;
	}

	led = cdev_alloc(); /* 分配 led 结构 */
	if (led != NULL) {
		cdev_init(led, &led_fops); /* 初始化 led 结构 */
		led->owner = THIS_MODULE;
		if (cdev_add(led, devno, 1) != 0) { /* 增加 led 到系统中 */
		printk(KERN_ERR "add cdev error!\n");
		goto error;
	}
	} else {
		printk(KERN_ERR "cdev_alloc error!\n");
		return -1;
	}

	led_class = class_create(THIS_MODULE, "led_class");
	if (IS_ERR(led_class)) {
		printk(KERN_INFO "create class error\n");
		return -1;
	}

	device_create(led_class, NULL, devno, NULL, "led");
	return 0;

error:
	unregister_chrdev_region(devno, 1); /* 释放已经获得的设备号 */
	return ret;
}

static void __exit led_exit(void)
{
	cdev_del(led); /* 移除字符设备 */
	unregister_chrdev_region(devno, 1); /* 释放设备号 */
	device_destroy(led_class, devno);
	class_destroy(led_class);
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

Listing 0.3 - Applications

  After driving completion, the need to write a test program to test the correctness of the drive. Listing 0.3 is a simple test program. After the device is opened, the ioctl method, controls the LED flashes 3 times.

  Note that if the drive is defined ioctl command, the application must define these commands, common practice is the drive containing the header file.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
#include "../led_drv.h"

#define DEV_NAME "/dev/led"

int main(int argc, char *argv[])
{
	int i;
	int fd = 0;
	
	fd = open (DEV_NAME, O_RDONLY);
	if (fd < 0) {
		perror("Open "DEV_NAME" Failed!\n");
		exit(1);
	}
	
	for (i=0; i<3; i++) {
		ioctl(fd, LED_ON);
		sleep(1);
		ioctl(fd, LED_OFF);
		sleep(1);
	}
	
	close(fd);
	return 0;
}
Published 716 original articles · won praise 1197 · Views 850,000 +

Guess you like

Origin blog.csdn.net/ReCclay/article/details/105318756