Драйвер devh-gpiokbd для ЗОСРВ "Нейтрино" редакции 2020
Этот коммит содержится в:
родитель
8365adbd8b
Коммит
3425dc4ecf
@ -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 - Параметры сборки драйверов
|
||||
|
|
||||
|
@ -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
Обычный файл
2
devh/gpiokbd/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=CPU
|
||||
include recurse.mk
|
2
devh/gpiokbd/arm/Makefile
Обычный файл
2
devh/gpiokbd/arm/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
2
devh/gpiokbd/arm/dll.le.v7/Makefile
Обычный файл
2
devh/gpiokbd/arm/dll.le.v7/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
include ../../../common.mk
|
||||
include ../../extra.mk
|
32
devh/gpiokbd/devh-gpiokbd.use
Обычный файл
32
devh/gpiokbd/devh-gpiokbd.use
Обычный файл
@ -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
Обычный файл
2
devh/gpiokbd/extra.mk
Обычный файл
@ -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
Исполняемый файл
98
devh/gpiokbd/gpio_am35.h
Исполняемый файл
@ -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
Обычный файл
706
devh/gpiokbd/gpiokbd.c
Обычный файл
@ -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
Обычный файл
84
devh/gpiokbd/gpiokbd.h
Обычный файл
@ -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
Обычный файл
3
devh/gpiokbd/pinfo.mk
Обычный файл
@ -0,0 +1,3 @@
|
||||
define PINFO
|
||||
PINFO DESCRIPTION=GPIO keyboard HID Driver
|
||||
endef
|
Загрузка…
x
Ссылка в новой задаче
Block a user