The precondition is that the working directory is under/usr/local/src. Write the de0_led.c driverProgram, As follows:
# Include <Linux/module. h>
# Include <Linux/kernel. h>
# Include <Linux/version. h>
# Include <Linux/init. h>
# Include <Linux/types. h>
# Include <Linux/string. h>
# Include <Linux/slab. h>
# Include </usr/local/src/uClinux-Dist/linux-2.6.x/include/asm-nios2nommu/IO. h>
# Include </usr/local/src/uClinux-Dist/linux-2.6.x/include/asm-nios2nommu/page. h>
# Include </usr/local/src/uClinux-Dist/linux-2.6.x/include/asm-nios2nommu/uaccess. h>
# Include <Linux/sched. h>
# Include <Linux/fs. h>
# Include <Linux/proc_fs.h>
# Include </usr/local/src/uClinux-Dist/linux-2.6.x/include/Linux/sysctl. h>
// # Include </usr/local/src/uClinux-Dist/linux-2.6.x/include/asm-nios2nommu/nios2.h>
# Include </usr/local/src/uClinux-Dist/linux-2.6.x/include/nios2_system.h>
# Define de0_led_major 120 // major number 120
Static char de0_led_name [] = "de0_led ";
Static int de0_led_open (struct inode * inode, struct file * file)
{
Printk ("Open the de0_led device, Major: % d, minor: % d \ n", Major (inode-> I _rdev), minor (inode-> I _rdev ));
Try_module_get (this_module );
Return 0;
}
Static int de0_led_release (struct inode * inode, struct file * file)
{
Printk ("Release the de0_led device! \ N ");
Module_put (this_module );
Return 0;
}
Static ssize_t de0_led_read (struct file * filp, char _ User * buff, size_t Len, loff_t * PPOs) // 32
{
Printk ("read de0_led device \ n ");
Int bytes_read = 0;
Bytes_read = na_led-> np_piodata; // 36
Printk ("bytes_read = % d \ n", bytes_read );
If (copy_to_user (buff, (char *) & bytes_read, sizeof (INT )))
{
Return-efault;
}
Return Len;
}
Static ssize_t de0_led_write (struct file * file, const char _ User * buff, size_t Len, loff_t * Off)
{
Unsigned int data_write = 0;
If (copy_from_user (char *) & data_write, buff, sizeof (INT) // 47
Return-efault;
Na_led-> np_piodata = data_write;
Return Len;
}
Static struct file_operations de0_led_fops = {
Owner: this_module,
Open: de0_led_open,
Release: de0_led_release,
Read: de0_led_read,
Write: de0_led_write // 57
};
Static int _ init led_init (void)
{
Printk ("init the module! \ N ");
Int err;
If (ERR = register_chrdev (de0_led_major, de0_led_name, & de0_led_fops) <0)
{
Printk ("register_chrdev failed! Error code = % d \ n ", err );
Return err;
}
Return 0;
}
Static void _ exit led_exit (void)
{
Printk ("Exit module !! \ N ");
Unregister_chrdev (de0_led_major, de0_led_name );
}
Module_init (led_init );
Module_exit (led_exit );
Module_license ("GPL ");
Put the written driver file under the linux-2.6/Drivers/Char and modify the kconfig and makefile files under the folder.
Add:
Config de0_led
Tristate "Nio led support"
Help
De0_led driver
Add the following in makefile:
OBJ-$ (config_de0_led) + = de0_led.o
Run make menuonfig to configure the kernel. To allow the operating system to support dynamic loading, You must select loadable module support in Linux Kernel configuration, then enter the device drivers option in Linux Kernel configuration, find character devices, and enter, find the newly added NiO led support and select m to dynamically load it. Save and exit.
The processing of user programs is the same as that of Hello world. Now, the SRC folder is compiled with a cross tool chain to copy the generated executable files to romfs/bin.
The next step is to compile the kernel, make.
Here we will summarize the steps for writing the drivers:
- Define the master device number and device name
- Define the functions implemented by the driver, and initialize the file_operations struct variable according to the defined functions.
- Compile the corresponding function bodies according to the defined functions, such as reading and writing functions, and turn on and off functions. When enabling function execution, you must first add a device counter to inform the system that the device is in use. You can also complete some hardware register settings in the open function. This is generally the first time you open the device. The function is used to reduce the device counter by one and inform the kernel that this process is no longer using this device.
- Compile the device Loading Function, also called the initialization function. In the initialization function, the device registration and some hardware-related register settings are completed.
- Compile the device uninstall function, which acts on the opposite of the load function.
- Use a macro to define the loading and unloading functions of a specified module.
- Other optional macro definitions.
After the driver program is compiled, use the user program to verify whether it works normally. User programs do not show hardware registers, but open files, read and write files, close files and other operations. All devices are processed as files. The LED driver test procedure is as follows:
# Include <stdio. h>
// # Include <linux-2.6.x/include/ASM/nios2.h>
# Include <string. h>
# Include <malloc. h>
# Include <sys/types. h>
# Include <sys/STAT. h>
# Include <fcntl. h>
# Include <unistd. h>
# Include <signal. h>
# Include <sys/IOCTL. h>
Void mydelay (INT count)
{
Int I;
Int J;
J = 0;
For (I = 0; I <count; I ++)
{
J = J + I;
}
}
Int main ()
{
Int FD;
Int count;
Char I = 0;
Unsigned char buff [] = {0xfe, 0xfe, 0xfe, 0xfe };
If (FD = open ("/dev/de0_led", o_rdwr) =-1)
{
Perror ("Open eror ");
Exit (1 );
}
While (1)
{
/* If (COUNT = read (FD, (char *) buff, 4 )! = 4)
{
Perror ("read error ");
Exit (1 );
}*/
Mydelay (100000 );
If (COUNT = write (FD, (char *) buff, 4 )! = 4)
{
Perror ("write error ");
Exit (1 );
}
Mydelay (100000 );
I ++;
Buff [4] = I;
}
}
After running the uClinux system, run the Altera nioii eds 11.0 command to communicate with the system. The path of the loadable module in uClinux is/lib/modules/2.6.19-uc1/kernel/Drivers/Char/
Go to this directory and run insmod de0_led.ko to install the kernel module.
Then create a device node and run mknod/dev/de0_led C 120 0
120 indicates the master device number, 0 indicates the secondary device number, and C indicates the char device.
After successfully registering the device and establishing the device node, return to the root directory: CD/
Run the user program and enter the command led_app.
The LED light turns on to prove that the driver works properly.
Note: The function of the user test program is endless, and the light should flash, but the actual effect is not blinking, but always on. Later, I checked the driver carefully and found the problem. After changing the device write function to the following driving mode, the LED will flash as specified by the user program.
Static ssize_t de0_led_write (struct file * file, const char _ User * buff, size_t Len, loff_t * Off)
{
Char data_write [4] = {0 };
If (copy_from_user (data_write, buff, sizeof (INT) // 47
Return-efault;
Na_led-> np_piodata = (data_write [0] | (data_write [1] <8) | (data_write [2] <16) | (data_write [3] <24 ));
Return Len;
}
The previous driver was copied from another user. If there is a problem with the driver, it will be wrong to forcibly convert the address of the int variable to the char * type, if the address value of the int variable is greater than 8 bits, after it is forcibly converted to char *, only the last 8 bits are retained, and all the preceding values are gone. For example, if this address is used to write data, will not respond to the LED. In addition, the system program may crash. UClinux has no memory protection, that is, users may accidentally access the system's memory space and modify the system'sCodeThe memory does not matter, so you should be very careful when writing the program.