CONTROL THE GPIO PINS ON THE DELL EMBEDDED BOX PC 5000 IN UBUNTU LINUX ABSTRACT The Dell Embedded Box PC 5000 provides General Purpose I/O (GPIO) pins for customization. Due to the unavailability of the corresponding kernel driver, users who run the Linux system on the Box PC face a problem in controlling the GPIO pins. This white paper describes how to control the GPIO pins by reading/writing IO ports in a user-space program.
TABLE OF CONTENTS GPIO ON DELL EMBEDDED BOX PC 5000 ............................................................................3 RESERVE THE IO RANGE FOR CALLER PROCESS ............................................................3 ACCESS THE SUPER IO CHIP ................................................................................................4 ACCESS THE GPO (OUTPUT) PINS........................................................................................5 READ THE GPI (INPUT) PINS .............
GPIO ON DELL EMBEDDED BOX PC 5000 The Dell Embedded Box PC 5000 provides 16 General Purpose I/O (GPIO) pins organized into two groups of eight pins: GPIO 8 IN (GPI0 to GPI7) for input GPIO 8 OUT (GPO0 to GPO7) for output. The pins are located on the front panels of the Embedded Box PC 5000. See Figure 1 for the placements. Figure 1 The GPIO pins are implemented by an on-board Super IO chip, the Nuvoton NCT6793D. The controller interfaces with the host processor through the Low Pin Count (LPC) bus.
The root privileges can be dropped after calling the ioperm function. A setuid() to a non-root user does not disable the access to the ports 2Eh and 2Fh, whose permissions have been granted in the example source code. The permission to access the IO port can be dropped at the end of the program by using the source code shown below. This is optional because the permission is removed with the process as it exits.
ACCESS THE GPO (OUTPUT) PINS The eight output pins GPIO 8 OUT (GPO0, GPO1,… and GPO7) are controlled on the virtual device 8 on the Super IO chip. To control the GPIO pins, select the device first. See the example which writes the data value 8 to the register 07h on the chip. outb(0x07, LPC_ADDR_PORT); outb(8, LPC_DATA_PORT); In the following example, the address of the register is written to the port 2Eh (i.e. LPC_ADDR_PORT). The data is written to the port 2Fh (i.e. LPC_DATA_PORT).
Each bit of the read byte indicates the current level of a pin. The following code gives a more complete example. It is a function to change the level of the pin specified by the given parameter “pin”, instead of changing all the pins. The value of the parameter “pin” ranges from 0 to 7 to indicate the pin in GPO0 to GPO7.
APPENDIX: FULL SOURCE CODE OF AN EXAMPLE PROGRAM #include #include #include #include #include #include
.base_port = 0xE0, }, { .device_num = 7, .
for ( i = PIN_GPO0 ; i <= PIN_GPO7 ; i++ ) { gc->pins[i].mode = GPIO_MODE_OUTPUT; // we do not allow user to change pin direction as input gc->pins[i].capability = GPIO_CAP_OUTPUT; } for ( i = PIN_GPI0 ; i <= PIN_GPI7 ; i++ ) { gc->pins[i].mode = GPIO_MODE_INPUT; // we do not allow user to change pin direction as output gc->pins[i].capability = GPIO_CAP_INPUT; } enter_extended_function_mode(); int bmp = 0; for ( i = 0 ; i < MAX_PIN_NUM ; i++ ) { int bit_index = i % 8; if ( gc->pins[i].
if (gc->pins[pin].mode != GPIO_MODE_OUTPUT) { fprintf(stderr, "%s: pin %d is not an output pin\n", __FUNCTION__, pin); return -EINVAL; } int index = pin / 8; int dev_num = sio_devices[index].device_num; int base_port = sio_devices[index].
__FUNCTION__, pin); return -EINVAL; } } else return -EINVAL; gc->pins[pin].mode = dir; index = pin / 8; dev_num = sio_devices[index].device_num; base_port = sio_devices[index].
if ( rc ) printf("error happened\n"); else printf("Read PIN_GPI0 level = %d\n", level); gpio_exit(gc); return 0; } 12