Development of uClinux drivers
Basic knowledge:
Kernel space ------- user space (memory application data exchange, etc)
Device ---- Device Driver ----- device No.
Driver category: character device block device network device
Interrupt handling
Driver development for uClinux and Linux is the same, but the debugging method is different. Learning driver development for uClinux is the process of learning the driver development for Linux. Linux driver debugging requires at least one computer, plus source code-level kernel debugging tools such as GDB and kdbg. If a virtual machine is installed, you only need one computer, however, this requires higher computer performance. For Driver debugging like uClinux, it is best to have a development board or a simulator. Transplantation on the ARM chip is an important application of uClinux. The most common Simulator for simulation of ARM is Skyeye, an open-source software developed by Chinese people. It can not only simulate the ARM kernel, but also provide further support for Chips Using arm as the kernel. You can use Skyeye
-H: view the ARM chips that Skyeye can simulate. Of course, you can also make some extensions to Skyeye to meet your own requirements. The following describes how to add a driver to uClinux.
1. Compile a simple character driver
// ----------------------------------------------- Mydevice. c -------------------------------------------
# Include <Linux/module. h>
# Include <Linux/init. h>
# Include <Linux/fs. h>
# Include <ASM/uaccess. h>
Module_license ("GPL ");
# Define major_num 254 // master device number
# Define driver_name "mydevice"
Static int global_var = 0; // global variable of the "mydevice" Device
Static ssize_t mydevice_read (struct file *, char *, size_t, loff_t *);
Static ssize_t mydevice_write (struct file *, const char *, size_t, loff_t *);
// Initialize the file_operations struct of the character Device Driver
Struct file_operations mydevice_fops =
{
. Read = mydevice_read,
. Write = mydevice_write,
};
Int mydevice_init (void)
{
Int ret;
// Register the device driver
Printk ("<0> mydevice_init \ n ");
Ret = register_chrdev (major_num, driver_name, & mydevice_fops );
Printk ("<0> register_chr_dev return % d \ n", RET );
If (Ret <0)
{
Printk ("<0> mydevice register failed \ n ");
}
Else
{
Printk ("<0> mydevice register success \ n ");
}
Return ret;
}
Void mydevice_exit (void)
{
Printk ("<0> mydevice_exit! \ N ");
Unregister_chrdev (major_num, driver_name );
}
Static ssize_t mydevice_read (struct file * filp, char * Buf, size_t Len, loff_t * Off)
{
// Copy global_var from kernel space to user space
If (copy_to_user (BUF, & global_var, sizeof (INT )))
{
Return-efault;
}
Return sizeof (INT );
}
Static ssize_t mydevice_write (struct file * filp, const char * Buf, size_t Len, loff_t * Off)
{
// Copy data from user sapce to kernel space
If (copy_from_user (& global_var, Buf, sizeof (INT )))
{
Return-efault;
}
Return sizeof (INT );
}
// Configure //-----------------------------------------------------------------------------------------------------------------
2. statically compile the driver into the uClinux kernel
To add a written driver to uClinux, you need to make some modifications to the configuration file and makefile. Because our driver is used as a drivers, we use mydevice. copy C to the (uClinux directory)/(Linux Kernel Directory)/Drivers/Char directory. Modify config. In, makefile, And mem. c In this directory.
1. Modify config. In:
Add the following line under the comment 'character devices' line:
Bool 'support for mydevice' config_mydevice y
2. Modify makefile
In
#
# UClinux drivers
#
Add the following content:
OBJ-$ (config_mydevice) + = mydevice. o
3. Modify mem. C.
Mem. c initializes some virtual devices. These devices usually use memory as the basic "device". We add the mydevice initialization code to it:
Add the following code to the start position of the mem. c file:
# Ifdef config_mydevice
Extern int mydevice_init (void );
# Endif
Modify the chr_dev_init function of mem. C.
If (devfs_register_chrdev (mem_major, "mem", & memory_fops ))
Printk ("unable to get Major % d For memory Devs \ n", mem_major );
Memory_devfs_register ();
Rand_initialize ();
# Ifdef config_mydevice
Mydevice_init ();
# Endif
# Ifdef config_i2c
I2c_init_all ();
# Endif
4. Compile the mydevice driver
All the modifications are so simple. The next question is how to compile our driver into the kernel.
(1) configure the kernel
Run make menuconfig
Go to the kernel/library/defaults selection menu
Select customize kernel settings
Exit and Save settings
Go to the character devices sub-menu in the new menu
Choose support for mydevice
Exit and Save settings
Use make Dep and make commands to generate kernel images and memory file system images
3. test our driver
How to deal with our drivers? Of course, the answer is to build an application. In "study Note 2", I have explained in detail how to add an application to uClinux, now let's take a look at how to call our driver in the application.
In order for our driver to be used by the application, we must create a file node in advance. In general Linux, we can use the mknod command to create the node in the/dev directory. But in the embedded Linux system uClinux, a better way is to let uClinux do these things at startup:
Open the makefile in the (uClinux directory)/vendors/GDB/armulator-EB directory and make some modifications as follows:
(Note: select the makefile under vendors according to the selection in the menu of Vendor/product selection during configuration.
The positions of different makefiles on the chip are different)
Devices = \
Mydevice, C, 254,0 \
Tty, C, 5, 0 console, C, 5, 1 cua0, C, 5, 64 cua1, C, 5, 65 \
Here, mydevice, C, and 0 are the content we added. The meanings of each item are as follows:
Mydevice: Device Name
C: character device
254: master device number
0: Sub-device number
Let's take a look at our testing program:
// ------------------------------------ Hello. c --------------------------------------
# Include <sys/types. h>
# Include <sys/STAT. h>
# Include <stdio. h>
# Include <fcntl. h>
Int main (void)
{
Int FD, num;
FD = open ("/dev/mydevice", o_rdwr, s_irusr | s_iwusr );
If (FD! =-1)
{
Read (FD, & num, sizeof (INT ));
Printf ("The globalvar is % d \ n", num );
Printf ("Please input the num written to globalvar \ n ");
Scanf ("% d", & num );
Write (FD, & num, sizeof (INT ));
Read (FD, & num, sizeof (INT ));
Printf ("The globalvar is % d \ n", num );
Close (FD );
}
Else
{
Printf ("device open failure \ n ");
}
}
This code should be easy to understand. First open the device and then write and read it out.
After the configuration, re-compile the kernel and use Skyeye simulation (we can also use the Development Board for PS)
Now, we have started the development of uClinux drivers.
References:
Http://dev.yesky.com/186/2623186.shtml
This article from the csdn blog, reproduced please indicate the source: http://blog.csdn.net/I2Cbus/archive/2008/08/26/2834849.aspx