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.