This is the first driver written on the MICRO 2440 development board in the process of learning driver development. It realizes the control of S3C2440's GPIO and is the simplest driver on ARM-LINUX. This driver controls 4 LEDs through S3C2440's GPB5~8 and is a MISC (mixed) driver. In fact, MISC is also a special character driver, but the character driver with the main device number 10 is classified as a MISC driver.
The MISC class driver structure is as follows:
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
minor is the specified minor device number. If it is equal to MISC_DYNAMIC_MINOR, it means the minor device number is obtained dynamically.
name is the device name.
fops is a file_operations structure, a set of device operation function pointers.
file_operations structure:
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.ioctl = sbc2440_leds_ioctl,
};
The device omits the OPEN and RELESE operation functions, which means it is in the open state by default. We only need to operate the IO port to turn the LED on and off, so only one IOCTL operation function is needed to meet the requirements.
GPIO port settings:
The S3C2440 GPIO port setting mainly involves setting three registers, namely GPxCON, GPxDAT, and GPxUP (x=A….J).
GPxCON is used to set the function of the IO port. Every two bits correspond to one IO port, input = 00, output = 01; special function = 10;
GPxDAT is the data register of the IO port, and each bit corresponds to one IO port.
GPxUP indicates whether to use pull-up resistors. 0 indicates use. Note that not every IO port has internal integrated pull-up resistors. If not, there is no such register.
The corresponding functions for setting these three registers are: s3c2410_gpio_cfgpin, s3c2410_gpio_setpin.
Driver code:
Loading function:
static int __init dev_init(void)
{
int ret;
int i;
for (i = 0; i < 4; i++) {
s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
s3c2410_gpio_setpin(led_table[i], 0);
}
ret = misc_register(&misc);
printk (DEVICE_NAME "tinitializedn");
return ret;
}
In the loading function, the main tasks are to initialize the IO port and register a MISC class device. In the misc_register call, the MISC class will help us register a character device based on the members in struct miscdevice, so our MISC driver loading function is relatively short.
Uninstall function:
static void __exit dev_exit(void)
{
misc_deregister(&misc);
}
In the uninstall function, just call misc_deregister to uninstall the MISC device.
IOCTL function:
static int sbc2440_leds_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
switch(cmd) {
case 0:
case 1:
if (arg > 4) {
return -EINVAL;
}
s3c2410_gpio_setpin(led_table[arg], !cmd);
return 0;
default:
return -EINVAL;
}
}
In this MISC device, the main function used is the control function. Through the functions of operating IO registers introduced earlier, we can easily control the IO port.
Compile and load:
Put the source code into /drivers/char.
Modify the Kconfig file in the kernel source directory linux-2.6.32.2/drivers/char and add the following text to add the driver to the source tree.
config LOCKER_LEDS
tristate "Locker_Liang leds"
depends on MACH_MINI2440
default m if MACH_MINI2440
help
Locker_Liang leds.
"config" defines a new configuration option. Tristate is the option name. depends on is based on which type of processor. Default means that if the previous processor is not available, this one is selected by default. Help is the help information, and the next line is the help information. For a detailed description of Kconfig syntax, see the Kconfig document.
Modify Makefile and add
obj-$(CONFIG_LOCKER_LEDS)+= MY_leds.o
Note that LOCKER_LEDS must be the same as on Kconfig, and the .o file must also be the same as the source file name.
Enter make menuconfig in the linux-2.6.32.2 directory, select the module we added in Device Drivers -> Character devices, and select M, which means compiling it as a module.
Type make modules to compile the module. A MY_leds.ko file will be generated in /drivers/char. Copy the file to the development board and type insmod MY_leds.ko to load the module into the kernel. The device file will be automatically generated. Type rmmod MY_leds.ko to uninstall the module.
This will allow you to operate the device, but there is another problem: after resetting, you need to reload the driver module and regenerate the device file. At this time, we can add commands to load the driver module and generate the device file in the /etc/init.d/rcS file, so that the settings will be automatically completed every time you start the computer.
Complete code:
#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEVICE_NAME "MY_leds" static unsigned long led_table[] = { S3C2410_GPB(5), S3C2410_GPB(6), S3C2410_GPB(7), S3C2410_GPB(8), }; static unsigned int led_cfg_table[] = { S3C2410_GPIO_OUTPUT, S3C2410_GPIO_OUTPUT, S3C2410_GPIO_OUTPUT, S3C2410_GPIO_OUTPUT, }; static int sbc2440_leds_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { switch(cmd) { case 0: case 1: if (arg > 4) { return -EINVAL; } s3c2410_gpio_setpin(led_table[arg], !cmd); return 0; default: return -EINVAL; } } static struct file_operations dev_fops = { .owner = THIS_MODULE, .ioctl = sbc2440_leds_ioctl, }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; static int __init dev_init(void) { int ret; int i; for (i = 0; i < 4; i++) { s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]); s3c2410_gpio_setpin(led_table[i], 0); } ret = misc_register(&misc); printk (DEVICE_NAME "tinitializedn"); return ret; } static void __exit dev_exit(void) { misc_deregister(&misc); } module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Locker_Liang Inc."); test program: #include #include #include #include #define IOCTL_LED_ON 1 #define IOCTL_LED_OFF 0 void usage(char *exename) { printf("Usage:n"); printf(" %s printf(" led_no = 1, 2, 3 or 4n"); } int main(int argc, char **argv) { unsigned int led_no; int fd = -1; if (argc != 3) goto err; fd = open("/dev/MY_leds", 0); // Open the device if (fd < 0) { printf("Can't open /dev/ledsn"); return -1; } led_no = strtoul(argv[1], 0, 0) - 1; // Which LED to operate? if (led_no > 3) goto err; if (!strcmp(argv[2], "on")) { ioctl(fd, IOCTL_LED_ON,led_no); // turn it on } else if (!strcmp(argv[2], "off")) { ioctl(fd, IOCTL_LED_OFF,led_no); // turn it off } else { goto err; } close(fd); return 0; err: if (fd > 0) close(fd); usage(argv[0]); return -1; } Test command ./test 1 on
Previous article:Linux (AT91SAM9260) adds support for UBIFS file system
Next article:Porting U-BOOT-2.14.07 to MICRO2440 development board
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Molex leverages SAP solutions to drive smart supply chain collaboration
- Pickering Launches New Future-Proof PXIe Single-Slot Controller for High-Performance Test and Measurement Applications
- Apple faces class action lawsuit from 40 million UK iCloud users, faces $27.6 billion in claims
- Apple faces class action lawsuit from 40 million UK iCloud users, faces $27.6 billion in claims
- The US asked TSMC to restrict the export of high-end chips, and the Ministry of Commerce responded
- The US asked TSMC to restrict the export of high-end chips, and the Ministry of Commerce responded
- ASML predicts that its revenue in 2030 will exceed 457 billion yuan! Gross profit margin 56-60%
- Detailed explanation of intelligent car body perception system
- How to solve the problem that the servo drive is not enabled
- Why does the servo drive not power on?
- Mobile 5G device antenna tuning revealed
- CircuitPython upgrade micropython kernel
- Common data storage for python crawlers
- Embedded processor architecture and core
- MSP430F5529 ADC sampling example
- 5 days left to register | Full schedule of the annual AIoT Developer Conference! 19 technical lectures full of practical information!
- STEVAL-IDB010V1 BlueNRG-LP evaluation board data
- Revealing the secret! How can 100 MHz power decoupling hold Gbps high-speed signals?
- Please tell me how to protect the gas meter using Hall device from strong magnetism, and whether it has one or two Hall devices.
- [STM32F769Discovery development board trial] USB-HS HID simple transmission and reception evaluation