3. Ioctl() calls

3.1 Description

Before making an ioctl() call to a special file (device driver description file in our case), the device must have been opened by the RTLinux task, using the driver's open() function call which may look like fd = open("/dev/pdiso", O_NONBLOCK).

Then to make any ioctl() call user has to indicate the file descriptor (int FD) that has been returned by the open() function, a command parameter (unsigned char cmd) and, if required, an argument parameter. The call then may look like err=ioctl(FD, cmd, arg) where err is an integer returned by the function. In the pdiso16 device driver, arg is required while reading digital inputs thus, the ioctl() function waits for well sized buffer . User must then provide a buffer address to the function. Used with CHANGE_PORT command, arg takes two values: PORT1 or PORT2 constants.

This section explains the specifications of cmd and arg parameters and the returned values of the ioctl() function.

3.2 Command parameter (cmd)

This unsigned char parameter is used to indicate to the driver which port(s) (CHANGE_PORT, BOTH_PORTS) you want to read or to write on the pdiso16 board. You can also indicate that you want to read digital inputs of your board (DIGITAL_INPUT).

cmd=CHANGE_PORT:

read()/write() functions applied on relay port given in arg field (byte-wise bit manipulation)

cmd=BOTH_PORTS:

read()/write() functions applied on both relay ports (word-wise bit manipulation)

cmd=DIGITAL_INPUT:

read differential digital inputs, result stored at address indicated by the arg parameter.

CHANGE_PORT, BOTH_PORTS and DIGITAL_INPUT are unsigned char (u8) values declared on com.h:

/*com.h*/

/*ioctl() cmd constants*/

#define CHANGE_PORT 0xA1

#define BOTH_PORTS 0xA2

#define DIGITAL_INPUT 0xA3

3.3 Argument parameters (arg)

The arg parameter is used, on the one hand, to select a port when the CHANGE_PORT command is used, on the other hand, to get back the value of the digital input channels.

Selecting port constants

In com.h header file:

/*ioctl() arg constants*/

#define PORT1 0

#define PORT2 1

Example: want to read port2 relay state ?


u8 buffer;   /* u8: byte-wise variable ( = unsigned char ) */
int err, n; 
...
err=ioctl(fd, CHANGE_PORT, PORT2);
if (err == 0) {
    n = read (fd, &buffer, sizeof(buffer));
    if (n > 0) rtl_printf("port2 0x%x\n", buffer );
}
 

Reading the digital input channels

I decided to use an ioctl() call to read these I/O ports instead of adding another device. Although it can be done easily... The command used is DIGITAL_INPUT to signal the driver it has to read its digital input channels and to get back the value in the result buffer.

Note that the result buffer must be sized according to the number of port you want to read (byte-wise for an only port reading, word-wise for a dual port reading).

Example: want to read port1 then both ports digital input state ?


u8    read_buffer_single_port;
u16  read_buffer_double_port;
...
ioctl(fd, CHANGE_PORT, PORT1); 
if (ioctl(fd, DIGITAL_INPUT, &read_buffer_single_port)==0)
    rtl_printf("Digital input PORT1 0x%x\n", read_buffer_single_port);

ioctl(fd, BOTH_PORTS);
if (ioctl(fd, DIGITAL_INPUT, &read_buffer_double_port)==0) 
    rtl_printf("Digital input PORT1 0x%x\n", read_buffer_double_port);
 

3.4 Returned value

The ioctl() call returns 0 on success or -1 on fail. In case of fail, errno values are standardized by the include file <asm/errno.h> so that you can know what kind of problem has occurred.

If the driver has the required debug level, you can also use the command dmesg to see in details where and why the ioctl() call has failed.

Next Previous Contents         Home