1
1
Fork 0

Драйвер devh-gpiokbd для ЗОСРВ "Нейтрино" редакции 2020

This commit is contained in:
parent 8365adbd8b
commit 3425dc4ecf
11 changed files with 933 additions and 1 deletions

View File

@ -33,6 +33,7 @@
```
|- devh/
| |- egalax/ - Исходный код HID-драйвера поддержки тачскринов egalax, подключаемых по USB
| |- gpiokbd/ - Исходный код HID-драйвера специализированной клавиатуры, [подключенной через GPIO](https://git.kpda.ru/drivers/gpio/src/branch/neutrino/2020/hardware/gpio/am35)
| |- Makefile - Правила сборки дерева исходников
| `- common.mk - Параметры сборки драйверов
|

View File

@ -16,7 +16,7 @@ LDFLAGS += -M
ifeq ($filter usb, $(VARIANTS),,)
NAME=devh
else
EXTRA_SILENT_VARIANTS=usb example egalax touchintl microtouch bt
EXTRA_SILENT_VARIANTS=usb example egalax touchintl microtouch bt gpiokbd
NAME=devh-$(SECTION)
endif

2
devh/gpiokbd/Makefile Normal file
View File

@ -0,0 +1,2 @@
LIST=CPU
include recurse.mk

View File

@ -0,0 +1,2 @@
LIST=VARIANT
include recurse.mk

View File

@ -0,0 +1,2 @@
include ../../../common.mk
include ../../extra.mk

View File

@ -0,0 +1,32 @@
%C Driver for GPIO hardware keyboard
Converts Interrupt events into Generic HID packets.
Syntax:
io-hid -d gpiokbd [option[,option ...]] ... &
Options:
poll_interval=ms Polling interval in ms. Default 50ms.
verbose=level Verbose level
keyXmod=modifier Key scancode modifier (X = 1..6).
keyXcode=scancode Key scancode (X = 1..6).
Default keys codes:
Key 1 (Up)
Key 2 (Down)
Key 3 (Left)
Key 4 (Right)
Key 5 (Enter)
Key 6 (Esc)
Examples:
# Start io-hid using the gpiokbd hardware keys driver.
io-hid -d gpiokbd &
# Start io-hid using the gpiokbd hardware keys driver
with custom scancodes.
io-hid -d gpiokbd key1mod=0x00,key1code=0x04,key2mod=0x04,key2code=0x3d &
(see usbcodes.h for details)

2
devh/gpiokbd/extra.mk Normal file
View File

@ -0,0 +1,2 @@
LVARIANT = $(patsubst amanda,-amanda,$(filter amanda, $(VARIANTS)))
LIB_VARIANT = $(patsubst so.,so,$(subst $(space),.,so $(filter wcc be le amanda,$(VARIANTS))))

98
devh/gpiokbd/gpio_am35.h Executable file
View File

@ -0,0 +1,98 @@
/*
* Copyright 2017, CBD BC
*
* $QNXLicenseC:
* Copyright 2014, QNX Software Systems.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You
* may not reproduce, modify or distribute this software except in
* compliance with the License. You may obtain a copy of the License
* at: http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OF ANY KIND, either express or implied.
*
* This file may contain contributions from others, either as
* contributors under the License or as licensors under other terms.
* Please review this entire file for other proprietary rights or license
* notices, as well as the QNX Development Suite License Guide at
* http://licensing.qnx.com/license-guide/ for other information.
* $
*/
#ifndef _GPIO_AM35_H_INCLUDED
#define _GPIO_AM35_H_INCLUDED
#define GPIO_DEVICE_NAME "/dev/gpio"
#define GPIO_INPUT 0
#define GPIO_OUTPUT 1
#define GPIO_INT_LEVEL_UNCHANGED 0
#define GPIO_INT_LEVEL_LOW 1
#define GPIO_INT_LEVEL_HIGH 2
#define GPIO_RESMGR_NPARTS_MIN 2
#define GPIO_RESMGR_MSGSIZE_MIN 16
#define GPIO_CLIENTS_MAX 32
typedef struct {
uint8_t pin_num;
} gpio_devctl_input_t;
typedef struct {
uint8_t pin_num;
} gpio_devctl_output_t;
typedef struct {
uint8_t pin_num;
uint8_t data;
} gpio_devctl_read_t;
typedef struct {
uint8_t pin_num;
uint8_t data;
} gpio_devctl_write_t;
typedef struct {
uint8_t pin_num;
uint8_t level;
int coid;
} gpio_devctl_int_t;
// A union of all devctl messages
typedef union {
gpio_devctl_input_t set_input;
gpio_devctl_output_t set_output;
gpio_devctl_read_t cmd_read;
gpio_devctl_write_t cmd_write;
gpio_devctl_int_t cmd_intterupt;
} gpio_devctl_t;
typedef struct {
uint8_t pin;
uint8_t level;
} gpio_interrupt_t;
#define GPIO_SET_INPUT 0
#define GPIO_SET_OUTPUT 1
#define GPIO_READ 2
#define GPIO_WRITE 3
#define GPIO_INT_ENABLE 4
#define GPIO_INT_DISABLE 5
#define GPIO_INT_WAIT_PULSE 6
#define DCMD_SET_INPUT __DIOT(_DCMD_MISC, GPIO_SET_INPUT, gpio_devctl_input_t)
#define DCMD_SET_OUTPUT __DIOT(_DCMD_MISC, GPIO_SET_OUTPUT, gpio_devctl_output_t)
#define DCMD_READ __DIOTF(_DCMD_MISC, GPIO_READ, gpio_devctl_read_t)
#define DCMD_WRITE __DIOTF(_DCMD_MISC, GPIO_WRITE, gpio_devctl_write_t)
#define DCMD_INT_ENABLE __DIOTF(_DCMD_MISC, GPIO_INT_ENABLE, gpio_devctl_int_t)
#define DCMD_INT_DISABLE __DIOTF(_DCMD_MISC, GPIO_INT_DISABLE, gpio_devctl_int_t)
#define DCMD_INT_ENABLE_WAIT_PULSE __DIOTF(_DCMD_MISC, GPIO_INT_WAIT_PULSE, gpio_devctl_int_t)
#endif

706
devh/gpiokbd/gpiokbd.c Normal file
View File

@ -0,0 +1,706 @@
/***************************************************************************
*
* 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);
}

84
devh/gpiokbd/gpiokbd.h Normal file
View File

@ -0,0 +1,84 @@
/***************************************************************************
*
* Copyright 2017, CBD BC
*
* GPIO hardware keyboard driver
*
***************************************************************************/
#ifndef _GPIO_KBD_H
#define _GPIO_KBD_H
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <share.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
#include <sys/io-hid.h>
#include <fcntl.h>
#include <sys/types.h>
#include <devctl.h>
#include "gpio_am35.h"
#define POLL_INTERVAL 0
#define VERBOSE 1
#define KEY_1_MODIFIES 2
#define KEY_1_SCAN_CODE 3
#define KEY_2_MODIFIES 4
#define KEY_2_SCAN_CODE 5
#define KEY_3_MODIFIES 6
#define KEY_3_SCAN_CODE 7
#define KEY_4_MODIFIES 8
#define KEY_4_SCAN_CODE 9
#define KEY_5_MODIFIES 10
#define KEY_5_SCAN_CODE 11
#define KEY_6_MODIFIES 12
#define KEY_6_SCAN_CODE 13
#define GPIOKBD_VENDOR_ID (0)
#define GPIOKBD_DEVICE_ID (0)
#define GPIOKBD_VERSION_ID (0x100)
#define NUM_OF_INPUT_KEYS (6)
#define DEFAULT_POLLING_INT 50
#define GPIO_ROW_1 177
#define GPIO_ROW_2 119
#define GPIO_ROW_3 182
#define GPIO_LINE_1 176
#define GPIO_LINE_2 178
struct _gpio_key {
int gpio_isr;
int iid;
int pressed;
int gpio_mask;
uint64_t lcc;
const char *name;
int scan_code;
int modifies;
};
typedef struct _gpiokbd_ctrl {
_uint32 polling_interval;
_uint32 verbose;
void *dll_hdl;
io_hid_self_t *ioh;
int hid_hdl;
struct _gpio_key key[6];
} gpiokbd_ctrl_t;
typedef struct _keybInputReport {
_uint8 modifies; // State of modifiers (from U224 to U231)
_uint8 reserv; // Reserved byte
_uint8 pressKeys[NUM_OF_INPUT_KEYS]; // Usages from U0 to U255
} keybInputReport_t, * pKeybInputReport_t;
#endif /* _GPIO_KBD_H */

3
devh/gpiokbd/pinfo.mk Normal file
View File

@ -0,0 +1,3 @@
define PINFO
PINFO DESCRIPTION=GPIO keyboard HID Driver
endef