IOCTL is a function call that allows you to interface with kernel drivers, allowing you to adjust settings or set parameters from code without compiling a new module.
From a programming perspective, having the linux kernel source is a prerequisite. In this example, I cloned the main kernel:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git linux
Once I had the source, I specifically wanted to see exactly how I could interface with the driver called usblp. I was using a USB to parallel port converter, and wanted to see if there was any way to force it to operate differently as we needed a non-printer device to work with it.
After opening the kernel source, I found the driver file itself which was under /drivers/usb/class/usblp.c. In this file I found a section of information about which IOCTLs it supported, and put them in a header file for my program called usblp-hack.h:
#ifndef USBLP_HACK_H #define USBLP_HACK_H #include <linux/ioctl.h> /* ioctls: */ #define IOCNR_GET_DEVICE_ID 1 #define IOCNR_GET_PROTOCOLS 2 #define IOCNR_SET_PROTOCOL 3 #define IOCNR_HP_SET_CHANNEL 4 #define IOCNR_GET_BUS_ADDRESS 5 #define IOCNR_GET_VID_PID 6 #define IOCNR_SOFT_RESET 7 /* Get device_id string: */ #define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) /* The following ioctls were added for http://hpoj.sourceforge.net: */ /* Get two-int array: * [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3), * [1]=supported protocol mask (mask&(1<<n)!=0 means 7/1/n supported): */ #define LPIOC_GET_PROTOCOLS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_PROTOCOLS, len) /* Set protocol (arg: 1=7/1/1, 2=7/1/2, 3=7/1/3): */ #define LPIOC_SET_PROTOCOL _IOC(_IOC_WRITE, 'P', IOCNR_SET_PROTOCOL, 0) /* Set channel number (HP Vendor-specific command): */ #define LPIOC_HP_SET_CHANNEL _IOC(_IOC_WRITE, 'P', IOCNR_HP_SET_CHANNEL, 0) /* Get two-int array: [0]=bus number, [1]=device address: */ #define LPIOC_GET_BUS_ADDRESS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_BUS_ADDRESS, len) /* Get two-int array: [0]=vendor ID, [1]=product ID: */ #define LPIOC_GET_VID_PID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_VID_PID, len) /* Perform class specific soft reset */ #define LPIOC_SOFT_RESET _IOC(_IOC_NONE, 'P', IOCNR_SOFT_RESET, 0) #endif
There are plenty of hints on usage here, and I was able to grab a little more info after searching for some of those defines in google code search. Using these IOCTLs I wanted to know exactly which modes the USB to parallel converter supported, and try to set it in mode 3, which I hoped would give me more options for talking to the device.
Here is my usblp-hack.c which was able to probe and update these settings, although in my case mode 3 didn’t work, but shows an example of exactly how to do it:
#include "usblp-hack.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h> /* open */
#include <unistd.h> /* exit */
#include <sys/ioctl.h> /* ioctl */
main()
{
int fd;
int twoints[2];
fd = open("/dev/usblp0", O_RDONLY | O_NONBLOCK);
if (fd < 0) {
printf("Cannot open device.\n");
exit(-1);
}
if(ioctl(fd, LPIOC_GET_PROTOCOLS(sizeof(int[2])), &twoints) >= 0)
printf("Great success: %d / %d\n", twoints[0], twoints[1]);
else {
printf("Fail!\n");
exit(-1);
}
if(ioctl(fd, LPIOC_SET_PROTOCOL, 2) >= 0)
printf("set protocol to version 2\n");
else {
printf("Fail!\n");
exit(-1);
}
if(ioctl(fd, LPIOC_GET_PROTOCOLS(sizeof(int[2])), &twoints) >= 0)
printf("Great success: %d / %d\n", twoints[0], twoints[1]);
else {
printf("Fail!\n");
exit(-1);
}
if(ioctl(fd, LPIOC_SOFT_RESET) >= 0)
{
printf("Success reset device\n");
} else {
printf("Could not reset device\n");
exit(-1);
}
close(fd);
exit(0);
}
You can compile the above example just using gcc:
gcc -o usblp-hack usblp-hack.c
You can see in the example above I was able to probe the device to see what mode it was currently in and supports (LPIOC_GET_PROTOCOLS), attempt to set the device mode (LPIOC_SET_PROTOCOL), and soft reset the device (LPIOC_SOFT_RESET).
So in the end, nothing here too complex or mind blowing, but if you are just getting your feet wet it might take you a minute to dig this sort of information up.