i.MX283 development board -LED Linux driver driving a first improvement

On a blog i.MX283 first Linux driver development board said is the most simple LED driver to write, but where there are some shortcomings.

The first is in the use insmod to load drivers, need to use command mknod / dev / imx283_led c 200 0 create a device node manually, or under / dev will not have our devices, applications open ( "/ dev / imx283_led" , O_RDWR) is bound to fail.

Here the improvements to be driven on a LED, automatically create device nodes in the / dev then allowed insmod.

  • udev, mdev mechanism

Linux has udev, mdev mechanisms, and our ARM development board transplantation busybox have mdev mechanism, then mdev to find the appropriate mechanism will be driven by device class class class to automatically create device nodes (premise need mdev)

udev is a user program in Linux to achieve the creation and deletion of files by udev device, udev device can detect the hardware state of the system, the device can create or delete files based on system hardware status. For example, after using the modprobe command successfully load the module automatically in / create corresponding device node files in dev directory, use the rmmod command to unload the driver module after it is deleted device node files in the / dev directory.

To create a class 1. First class and device equipment.

static struct class *led_class;//创建一个LED类
static struct device *led_device;//创建一个LED设备 该设备是需要挂在LED类下面的
static int major;//主设备号

Note: major application is defined as the next dynamic major number, if the manually assigned, major herein needs of a given value

2. Improve the registration and cancellation of character device function

  • Registration device functions:
static int __init led_init(void)
{  
   //1.申请或者指定主设备号 此处由内核动态分配主设备号
   major = register_chrdev(0,DEVICE_NAME,&led_fops);
   if(major < 0)
   {
     printk("register_chrdev error %d\n",major); 
     return major;
   }
   //2.创建一个LED类
   led_class = class_create(THIS_MODULE,"led_class");
   //3.在LED类下面创建一个LED设备 然后mdev通过这个自动创建/dev/"DEVICE_NAME"
   led_device = device_create(led_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME);
   printk("module init ok\n");
   return 0; 
}

class_create function is to create a class, you need to reference the header file #include <linux / device.h>

/* This is a #define to keep the compiler from merging different
 * instances of the __key variable */
#define class_create(owner, name)		\
({						\
	static struct lock_class_key __key;	\
	__class_create(owner, name, &__key);	\
})

owner:THIS_MODULE

name: Class name, free

device_create device for creating a class specified below

struct device *device_create(struct class *class, struct device *parent,
			     dev_t devt, void *drvdata, const char *fmt, ...)
{
	va_list vargs;
	struct device *dev;

	va_start(vargs, fmt);
	dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
	va_end(vargs);
	return dev;
}

class: Specifies a class, the class specified here step created

parent: the parent device, usually NULL

devt: device number, it can be constructed by MKDEV

drvdata: Some devices may use the data, usually NULL

fmt: device name, if set fmt = xxx, it would generate / dev / xxx this device file. The return value is to create good equipment.

MKDEV a macro definition, is to construct a device dev_t type according to the existing number of major and minor numbers.

  • Write-off device functions:
static void __exit led_exit(void)
{
   
  //1.注销设备 cat /proc/devices下不可见
  unregister_chrdev(major, DEVICE_NAME);
  //2.删除LED设备
  device_destroy(led_class, MKDEV(major,0));
  //3.删除LED类
  class_destroy(led_class);
  printk("module exit ok\n");
}

 device_destroy function is to remove a device from the specified class below

/**
 * device_destroy - removes a device that was created with device_create()
 * @class: pointer to the struct class that this device was registered with
 * @devt: the dev_t of the device that was previously registered
 *
 * This call unregisters and cleans up a device that was created with a
 * call to device_create().
 */
void device_destroy(struct class *class, dev_t devt)
{
	struct device *dev;

	dev = class_find_device(class, NULL, &devt, __match_devt);
	if (dev) {
		put_device(dev);
		device_unregister(dev);
	}
}

class: Specifies a class devt: device number

/**
 * class_destroy - destroys a struct class structure
 * @cls: pointer to the struct class that is to be destroyed
 *
 * Note, the pointer to be destroyed must have been created with a call
 * to class_create().
 */
void class_destroy(struct class *cls)
{
	if ((cls == NULL) || (IS_ERR(cls)))
		return;

	class_unregister(cls);
}

cls: Class to be deleted

Full driver functions are given below:

/*
   GPIO Driver driver for EasyARM-iMX283
*/
#include <linux/module.h>//模块加载卸载函数
#include <linux/kernel.h>//内核头文件
#include <linux/types.h>//数据类型定义
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/fs.h>//file_operations结构体
#include <linux/device.h>//class_create等函数
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/bcd.h>
#include <linux/capability.h>
#include <linux/rtc.h>
#include <linux/cdev.h>
#include <linux/gpio.h>//gpio_request  gpio_free函数 

#include <../arch/arm/mach-mx28/mx28_pins.h>

#define DEVICE_NAME	"imx283_led"//驱动名称
#define LED_GPIO	MXS_PIN_TO_GPIO(PINID_LCD_D23)		//for 283 287A/B

static int led_open(struct inode *inode ,struct file *flip)
{

   int ret = -1;
   gpio_free(LED_GPIO); 
   ret = gpio_request(LED_GPIO, "LED1");
   printk("gpio_request = %d\r\n",ret);
   return 0;
}


static int led_release(struct inode *inode ,struct file *flip)
{
  gpio_free(LED_GPIO);
  return 0;  
}


static int led_write(struct file *filp, const char __user *buf, size_t count,
                loff_t *f_pos)
{
   int ret = -1;
   unsigned char databuf[1];
   ret = copy_from_user(databuf,buf,1);
   if(ret < 0 ) 
   	{
   	  printk("kernel write error \n");
	  return ret;
   	}
   gpio_direction_output(LED_GPIO, databuf[0]);
   return ret; 
}


static   led_read(struct file *filp, const char __user *buf, size_t count,
                loff_t *f_pos)
{
    return 0;
}

static struct file_operations led_fops={
	.owner		= THIS_MODULE,
	.open 		= led_open,
	.write		= led_write,
	.read       = led_read,
	.release	= led_release,
};


static struct class *led_class;//创建一个LED类
static struct device *led_device;//创建一个LED设备 该设备是需要挂在LED类下面的
static int major;//主设备号

static int __init led_init(void)
{  
   //1.申请或者指定主设备号 此处由内核动态分配主设备号
   major = register_chrdev(0,DEVICE_NAME,&led_fops);
   if(major < 0)
   {
     printk("register_chrdev error %d\n",major); 
     return major;
   }
   //2.创建一个LED类
   led_class = class_create(THIS_MODULE,"led_class");
   //3.在LED类下面创建一个LED设备 然后mdev通过这个自动创建/dev/"DEVICE_NAME"
   led_device = device_create(led_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME);
   printk("module init ok\n");
   return 0; 
}


static void __exit led_exit(void)
{
   
  //1.注销设备 cat /proc/devices下不可见
  unregister_chrdev(major, DEVICE_NAME);
  //2.删除LED设备
  device_destroy(led_class, MKDEV(major,0));
  //3.删除LED类
  class_destroy(led_class);
  printk("module exit ok\n");
}

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

3. Test

The above-mentioned driver files, test files compiled .ko development board.

First look / dev Mody at the LED device node

At this time, no LED device node, then load driving.

Driver loaded successfully, then we look at the / dev

It has been automatically generated device node device, the master device 250, minor number 0. 

Finally, we then uninstall the driver, and see again the / dev and / proc / devices

No "imx283_led" This device is present, the description has been deleted.

Reference article:

1. "embedded Linux application development entirely manual" 

2. "[punctuality] I.MX6U atom embedded Linux Driver Development Guide V1.0"

 

 

 

Published 45 original articles · won praise 70 · Views 100,000 +

Guess you like

Origin blog.csdn.net/qq_24835087/article/details/104100403