Ioctl support for Custom GPIO Serial Communication Device Driver
Pravin Raghul
Embedded Software Engineer | Cortex-M | Embedded Linux & Kernel Drivers | C, C++, Python
This article focuses on enhancing our gpioserdev-driver Custom GPIO Serial Communication Device Driver with IOCTL (Input/Output Control) functionality, enabling direct control of GPIO pins for testing and debugging purposes. We'll explore why ioctl is useful in device drivers, how to implement it, and demonstrate testing of the new functionality.
This article is a continuation of the previous following articles,
Why Add Ioctl Support?
Ioctl system calls enables a direct communication with the user space application and device driver. In this Custom GPIO Serial Communication Device Driver, it provides way to manually control individual GPIO pins during the development phases. Basically to test the strobe and data pins.
How Does Ioctl Work in Our Driver?
?We define two commands to control strobe and data pins. Each command uses the _IOW macro, indicating that we're writing data from user space to kernel space. The 'k' magic number identifies our driver's commands, to prevent conflicts with other drivers.
// IOCTL command definitions
#define GPIOSERDEV_IOC_MAGIC 'k'
#define GPIOSERDEV_STRBPIN _IOW(GPIOSERDEV_IOC_MAGIC, 1, int)
#define GPIOSERDEV_DATAPIN _IOW(GPIOSERDEV_IOC_MAGIC, 2, int)
When a user application calls ioctl, the driver receives the command & argument. copy_from_user used to safely transfer the pin & state value from user space to kernel space. Based on the command, the driver sets the appropriate GPIO pin to the specified state (high or low).
// IOCTL handler function
static long gpioserdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
unsigned long value;
if(copy_from_user(&value ,(int32_t*) arg, sizeof(value))) {
printk("data write : Error!\n");
}
switch(cmd) {
case GPIOSERDEV_STRBPIN:
gpio_set_value(GPIOSERDEV_STRB_PINID, value);
printk("set strobe_pin value = %ld\n", value);
break;
case GPIOSERDEV_DATAPIN:
gpio_set_value(GPIOSERDEV_DATA_PINID, value);
printk("set data_pin value = %ld\n", value);
break;
default:
break; // Invalid command
}
return 0;
}
领英推荐
Testing and Validation
Hardware Setup:
User-Space Application:
Here is the below user space application for accessing the ioctl calls to test the strobe and data pins.,
#include <stdio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define GPIOSERDEV_IOC_MAGIC 'k'
#define GPIOSERDEV_STRBPIN _IOW(GPIOSERDEV_IOC_MAGIC, 1, int)
#define GPIOSERDEV_DATAPIN _IOW(GPIOSERDEV_IOC_MAGIC, 2, int)
void print_usage(const char* program) {
printf("Usage: %s <strobe|data> <on|off>\n", program);
printf("Example: %s strobe on\n", program);
}
int main(int argc, char *argv[]) {
if (argc != 3) {
print_usage(argv[0]);
return 1;
}
int fd = open("/dev/gpioserdev", O_RDWR);
if (fd < 0) {
perror("Failed to open device");
return -1;
}
int value = (strcmp(argv[2], "on") == 0) ? 1 : 0;
unsigned int cmd;
if (strcmp(argv[1], "strobe") == 0) {
cmd = GPIOSERDEV_STRBPIN;
} else if (strcmp(argv[1], "data") == 0) {
cmd = GPIOSERDEV_DATAPIN;
} else {
print_usage(argv[0]);
close(fd);
return 1;
}
if (ioctl(fd, cmd, &value) < 0) {
perror("IOCTL failed");
close(fd);
return -1;
}
printf("%s pin set to %s\n", argv[1], argv[2]);
close(fd);
return 0;
}
Output Validation:
Once the module is loaded, run the user-space application usrgpioserdev and python application to test the status of the strobe and data pin. Refer the below image,
Conclusion
This article demostrated how to implement ioctl calls, providing additional functionalities for the gpioserdev-driver, used to perform test for strobe pin and data pin.
In the next article, we'll explore the device overlay implementation for this gpioserdev-driver. let me know your thoughts...!