707 строки
22 KiB
C
707 строки
22 KiB
C
/***************************************************************************
|
|
*
|
|
* Copyright 2017, CBD BC
|
|
*
|
|
* GPIO hardware keyboard driver
|
|
*
|
|
***************************************************************************/
|
|
|
|
|
|
#include <hw/inout.h>
|
|
#include "gpiokbd.h"
|
|
#include <gulliver.h>
|
|
#include <sys/usbdi.h>
|
|
#include <sys/io-hid.h>
|
|
#include <math.h>
|
|
#include <stdarg.h>
|
|
#include <sys/slog.h>
|
|
#include <sys/slogcodes.h>
|
|
#include <sys/hidut.h>
|
|
#include "sys/usbcodes.h"
|
|
#include <stdint.h>
|
|
#include <sys/mman.h>
|
|
|
|
|
|
int kbd_coid;
|
|
int kbd_chid;
|
|
pthread_t kbd_tid;
|
|
int fd;
|
|
|
|
int gpiokbd_init( void *dll_hdl, dispatch_t *dpp, io_hid_self_t *ioh, char *options );
|
|
int gpiokbd_stop();
|
|
|
|
int gpiokbd_client_attach( int reg_hdl, void *user );
|
|
int gpiokbd_client_detach( int reg_hdl, void *user );
|
|
int gpiokbd_report_read( int reg_hdl, void *user, _uint8 rid, _uint16 rtype, void *rdata, _uint16 rlen );
|
|
int gpiokbd_report_write( int reg_hdl, void *user, _uint8 rid, _uint16 rtype, void *rdata, _uint16 rlen );
|
|
int gpiokbd_get_idle( int reg_hdl, void *user, _uint8 rid, _uint16 *idle_rate );
|
|
int gpiokbd_set_idle( int reg_hdl, void *user, _uint8 rid, _uint16 idle_rate );
|
|
int gpiokbd_get_protocol( int reg_hdl, void *user, _uint8 *protocol );
|
|
int gpiokbd_set_protocol( int reg_hdl, void *user, _uint8 protocol );
|
|
int gpiokbd_reset( int reg_hdl, void *user );
|
|
int gpiokbd_rbuffer_alloc( _uint16 size, void **bptr );
|
|
int gpiokbd_get_string( int reg_hdl, void *user, _uint16 request, void **str );
|
|
int gpiokbd_get_indexed_string( int reg_hdl, void *user, _uint16 index, void **str );
|
|
int gpiokbd_rbuffer_free( void *bptr );
|
|
|
|
gpiokbd_ctrl_t KCtrl;
|
|
struct hiddi_device_instance;
|
|
|
|
io_hid_dll_entry_t io_hid_dll_entry = {
|
|
"devh-gpiokbd",
|
|
2,
|
|
gpiokbd_init,
|
|
gpiokbd_stop
|
|
};
|
|
|
|
io_hid_registrant_funcs_t gpiokbd_funcs = {
|
|
9,
|
|
gpiokbd_client_attach,
|
|
gpiokbd_client_detach,
|
|
gpiokbd_rbuffer_alloc,
|
|
gpiokbd_rbuffer_free,
|
|
gpiokbd_report_read,
|
|
gpiokbd_report_write,
|
|
gpiokbd_get_idle,
|
|
gpiokbd_set_idle,
|
|
gpiokbd_get_protocol,
|
|
gpiokbd_set_protocol,
|
|
// gpiokbd_get_string,
|
|
0,
|
|
gpiokbd_get_indexed_string,
|
|
gpiokbd_reset,
|
|
};
|
|
|
|
char *gpiokbd_opts[] = {
|
|
"poll_interval",
|
|
"verbose",
|
|
"key1mod",
|
|
"key1code",
|
|
"key2mod",
|
|
"key2code",
|
|
"key3mod",
|
|
"key3code",
|
|
"key4mod",
|
|
"key4code",
|
|
NULL
|
|
};
|
|
|
|
static unsigned char kbd_report_descr[] = { /* Report & Boot modes */
|
|
0x05, 0x01, // Usage Oage (Generic Desktop)
|
|
0x09, 0x06, // Usage (Keyboard)
|
|
0xA1, 0x01, // Collection (Application)
|
|
0x05, 0x07, // Usage Page (Key Codes)
|
|
0x19, 0xE0, // Usage Minimum (224)
|
|
0x29, 0xE7, // Usage Maximum (231)
|
|
0x15, 0x00, // Logical Minimum (0)
|
|
0x25, 0x01, // Logical Maximum (1)
|
|
0x75, 0x01, // Report Size (1)
|
|
0x95, 0x08, // Report Count (8)
|
|
0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
|
|
0x95, 0x01, // Report Count (1)
|
|
0x75, 0x08, // Report Size (8)
|
|
0x81, 0x01, // Input (Constant), ;Reserved byte
|
|
0x95, 0x05, // Report Count (5)
|
|
0x75, 0x01, // Report Size (1)
|
|
0x05, 0x08, // Usage Page (Page# for LEDs)
|
|
0x19, 0x01, // Usage Minimum (1)
|
|
0x29, 0x05, // Usage Maximum (5)
|
|
0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report
|
|
0x95, 0x01, // Report Count (1)
|
|
0x75, 0x03, // Report Size (3)
|
|
0x91, 0x01, // Output (Constant), ;LED report padding
|
|
0x95, 0x06, // Report Count (6)
|
|
0x75, 0x08, // Report Size (8)
|
|
0x15, 0x00, // Logical Minimum (0)
|
|
0x26, 0xff, 0x00, // Logical Maximum(255)
|
|
0x05, 0x07, // Usage Page (Key Codes)
|
|
0x19, 0x00, // Usage Minimum (0)
|
|
0x2a, 0xff, 0x00, // Usage Maximum (255)
|
|
0x81, 0x00, // Input (Data, Array), ;Key arrays (6 bytes)
|
|
0xC0 // End Collection
|
|
};
|
|
|
|
|
|
/* Slog wrapper function */
|
|
ssize_t hid_slogf( const char *fmt, ... )
|
|
{
|
|
ssize_t ret = 0;
|
|
va_list arglist;
|
|
int verbosity = KCtrl.verbose;
|
|
|
|
if ( verbosity > 2 )
|
|
{
|
|
va_start( arglist, fmt );
|
|
vfprintf( stderr, fmt, arglist );
|
|
va_end( arglist );
|
|
fprintf( stderr, "\n" );
|
|
}
|
|
|
|
va_start( arglist, fmt );
|
|
ret = vslogf( _SLOGC_INPUT, _SLOG_INFO, fmt, arglist );
|
|
va_end( arglist );
|
|
|
|
return (ret);
|
|
}
|
|
|
|
|
|
/* Setup report descriptor and register with io-hid. */
|
|
int gpiokbd_get_report_descriptor( gpiokbd_ctrl_t KCtrl )
|
|
{
|
|
/* Structures we need to register device in io-hid */
|
|
io_hid_registrant_t dev;
|
|
hidd_device_ident_t device_ident;
|
|
|
|
dev.desc = kbd_report_descr;
|
|
dev.dlen = sizeof( kbd_report_descr );
|
|
|
|
device_ident.vendor_id = GPIOKBD_VENDOR_ID;
|
|
device_ident.product_id = GPIOKBD_DEVICE_ID;
|
|
device_ident.version = GPIOKBD_VERSION_ID;
|
|
|
|
dev.flags = 0;
|
|
dev.device_ident = &device_ident;
|
|
dev.user_hdl = &KCtrl;
|
|
dev.funcs = &gpiokbd_funcs;
|
|
|
|
/* register device with hiddi */
|
|
|
|
return (*(KCtrl.ioh->reg))( KCtrl.dll_hdl, &dev, &(KCtrl.hid_hdl) );
|
|
}
|
|
|
|
|
|
/* Client attaches. First attachment to the device, so enable the device. */
|
|
int gpiokbd_client_attach( int reg_hdl, void *user )
|
|
{
|
|
return (EOK);
|
|
}
|
|
|
|
|
|
/* Last client detached from the device, so disable the device. */
|
|
int gpiokbd_client_detach( int reg_hdl, void *user )
|
|
{
|
|
return (EOK);
|
|
}
|
|
|
|
|
|
/* Client called read report (polls the device) */
|
|
int gpiokbd_report_read( int reg_hdl, void *user, _uint8 rid, _uint16 rtype, void *rdata, _uint16 rlen )
|
|
{
|
|
return (ENOTSUP);
|
|
}
|
|
|
|
|
|
/* Client is sending output/feature report to device. We will use this for
|
|
* calibration requests from a controller calibration utility. */
|
|
int gpiokbd_report_write( int reg_hdl, void *user, _uint8 rid, _uint16 rtype, void *rdata, _uint16 rlen )
|
|
{
|
|
return (ENOTSUP);
|
|
}
|
|
|
|
|
|
/* Fetch the idle time. */
|
|
int gpiokbd_get_idle( int reg_hdl, void *user, _uint8 rid, _uint16 *idle_rate )
|
|
{
|
|
return (ENOTSUP);
|
|
}
|
|
|
|
|
|
/* Set the idle time. */
|
|
int gpiokbd_set_idle( int reg_hdl, void *user, _uint8 rid, _uint16 idle_rate )
|
|
{
|
|
return (EOK);
|
|
}
|
|
|
|
|
|
/* Get the protocol. */
|
|
int gpiokbd_get_protocol( int reg_hdl, void *user, _uint8 *protocol )
|
|
{
|
|
return (EOK);
|
|
}
|
|
|
|
|
|
/* Set the protocol. */
|
|
int gpiokbd_set_protocol( int reg_hdl, void *user, _uint8 protocol )
|
|
{
|
|
return (EOK);
|
|
}
|
|
|
|
|
|
int gpiokbd_get_indexed_string( int reg_hdl, void *user, _uint16 index, void **string )
|
|
{
|
|
return (EOK);
|
|
}
|
|
|
|
|
|
int gpiokbd_get_string( int reg_hdl, void *user, _uint16 request, void **string )
|
|
{
|
|
return (EOK);
|
|
}
|
|
|
|
|
|
int gpiokbd_reset( int reg_hdl, void *user )
|
|
{
|
|
return (EOK);
|
|
}
|
|
|
|
|
|
int gpiokbd_rbuffer_alloc( _uint16 size, void **bptr )
|
|
{
|
|
if ( (*bptr = malloc( size )) == NULL )
|
|
return (ENOMEM);
|
|
|
|
memset( *bptr, 0xff, size );
|
|
|
|
return (EOK);
|
|
}
|
|
|
|
|
|
int gpiokbd_rbuffer_free( void *bptr )
|
|
{
|
|
if ( NULL != bptr )
|
|
free( bptr );
|
|
|
|
return (EOK);
|
|
}
|
|
|
|
|
|
int gpiokbd_stop( void *dll_hdl )
|
|
{
|
|
return (EOK);
|
|
}
|
|
|
|
|
|
void *gpiokbd_event_handler( void *data )
|
|
{
|
|
int rcvid;
|
|
struct _gpio_key *key;
|
|
struct _pulse pulse;
|
|
keybInputReport_t buf;
|
|
int gpio_pin;
|
|
|
|
data = data;
|
|
|
|
while ( 1 )
|
|
{
|
|
if ( ( rcvid = MsgReceivePulse( kbd_chid, &pulse, sizeof( pulse ), NULL )) == -1 )
|
|
continue;
|
|
|
|
gpio_pin = pulse.value.sival_int;
|
|
|
|
hid_slogf( "devh-gpiokbd: pulse code %d recieved. GPIO interrupt from PIN %u", pulse.code, gpio_pin );
|
|
|
|
key = &KCtrl.key[0];
|
|
|
|
key->pressed = 1;
|
|
|
|
switch ( gpio_pin )
|
|
{
|
|
case GPIO_ROW_1:
|
|
if ( key->pressed == 1 )
|
|
{
|
|
buf.modifies = KCtrl.key[0].modifies;
|
|
buf.pressKeys[0] = KCtrl.key[0].scan_code;
|
|
buf.pressKeys[1] = KS_None;
|
|
} else {
|
|
buf.modifies = 0;
|
|
buf.pressKeys[0] = KS_None;
|
|
}
|
|
break;
|
|
|
|
case GPIO_ROW_2:
|
|
if ( key->pressed == 1 )
|
|
{
|
|
buf.modifies = KCtrl.key[1].modifies;
|
|
buf.pressKeys[0] = KCtrl.key[1].scan_code;
|
|
buf.pressKeys[1] = KS_None;
|
|
} else {
|
|
buf.modifies = 0;
|
|
buf.pressKeys[0] = KS_None;
|
|
}
|
|
break;
|
|
|
|
case GPIO_ROW_3:
|
|
if ( key->pressed == 1 )
|
|
{
|
|
buf.modifies = KCtrl.key[2].modifies;
|
|
buf.pressKeys[0] = KCtrl.key[2].scan_code;
|
|
buf.pressKeys[1] = KS_None;
|
|
} else {
|
|
buf.modifies = 0;
|
|
buf.pressKeys[0] = KS_None;
|
|
}
|
|
break;
|
|
|
|
case GPIO_LINE_1:
|
|
if ( key->pressed == 1 )
|
|
{
|
|
buf.modifies = KCtrl.key[3].modifies;
|
|
buf.pressKeys[0] = KCtrl.key[3].scan_code;
|
|
buf.pressKeys[1] = KS_None;
|
|
} else {
|
|
buf.modifies = 0;
|
|
buf.pressKeys[0] = KS_None;
|
|
}
|
|
break;
|
|
|
|
case GPIO_LINE_2:
|
|
if ( key->pressed == 1 )
|
|
{
|
|
buf.modifies = KCtrl.key[4].modifies;
|
|
buf.pressKeys[0] = KCtrl.key[4].scan_code;
|
|
buf.pressKeys[1] = KS_None;
|
|
} else {
|
|
buf.modifies = 0;
|
|
buf.pressKeys[0] = KS_None;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
buf.reserv = 0;
|
|
|
|
(*KCtrl.ioh->send_report)( KCtrl.hid_hdl, (void *)&buf, sizeof( buf ) );
|
|
}
|
|
}
|
|
|
|
|
|
int read_gpio_pin(int gpio_pin)
|
|
{
|
|
int status = 0;
|
|
int pin_status = -1;
|
|
gpio_devctl_t msg;
|
|
|
|
if ( KCtrl.verbose > 3 )
|
|
hid_slogf( "devh-gpiokbd: reading PIN %d", gpio_pin );
|
|
|
|
msg.set_input.pin_num = gpio_pin;
|
|
|
|
// Set pin direction
|
|
if ( (status = devctl( fd, DCMD_SET_INPUT, &msg, sizeof( msg ), NULL )) != EOK )
|
|
{
|
|
if ( KCtrl.verbose )
|
|
hid_slogf( "devh-gpiokbd: GPIO DCMD_SET_INPUT devctl failed; status = %d", status );
|
|
return (-1);
|
|
}
|
|
|
|
if ( ( status = devctl( fd, DCMD_READ, &msg, sizeof( msg ), NULL ) ) )
|
|
{
|
|
if ( KCtrl.verbose )
|
|
hid_slogf( "devh-gpiokbd: GPIO DCMD_READ devctl failed; status = %d", status );
|
|
return (-1);
|
|
}
|
|
|
|
if ( KCtrl.verbose > 3 )
|
|
hid_slogf( "devh-gpiokbd: GPIO Pin %d direction: INPUT value: %d",
|
|
msg.cmd_read.pin_num, msg.cmd_read.data );
|
|
|
|
pin_status = msg.cmd_read.data;
|
|
|
|
return pin_status;
|
|
}
|
|
|
|
|
|
void *gpiokbd_event_handler_polling( void *data )
|
|
{
|
|
struct _gpio_key *key;
|
|
keybInputReport_t buf;
|
|
int status;
|
|
gpio_devctl_t msg;
|
|
int gpio_row1 = 0;
|
|
int gpio_row2 = 0;
|
|
int gpio_row3 = 0;
|
|
int gpio_line1 = 0;
|
|
int gpio_line2 = 0;
|
|
|
|
data = data;
|
|
|
|
while ( 1 )
|
|
{
|
|
gpio_row1 = read_gpio_pin( GPIO_ROW_1 );
|
|
gpio_row2 = read_gpio_pin( GPIO_ROW_2 );
|
|
gpio_row3 = read_gpio_pin( GPIO_ROW_3 );
|
|
|
|
gpio_line1 = read_gpio_pin( GPIO_LINE_1 );
|
|
gpio_line2 = read_gpio_pin( GPIO_LINE_2 );
|
|
|
|
// Set pins direction
|
|
msg.set_output.pin_num = GPIO_LINE_1;
|
|
if ( (status = devctl( fd, DCMD_SET_OUTPUT, &msg, sizeof( msg ), NULL )) )
|
|
{
|
|
if ( KCtrl.verbose )
|
|
hid_slogf( "devh-gpiokbd: GPIO DCMD_SET_OUTPUT devctl failed: %s", strerror( status) );
|
|
}
|
|
|
|
msg.set_output.pin_num = GPIO_LINE_2;
|
|
if ( (status = devctl( fd, DCMD_SET_OUTPUT, &msg, sizeof( msg ), NULL )) )
|
|
{
|
|
if ( KCtrl.verbose )
|
|
hid_slogf( "devh-gpiokbd: GPIO DCMD_SET_OUTPUT devctl failed; status = %d", status );
|
|
}
|
|
|
|
msg.set_output.pin_num = GPIO_ROW_2;
|
|
if ( (status = devctl( fd, DCMD_SET_OUTPUT, &msg, sizeof( msg ), NULL )) )
|
|
{
|
|
if ( KCtrl.verbose )
|
|
hid_slogf( "devh-gpiokbd: GPIO DCMD_SET_OUTPUT devctl failed; status = %d", status );
|
|
}
|
|
|
|
msg.set_output.pin_num = GPIO_ROW_1;
|
|
if ( (status = devctl( fd, DCMD_SET_OUTPUT, &msg, sizeof( msg ), NULL )) )
|
|
{
|
|
if ( KCtrl.verbose )
|
|
hid_slogf( "devh-gpiokbd: GPIO DCMD_SET_OUTPUT devctl failed; status = %d", status );
|
|
}
|
|
|
|
msg.set_output.pin_num = GPIO_ROW_3;
|
|
if ( (status = devctl( fd, DCMD_SET_OUTPUT, &msg, sizeof( msg ), NULL )) )
|
|
{
|
|
if ( KCtrl.verbose )
|
|
hid_slogf( "devh-gpiokbd: GPIO DCMD_SET_OUTPUT devctl failed; status = %d", status );
|
|
}
|
|
|
|
delay( KCtrl.polling_interval );
|
|
|
|
key = &KCtrl.key[0];
|
|
|
|
if ( gpio_line1 == 1 && gpio_row1 == 0 )
|
|
{
|
|
key->pressed = 1;
|
|
buf.modifies = KCtrl.key[0].modifies;
|
|
buf.pressKeys[0] = KCtrl.key[0].scan_code;
|
|
buf.pressKeys[1] = KS_None;
|
|
}
|
|
else if ( gpio_line1 == 1 && gpio_row2 == 0 )
|
|
{
|
|
key->pressed = 1;
|
|
buf.modifies = KCtrl.key[1].modifies;
|
|
buf.pressKeys[0] = KCtrl.key[1].scan_code;
|
|
buf.pressKeys[1] = KS_None;
|
|
}
|
|
else if ( gpio_line1 == 1 && gpio_row3 == 0 )
|
|
{
|
|
key->pressed = 1;
|
|
buf.modifies = KCtrl.key[2].modifies;
|
|
buf.pressKeys[0] = KCtrl.key[2].scan_code;
|
|
buf.pressKeys[1] = KS_None;
|
|
}
|
|
else if ( gpio_line2 == 1 && gpio_row1 == 0 )
|
|
{
|
|
key->pressed = 1;
|
|
buf.modifies = KCtrl.key[3].modifies;
|
|
buf.pressKeys[0] = KCtrl.key[3].scan_code;
|
|
buf.pressKeys[1] = KS_None;
|
|
}
|
|
else if ( gpio_line2 == 1 && gpio_row2 == 0 )
|
|
{
|
|
key->pressed = 1;
|
|
buf.modifies = KCtrl.key[4].modifies;
|
|
buf.pressKeys[0] = KCtrl.key[4].scan_code;
|
|
buf.pressKeys[1] = KS_None;
|
|
}
|
|
else if ( gpio_line2 == 1 && gpio_row3 == 0 )
|
|
{
|
|
key->pressed = 1;
|
|
buf.modifies = KCtrl.key[5].modifies;
|
|
buf.pressKeys[0] = KCtrl.key[5].scan_code;
|
|
buf.pressKeys[1] = KS_None;
|
|
} else {
|
|
if ( key->pressed == 1 )
|
|
{
|
|
key->pressed = 0;
|
|
buf.modifies = 0;
|
|
buf.pressKeys[0] = KS_None;
|
|
|
|
(*KCtrl.ioh->send_report)( KCtrl.hid_hdl, (void *)&buf, sizeof( buf ) );
|
|
}
|
|
}
|
|
|
|
if ( key->pressed == 1 )
|
|
(*KCtrl.ioh->send_report)( KCtrl.hid_hdl, (void *)&buf, sizeof( buf ) );
|
|
}
|
|
}
|
|
|
|
|
|
int gpiokbd_start_driver( char *options )
|
|
{
|
|
char *value;
|
|
|
|
KCtrl.verbose = 0;
|
|
KCtrl.polling_interval = DEFAULT_POLLING_INT;
|
|
|
|
while ( options && *options != '\0' )
|
|
{
|
|
switch ( getsubopt( &options, gpiokbd_opts, &value ) )
|
|
{
|
|
case POLL_INTERVAL:
|
|
KCtrl.polling_interval = strtol( value, 0, 10 );
|
|
hid_slogf( "devh-gpiokbd: Polling interval = %d ms", KCtrl.polling_interval );
|
|
break;
|
|
|
|
case VERBOSE:
|
|
KCtrl.verbose = strtol( value, 0, 10 );
|
|
break;
|
|
|
|
case KEY_1_MODIFIES:
|
|
KCtrl.key[0].modifies = strtol( value, 0, 16 );
|
|
break;
|
|
|
|
case KEY_1_SCAN_CODE:
|
|
KCtrl.key[0].scan_code = strtol( value, 0, 16 );
|
|
break;
|
|
|
|
case KEY_2_MODIFIES:
|
|
KCtrl.key[1].modifies = strtol( value, 0, 16 );
|
|
break;
|
|
|
|
case KEY_2_SCAN_CODE:
|
|
KCtrl.key[1].scan_code = strtol( value, 0, 16 );
|
|
break;
|
|
|
|
case KEY_3_MODIFIES:
|
|
KCtrl.key[2].modifies = strtol( value, 0, 16 );
|
|
break;
|
|
|
|
case KEY_3_SCAN_CODE:
|
|
KCtrl.key[2].scan_code = strtol( value, 0, 16 );
|
|
break;
|
|
|
|
case KEY_4_MODIFIES:
|
|
KCtrl.key[3].modifies = strtol( value, 0, 16 );
|
|
break;
|
|
|
|
case KEY_4_SCAN_CODE:
|
|
KCtrl.key[3].scan_code = strtol( value, 0, 16 );
|
|
break;
|
|
|
|
case KEY_5_MODIFIES:
|
|
KCtrl.key[4].modifies = strtol( value, 0, 16 );
|
|
break;
|
|
|
|
case KEY_5_SCAN_CODE:
|
|
KCtrl.key[4].scan_code = strtol( value, 0, 16 );
|
|
break;
|
|
|
|
case KEY_6_MODIFIES:
|
|
KCtrl.key[5].modifies = strtol( value, 0, 16 );
|
|
break;
|
|
|
|
case KEY_6_SCAN_CODE:
|
|
KCtrl.key[5].scan_code = strtol( value, 0, 16 );
|
|
break;
|
|
|
|
default:
|
|
hid_slogf( "devh-gpiokbd: Invalid option" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (EOK);
|
|
}
|
|
|
|
|
|
/* register driver with hid class */
|
|
int gpiokbd_init( void *dll_hdl, dispatch_t *dpp, io_hid_self_t *ioh, char *options )
|
|
{
|
|
pthread_attr_t attr;
|
|
gpio_devctl_t msg;
|
|
int status;
|
|
|
|
ThreadCtl( _NTO_TCTL_IO, 0 );
|
|
|
|
memset( &KCtrl, 0, sizeof( KCtrl ) );
|
|
|
|
hid_slogf( "devh-gpiokbd: Starting gpiokbd input manager" );
|
|
|
|
if ( (fd = open( GPIO_DEVICE_NAME, O_RDWR )) == -1 )
|
|
{
|
|
hid_slogf( "devh-gpiokbd: failed to open GPIO device %s: %s", GPIO_DEVICE_NAME, strerror( errno ) );
|
|
perror( "devh-gpiokbd: failed to open GPIO device " );
|
|
return (EXIT_FAILURE);
|
|
}
|
|
|
|
if ( (kbd_chid = ChannelCreate( 0 )) == -1 || (kbd_coid = ConnectAttach( 0, 0, kbd_chid, _NTO_SIDE_CHANNEL, 0 )) == -1 )
|
|
{
|
|
hid_slogf( "devh-gpiokbd: Unable to attach channel and connection" );
|
|
perror( "devh-gpiokbd: Unable to attach channel and connection " );
|
|
return (EXIT_FAILURE);
|
|
}
|
|
|
|
// register driver with io-hid
|
|
KCtrl.dll_hdl = dll_hdl;
|
|
KCtrl.ioh = ioh;
|
|
|
|
msg.cmd_intterupt.coid = kbd_coid;
|
|
msg.cmd_intterupt.pin_num = GPIO_ROW_1;
|
|
msg.cmd_intterupt.level = GPIO_INT_LEVEL_LOW;
|
|
|
|
// Set pin direction
|
|
if ( (status = devctl( fd, DCMD_SET_OUTPUT, &msg, sizeof( msg ), NULL )) )
|
|
hid_slogf( "devh-gpiokbd: GPIO DCMD_SET_OUTPUT devctl failed; status = %d", status );
|
|
|
|
msg.cmd_intterupt.pin_num = GPIO_ROW_2;
|
|
msg.cmd_intterupt.level = GPIO_INT_LEVEL_LOW;
|
|
|
|
// Set pin direction
|
|
if ( (status = devctl( fd, DCMD_SET_OUTPUT, &msg, sizeof( msg ), NULL )) )
|
|
hid_slogf( "devh-gpiokbd: GPIO DCMD_SET_OUTPUT devctl failed; status = %d", status );
|
|
|
|
msg.cmd_intterupt.pin_num = GPIO_ROW_3;
|
|
msg.cmd_intterupt.level = GPIO_INT_LEVEL_LOW;
|
|
|
|
// Set pin direction
|
|
if ( (status = devctl( fd, DCMD_SET_OUTPUT, &msg, sizeof( msg ), NULL )) )
|
|
hid_slogf( "devh-gpiokbd: GPIO DCMD_SET_OUTPUT devctl failed; status = %d", status );
|
|
|
|
msg.cmd_intterupt.pin_num = GPIO_LINE_1;
|
|
msg.cmd_intterupt.level = GPIO_INT_LEVEL_LOW;
|
|
|
|
// Set pin direction
|
|
if ( (status = devctl( fd, DCMD_SET_OUTPUT, &msg, sizeof( msg ), NULL )) )
|
|
hid_slogf( "devh-gpiokbd: GPIO DCMD_SET_OUTPUT devctl failed; status = %d", status );
|
|
|
|
msg.cmd_intterupt.pin_num = GPIO_LINE_2;
|
|
msg.cmd_intterupt.level = GPIO_INT_LEVEL_LOW;
|
|
|
|
// Set pin direction
|
|
if ( (status = devctl( fd, DCMD_SET_OUTPUT, &msg, sizeof( msg ), NULL )) )
|
|
{
|
|
hid_slogf( "devh-gpiokbd: GPIO DCMD_SET_OUTPUT devctl failed; status = %d: %s", status, strerror( errno ) );
|
|
perror( "devh-gpiokbd: GPIO DCMD_SET_OUTPUT devctl failed" );
|
|
return (EXIT_FAILURE);
|
|
}
|
|
|
|
// Default key codes
|
|
KCtrl.key[0].modifies = 0x00;
|
|
KCtrl.key[0].scan_code = KS_Left;
|
|
KCtrl.key[1].modifies = 0x00;
|
|
KCtrl.key[1].scan_code = KS_Right;
|
|
KCtrl.key[2].modifies = 0x00;
|
|
KCtrl.key[2].scan_code = KS_Escape;
|
|
KCtrl.key[3].modifies = 0x00;
|
|
KCtrl.key[3].scan_code = KS_Up;
|
|
KCtrl.key[4].modifies = 0x00;
|
|
KCtrl.key[4].scan_code = KS_Down;
|
|
KCtrl.key[5].modifies = 0x00;
|
|
KCtrl.key[5].scan_code = KS_Enter;
|
|
|
|
KCtrl.key[0].lcc = KCtrl.key[1].lcc = KCtrl.key[2].lcc = KCtrl.key[3].lcc = ClockCycles();
|
|
|
|
gpiokbd_get_report_descriptor( KCtrl );
|
|
|
|
gpiokbd_start_driver( options );
|
|
|
|
pthread_attr_init( &attr );
|
|
|
|
if ( pthread_create( &kbd_tid, &attr, (void *)gpiokbd_event_handler_polling, 0 ) )
|
|
{
|
|
hid_slogf( "devh-gpiokbd: Unable to create driver thread" );
|
|
perror( "devh-gpiokbd: Unable to create driver thread" );
|
|
return (EXIT_FAILURE);
|
|
}
|
|
|
|
return (0);
|
|
}
|