Linux character Device driver Development Basics (i)--writing simple LED device driver __linux

Source: Internet
Author: User

Now, let's write our own first character device driver--light LEDs. (Imperfect, back to perfect)

Hardware platform: Exynos4412 (FS4412)


Writing the drive is divided into the following steps:

A--View the schematic, data manual, understand the equipment operation method;

B-Find a similar driver in the kernel, develop it as a template, and sometimes need to start from scratch;

C-Implement driver initialization: For example, register the driver with the kernel so that the application can pass in the filename and the kernel will find the appropriate driver;

D--The design of the operation to be implemented, such as open, close, read, write and other functions;

e-To implement interrupt services (interrupts are not required for each device driver);

F--Compile the driver into the kernel or load it with the INSMOD command;

g--test driver;


Here is a light LED driver:

The first step, of course, is to view the manual, view the schematic diagram, find the corresponding register;


To view the manual, the four led registers are:

Led2

Gpx2con 0X11000C40
Gpx2dat 0X11000C44

led3

Gpx1con 0X11000C20
Gpx1dat 0X11000C24

led4 3-4 3-5

Gpf3con 0x114001e0
Gpf3dat 0x114001e4


Here to note : ARM architecture is IO memory, must be mapped ioremap (); Its role is the mapping of physical memory to virtual memory . Using the Writel readl These two functions, the detailed explanation will not be on the back, look at the simple usage first:

Take LED2 as an example, the following is address mapping and reading and writing:

int *pgpx2con  ;
int *pgpx2dat;

Pgpx2con = Ioremap (Gpx2con, 4);
Pgpx2dat = Ioremap (gpx2dat,4);
Readl (Pgpx2con);
Writel (0x01, Pgpx2dat);

Here is the driver, which will be more complete later
#include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h
> #include <asm/io.h> #include <asm/uaccess.h> static int major = 250;
static int minor=0;
Static dev_t Devno;
static struct class *cls;

static struct device *test_device; #define GPX2CON 0x11000c40 #define GPX2DAT 0x11000c44 #define GPX1CON 0x11000c20 #define GPX1DAT 0x11000c2
4 #define GPF3CON 0x114001e0 #define GPF3DAT 0x114001e4 static int *pgpx2con;

static int *pgpx2dat;
static int *pgpx1con;

static int *pgpx1dat;
static int *pgpf3con;

static int *pgpf3dat;

void fs4412_led_off (int num); void fs4412_led_on (int num) {switch (num) {case 1:writel (READL (Pgpx2dat) | (
			0x1<<7), Pgpx2dat);
		Break Case 2:writel (Readl (Pgpx1dat) | (			
			0x1<<0), Pgpx1dat);			
		Break Case 3:writel (Readl (Pgpf3dat) | (	
			0x1<<4), Pgpf3dat);
		Break Case 4:writel (Readl (Pgpf3dat) | ( 0X1&LT;&LT;5), Pgpf3daT);	
		Break
			Default:fs4412_led_off (1);
			Fs4412_led_off (2);
			Fs4412_led_off (3);
			Fs4412_led_off (4);
			
	Break 
			} void Fs4412_led_off (int num) {switch (num) {case 1:writel (Readl (Pgpx2dat) & (~ (0x1<<7)), Pgpx2dat);
		Break			
			Case 2:writel (Readl (Pgpx1dat) & (~ (0x1<<0)), Pgpx1dat);			
		Break	
			Case 3:writel (Readl (Pgpf3dat) & (~ (0x1<<4)), Pgpf3dat);
		Break			
			Case 4:writel (Readl (Pgpf3dat) & (~ (0x1<<5)), Pgpf3dat);			
	Break
	} static int Led_open (struct inode *inode, struct file *filep) {//open fs4412_led_off (1);
	Fs4412_led_off (2);
	Fs4412_led_off (3);	
	Fs4412_led_off (4);
return 0;
	static int led_release (struct inode *inode, struct file *filep) {//close fs4412_led_off (1);
	Fs4412_led_off (2);
	Fs4412_led_off (3);	
	Fs4412_led_off (4);
return 0;

Static ssize_t led_read (struct file *filep, char __user *buf, size_t len, loff_t *pos) {return 0;} Static ssize_t led_write (struct file *Filep, const char __user *buf, size_t len, loff_t *pos) {int led_num;
	if (len!=4) {return-einval;	
	} if (Copy_from_user (&led_num,buf,len)) {return-efault;
	} fs4412_led_on (Led_num);

	PRINTK ("Led_num =%d \ n", led_num);
return 0; static struct file_operations hello_ops= {. open = Led_open,. Release = Led_release,. Read = Led_read,. WRI

Te = Led_write,};
	static void Fs4412_led_init (void) {Pgpx2con = Ioremap (gpx2con,4);

	Pgpx2dat = Ioremap (gpx2dat,4);
	Pgpx1con = Ioremap (gpx1con,4);

	Pgpx1dat =ioremap (gpx1dat,4);
	Pgpf3con = Ioremap (gpf3con,4);

	Pgpf3dat =ioremap (gpf3dat,4); Writel (Readl (Pgpx2con) & ~ (0xf<<28) | (
	0x1<<28), Pgpx2con); Writel (Readl (Pgpx1con) & ~ (0xf<<0) | (	
	0x1<<0), Pgpx1con); Writel (Readl (Pgpf3con) & ~ (0xff<<16) | (	
0X11&LT;&LT;16), Pgpf3con);	
	static int led_init (void) {int ret;
	Devno = Mkdev (Major,minor);

	ret = Register_chrdev (Major, "led", &hello_ops); CLS = Class_creatE (This_module, "MyClass");
		if (Is_err (CLS)) {Unregister_chrdev (Major, "led");
	Return-ebusy; } Test_device = Device_create (Cls,null,devno,null, "led");//mknod/dev/hello if (Is_err (Test_device)) {Class_destroy (c
		LS);
		Unregister_chrdev (Major, "led");
	Return-ebusy;
	} fs4412_led_init ();
return 0;
	} void Fs4412_led_unmap (void) {Iounmap (Pgpx2con);

	Iounmap (Pgpx2dat);
	Iounmap (Pgpx1con);

	Iounmap (Pgpx1dat);
	Iounmap (Pgpf3con);
Iounmap (Pgpf3dat);
	} static void Led_exit (void) {Fs4412_led_unmap ();
	Device_destroy (CLS,DEVNO);	
	Class_destroy (CLS);
	Unregister_chrdev (Major, "led");
PRINTK ("Led_exit \ n");
} module_license ("GPL");
Module_init (Led_init);
 Module_exit (Led_exit);

Test program:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h >

Main ()
{
	int fd,i,lednum;

	FD = open ("/dev/led", O_RDWR);
	if (fd<0)
	{
		perror ("Open fail \ n");
		return;
	}
	for (i=0;i<100;i++)
	{
		lednum=0;
		Write (fd,&lednum,sizeof (int));
		Lednum = i%4+1;
		Write (fd,&lednum,sizeof (int));	
		Sleep (1);
	}
	Close (FD);
}

Makefile

Ifneq  ($ (kernelrelease),)
obj-m:=hello.o
$ (Info "2nd")
else
#KDIR: =/lib/modules/$ ( Shell uname-r)/build
kdir: =/home/xiaoming/linux-3.14-fs4412
pwd:=$ (Shell PWD) all
:
	$ (info) 1st ")
	Make-c $ (kdir) m=$ (PWD) modules arm-none-linux-gnueabi-gcc test.c
	sudo cp Hello.ko a.out/rootfs/ test/clean
:
	rm-f *.ko *.o *.symvers *.mod.c *.mod.o *.order
endif

After the compilation finishes, copy A.out and Hello.ko to the Development Board:

# Insmod Hello.ko

#mknod/dev/hello C 250 0

#./a.out

will see the effect of the happy lantern.

The rear will be perfect for that drive.



Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.