1
1
Fork 0

Драйверы devi-[egalax/hid] из состава ЗОСРВ "Нейтрино" редакции 2020

This commit is contained in:
commit 4346965cdc
80 changed files with 4695 additions and 0 deletions

3
Makefile Normal file
View File

@ -0,0 +1,3 @@
LIST=hardware
EARLY_DIRS=devu
include recurse.mk

318
README.md Normal file
View File

@ -0,0 +1,318 @@
## Предостережение
Предоставленный исходный код драйвера [devi-hid](https://help.kpda.ru/help/topic/ru.kpda.doc.os_ru/html/utils/system/devi-hid.html) рекомендуется использовать **только для отладочных целей** при разработке HID-драйверов. Для всех остальных задач следует использовать штатный системный драйвер [devi-hid](https://help.kpda.ru/help/topic/ru.kpda.doc.os_ru/html/utils/system/devi-hid.html). В общем случае **не существует задач**, которые требуется решать в этом драйвере при поддержке нового оборудования (для этого должен быть написан/модифицирован отдельный драйвер ввода или HID-драйвер).
## Общая структура подсистемы ввода
```
┌───────────────────────────┐
│ │
│ Устройство ввода ◂───────────────────────┐
│ │ │
└─────────────▴─────────────┘ │
│ │
┌─────────────┴─────────────┐ │ Не HID-совместимое
│ │ │ устройство
│ HID-драйвер (devh-*) │ │
│ │ │
└─────────────▴─────────────┘ │
│ │
┌─────────────┴─────────────┐ ┌─────────────┴─────────────┐
│ │ │ │
│ HID-менеджер (io-hid) ◂─── * ───┤ Драйвер ввода (devi-*) ◂───▸ /dev/??? (standalone-режим)
│ │ │ │
└───────────────────────────┘ ▲ └─────────────▴─────────────┘
│ │
│ ┌─────────────▾─────────────┐
Интерфейс libhiddi ─────┘ │ │
│ Оконная оболочка Photon │
│ │
└───────────────────────────┘
```
## Дерево исходных кодов
```
|- devi/
| |- egalax/ - Исходный код драйвера поддержки тачскринов egalax, подключаемых по PS/2
| |- hid/ - Исходный код драйвера HID-совместимых устройств (только для отладочных целей)
| |- include/ - Заголовочные файлы библиотек
| |- keymap/ - Библиотека трансляции символов (libkeymap)
| |- lib/ - Библиотека менеджера ресурсов драйвера (libinput)
| |- public/ - Публичные интерфейсы драйвера
| |- Makefile - Правила сборки дерева исходников
| `- common.mk - Параметры сборки драйверов и библиотек
|
`- Makefile - Правила сборки дерева исходников
```
## Сборка драйвера
- Установить и настроить [комплект разработчика](https://help.kpda.ru/help/topic/ru.kpda.doc.dev_tools_ru/html/devkit/devkit.html) для [ЗОСРВ "Нейтрино" редакции 2020](https://help.kpda.ru/help/index.jsp).
- Выполнить команду:
```
make
```
## Запуск драйвера
Общая схема запуска драйвера:
```
devi-* <опции_драйвера> <протокол> <опции протокола> [<устройство> <опции_устройства>] [<фильтр> <опции_фильтра>]
```
Примеры:
```
devi-hirun -b kbd fd -d /dev/kbd ps2 mousedev
└───┬────┘ └───┬───┘ └───┬────┘ └────┬─────┘ └───────┬────────┘ └───┬────┘ └────┬─────┘
│ │ │ │ │ │ │
│ │ │ │ Опции устройства │ │
│ │ │ Устройство │ Устройство
│ │ Протокол Протокол
│ Опции
Драйвер
devi-hid -b touch mouse kbd
└───┬───┘ └───┬───┘ └───────┬───────┘
│ │ │
│ │ Протоколы
│ Опции
Драйвер
```
## События ввода (events)
**Маршрутизация событий:**
```
Hardware → Device → Protocol → Filter → Photon или /dev/???
```
**Виды событий ввода:**
- Относительные - содержат информирмацию об изменении координат на некоторую величину (мышь, touchpad)
- Абсолютные - содержащие координаты в контекста собственного разрешения устройства ввода (touchscreen)
- Клавиатурные - содержат сведения об изменении состояния клавиатуры (состояние клавиш, сканкоды и статусные флаги)
(!) Устройства с абсолютным позиционированием необходимо [калибровать](https://help.kpda.ru/help/topic/ru.kpda.doc.os_ru/html/utils/photon/calib.html) перед использованием. Это позволяет установить соответствие между пространством координат устройства ввода и координатами дисплея.
## Интерфейсы и взаимодействие
Пример чтения ctrl-структуры в клиентском приложении:
```
#include <sys/dcmd_input.h>
...
int main()
{
struct _keyboard_ctrl kbctrl;
int fd = open( "/dev/keyboard0", O_RDWR );
...
/* Инициализация */
...
if ( devctl( fd, _KEYBOARDGETCTRL, &kbctrl, sizeof( kbctrl ), NULL ) != EOK )
{
/* Обработка ошибок */
} else {
/* Структура контроля клавиатуры считана в переменную kbctrl. Можно приступать к ее анализу. */
}
}
```
## Разработка драйвера
**Дескриптор модуля:**
```
struct _input_module
{
/* Module parameters */
input_module_t *up; /* Up module in the bus line */
input_module_t *down; /* Down module in the bus line */
struct Line *line; /* Bus line */
int flags; /* flags */
int type; /* type of module */
char name[12]; /* Module name */
char date[12]; /* Date of compilation */
const char *args; /* Module arguments */
void *data; /* Private module data */
/* Callbacks */
int (*init)( input_module_t *module );
int (*reset)( input_module_t *module );
int (*input)( input_module_t *module, int num, void *data );
int (*output)( input_module_t *module, void *data, int num );
int (*pulse)( message_context_t *ctx, int code, unsigned flags, void *data );
int (*parm)( input_module_t *module, int code, char *optarg );
int (*devctrl)( input_module_t *module, int event, void *data );
int (*shutdown)( input_module_t *module, int delay );
}
```
**Инициализация драйвера:**
- Заполнить структуру дескриптора модуля
- Заполнить структуру `_common_callbacks` (см. ниже):
- Выполнить инициализацию библиотеки `libinput`, вызвав функцию: `devi_init( (struct _common_callbacks *)&ptr );`
- Выполнить всю необходимую инициализацию прочих библиотек и ресурсов
- Передать управление библиотеке `libinput`, вызвав функцию: `begin( (int)argc, (char**)argv );`
Структура `_common_callbacks`:
```
struct _common_callbacks {
int nCallbacks;
int (*pre_init)();
int (*post_init)();
int (*pre_shutdown)();
int (*post_shutdown)();
}
```
Диаграмма последовательности инициализации:
```
┌──────────────────────────┐ ┌──────────────────────┐ ┌──────────────────────────┐
│ Драйвер ввода (devi-*) │ │ Библиотека libinput │ │ Модуль │
└────────────┬─────────────┘ └──────────┬───────────┘ └────────────┬─────────────┘
│ │ │
│ devi_init() │ │
├──────────────────────────▸│ │
│ │ │
│ begin() │ │
├──────────────────────────▸│ │
│ │ │
│ pre_init_callbacks() │ │
│◂──────────────────────────┤ │
│ ├──┐ │
│ │ │ Разбор опций, иницализация │
│ │ │ структур модуля │
│ │◂─┘ │
│ │ │
│ │ init callback │
│ ├───────────────────────────────▸│
│ │ │
│ │ param callback │
│ ├───────────────────────────────▸│
│ │ │
│ │ reset callback │
│ ├───────────────────────────────▸│
│ │ │
│ post_init_callbacks() │ │
│◂──────────────────────────┤ │
│ ├──┐ │
│ │ │ Иницализация интерфейсов │
│ │◂─┘ │
│ ├──┐ │
│ │ │ Иницализация пула потоков │
│ │◂─┘ │
│ ├──┐ │
│ │ │ Запуск менеджера ресурсов │
│ │◂─┘ │
│ │ │
```
**Обработка событий (pulse):**
- Вызывается в ответ на возникновение события
- Обычно реализуется в модулях устройств
- Выполняет сбор данных из устройства
- Возможные способы регистрации обработчика: `devi_register_interrupt()`, `devi_register_pulse()` или `devi_register_timer()`
- Для передачи данных далее по Busline используется функция `module->up->input()`
**Ввод данных (input) передача данных клиенту:**
- Вызывается в моменты, когда модуль более низкого уровня готов к передаче данных
- Модуль устройства:
- Выполнить сбор данных
- Упаковать их в согласованный с модулем протокола формат
- Передать их на уровень модуля-протокола, используя функцию `module->up->input()`
- Модуль протокола:
- Преобразовать данные в стандартную структуру пакета, соответствующего обслуживаемому устройству (`packet_kbd`, `packet_abs`, `packet_rel`)
- Передать их на уровень модуля-протокола, используя функцию `module->up->input()`
- Модуль фильтра:
- Выполнить необходимую коррекцию принятых данных
- Передать данные на реализуемые интерфейсы, используя функцию `devi_enqueue_packet()`
Диаграмма последовательности ввода данных:
```
┌────────────┐ ┌────────────┐ ┌──────────┐ ┌────────────┐ ┌──────────┐ ┌──────────┐
│ Hardware │ │ libinput │ │ Device │ │ Protocol │ │ Filter │ │ Клиент │
└─────┬──────┘ └──────┬─────┘ └─────┬────┘ └──────┬─────┘ └─────┬────┘ └─────┬────┘
│ │ │ │ │ │
│ │ devi_interrupt_attach() │ │ │ │
│ │◂──────────────────────────┤ │ │ │
│ Прерывание │ │ │ │ │
├───────────────▸│ pulse_callback() │ │ │ │
│ ├──────────────────────────▸│ │ │ │
│ │ │ │ │ │
│ │ read() │ │ │ │
│◂───────────────────────────────────────────┤ │ │ │
│ │ │ │ │ │
│ Данные │ │ input │ │ │
├───────────────────────────────────────────▸│ callback │ input │ │
│ │ ├─────────────▸│ callback │ │
│ │ │ ├─────────────▸│ devi_enqueue_packet() │
│ │ │ │ ├────────────────────────▸│
│ │ │ │ │ │
```
**Управление устройством (devctl):**
- Реализует управление модулем и реакцию на внешние [devctl()](https://help.kpda.ru/help/topic/ru.kpda.doc.os_ru/html/libraries/libc/d/devctl.html) команды
- Собственные [devctl()](https://help.kpda.ru/help/topic/ru.kpda.doc.os_ru/html/libraries/libc/d/devctl.html) команды можно зарегистрировать, используя константы из заголовочного файла `include/const.h`
- Модуль устройства:
- Если тип события известен выполнить обработку
- Если тип события не известен вернуть значение `-1` и установить переменную [errno](https://help.kpda.ru/help/topic/ru.kpda.doc.os_ru/html/libraries/libc/e/errno.html) в значение `EINVAL`;
- Модуль протокола:
- Если тип события известен выполнить обработку
- Если тип события не известен и имеется связанный модуль нижнего уровня передать событие далее
## Обзор API библиотеки libinput
- Работа с циклическими буферами (см. функции семейства `buff_*()`)
- Системные функции:
- `clk_get()`
- `devi_request_iorange()`
- Передача данных на/от реализуемых интерфейсов:
- `devi_enqueue_packet()`
- Регистрация обработчиков событий (см. `devi_register_*()`)
- Доступ к данным менеджера ресурсов:
- `devi_get_coid()`
- `devi_get_dispatch_handle()` / `devi_set_dispatch_handle()`
- Работа с менеджером [io-hid](https://help.kpda.ru/help/topic/ru.kpda.doc.os_ru/html/services/io-hid.html):
- `devi_hid_init()`
- `devi_hid_register_client()` / `devi_hid_unregister_client()`
- `devi_hid_server_connect()` / `devi_hid_server_disconnect()`
- `devi_scan_to_usb()` / `devi_usb_to_scan()`

3
devi/Makefile Normal file
View File

@ -0,0 +1,3 @@
EARLY_DIRS=keymap lib
LIST=DEVI
include recurse.mk

61
devi/common.mk Normal file
View File

@ -0,0 +1,61 @@
#
# (c) 2010-2018, SWD Embedded Systems Limited, http://www.kpda.ru
#
ifndef QCONFIG
QCONFIG=qconfig.mk
endif
include $(QCONFIG)
INSTALLDIR=usr/photon/bin
define PINFO
PINFO DESCRIPTION=
endef
USEFILE=$(PROJECT_ROOT)/$(SECTION)/devi-$(SECTION).use
EXTRA_SILENT_VARIANTS = $(subst -, ,$(SECTION))
NAME=$(PROJECT)-$(SECTION)
LIBPREF_ph = -Bstatic
LIBPOST_ph = -Bdynamic
LIBS += input keymap ph gf cache
CCFLAGS += -w0 -D__DATE__=\"$(PINFO_DATE)\" -D__TIME__=\"\"
#PUBLIC_INCVPATH+=$(PROJECT_ROOT)/private $(PROJECT_ROOT)/public
PUBLIC_INCVPATH+=$(PROJECT_ROOT)/public
SERVICES_ROOT=$(PRODUCT_ROOT)/../services
LIB_VARIANT=$(subst dll,o,$(COMPOUND_VARIANT))
# Local modifications of make environment
-include ../../../private.mk
include $(MKFILES_ROOT)/qmacros.mk
include $(PROJECT_ROOT)/$(SECTION)/pinfo.mk
-include $(PROJECT_ROOT)/roots.mk
ifndef DEVILIB_ROOT
DEVILIB_ROOT=$(PROJECT_ROOT)/lib
endif
ifndef KEYMAP_ROOT
KEYMAP_ROOT=$(PROJECT_ROOT)/keymap
endif
EXTRA_INCVPATH+=$(PROJECT_ROOT)/private/sys $(PROJECT_ROOT)/private
EXTRA_INCVPATH+=$(PROJECT_ROOT)/public/sys
EXTRA_LIBVPATH+=$(SERVICES_ROOT)/usb/usbdi/$(subst x86/so.,x86/so,$(CPU)/so.$(filter le be,$(subst ., ,$(VARIANTS))))
EXTRA_LIBVPATH+=$(SERVICES_ROOT)/hid/hiddi/$(subst x86/so.,x86/so,$(CPU)/so.$(filter le be,$(subst ., ,$(VARIANTS))))
EXTRA_INCVPATH+=$(PROJECT_ROOT)/include $(PROJECT_ROOT)/../../lib/ph
EXTRA_LIBVPATH+=$(DEVILIB_ROOT)/$(OS)/$(CPU)/a.$(COMPOUND_VARIANT) $(KEYMAP_ROOT)/$(OS)/$(CPU)/a.$(COMPOUND_VARIANT)
EXTRA_LIBVPATH+=$(DEVILIB_ROOT)/$(OS)/$(CPU)/a.$(COMPOUND_VARIANT).shared $(KEYMAP_ROOT)/$(OS)/$(CPU)/a.$(COMPOUND_VARIANT).shared
include $(MKFILES_ROOT)/qtargets.mk
infoinfo:
echo $(VARIANT1) $(COMPOUND_VARIANT)

2
devi/egalax/Makefile Normal file
View File

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

View File

@ -0,0 +1,46 @@
%C [general_opts] protocol* [protocol_opts]*
%C : EETI eGalaxTouch (PS/2) Input Manager for Photon
ATTENTION! Manager is incompatible with any ps2 hid modules
General opts:
-P disable photon interface (default start Photon interface)
-r start resource manager interface (only use if not using Photon)
-b prevent CASB exit (default allow CASB)
-G presence of grafx driver is not required when
starting up a touchscreen driver; useful in debug mode
-g input group (default 1)
-v increment verbosity (default 0)
-l list List the internal modules. Modules are listed in
the following format:
module name | date last compiled | revision | class
where: class is comprised of (D)evice and/or
(P)rotocol and/or (F)ilter
Protocol and protocol_opts:
egalaxtouch [egalaxtouch_opts] [uart uart_opts]
protocol modules and their options:
egalax Elographics smartset protocol
-R Don't reset device (default reset device)
filter modules and their options:
abs Transform and compresses absolute coordinate "touch" events
-b Touching the screen is a right mouse button (default left)
-c Calibrate mode - don't transform coordinates
-f filename Calibration file name
-o x,y Origin of display region (default, origin of graphics region)
-s x,y Coordinates of lower right corner of display region
(default, width and height of graphics region)
-x Reverse X
-y Reverse Y
Examples
--------
%C egalax

495
devi/egalax/egalax.c Normal file
View File

@ -0,0 +1,495 @@
/*
* (c) 2016, SWD Embedded Systems Limited, http://www.kpda.ru
*/
/*
* smarttest.c
*
* Elographics touch screen protocol.
*
*/
#include "devi.h"
#include <time.h>
#include <pthread.h>
#define TRUE 1
#define FALSE !TRUE
#define DEBOUNCE 80000L
#define TRY_LIMIT (100000)
#define TIME_DELAY (10000)
#define IN_BUFF_FULL (0x2)
#define OUT_BUFF_FULL (0x1)
#define AUX_IRQ 12 /* default aux irq */
#define PS2_DATA_PORT 0x60
#define PS2_STATUS_REGISTER 0x64
#define PS2_COMMAND_REGISTER 0x64
#define PS2_TEST_CONTROLLER 0xAA
#define PS2_SELFTEST_SUCCESS 0x55
#define PS2_READ_CONFBYTE 0x20
#define PS2_WRITE_CONFBYTE 0x60
#define PS2_AUX_TEST 0xA9
#define PS2_AUX_WRITE 0xD4
#define AUX_DISABLE 0xA7 /* disable the aux device */
#define AUX_ENABLE 0xA8 /* enable the aux device */
#define AUX_ENABLE_XFER 0xf4 /* enable stream mode transfer */
#define AUX_DISABLE_XFER 0xf5 /* disable stream mode transfer */
#define AUX_RESET 0xFF /* RESET mouse */
#define AUX_COMPLETE 0xaa /* Mouse complete */
#define AUX_GET_STATUS 0xe9 /* get mouse state */
#define AUX_DEV_ID 0xf2 /* get device ID */
#define AUX_STREAM_MODE 0xea /* Set stream mode */
// Mouse replies
#define RESEND (0xfe) /* resend */
#define ACK (0xfa)
#define NUM_OF_RETRIES (5)
#define TRY_LIMIT (100000)
#define TIME_DELAY (10000)
#define IN_BUFF_FULL (0x2)
#define OUT_BUFF_FULL (0x1)
#define DATA_PACKAGE_SIZE (5)
#define FLAG_INIT 0x1000
#define FLAG_RESET 0x2000
struct data {
int flags;
struct sigevent event;
struct packet_abs tp;
int state; /* current state (see smart_input for details) */
};
extern struct sigevent event;
static int egalax_init(input_module_t *module);
static int egalax_devctrl(input_module_t *module,int event,void *ptr);
static int egalax_reset(input_module_t *module);
static int egalax_input(input_module_t *module, int num, void *ptr);
static int egalax_parm(input_module_t *module,int opt,char *optarg);
static int egalax_shutdown(input_module_t *module, int delay);
static int egalax_pulse(message_context_t *ctp, int code, unsigned flags, void *data);
void* inter_wait_cycle( input_module_t *module );
int ps2_init( void );
int aux_reset( void );
input_module_t egalax = {
NULL,
NULL,
NULL,
0,
DEVI_CLASS_ABS | DEVI_MODULE_TYPE_DEVICE | DEVI_MODULE_TYPE_PROTO,
"egalax",
__DATE__,
"R",
NULL, // data
egalax_init,
egalax_reset,
egalax_input,
NULL,
NULL, //egalax_pulse,
egalax_parm,
egalax_devctrl,
egalax_shutdown,
};
/* Description: callback initialisation function; it is called when input module */
/* initializes input system */
/* Input : input_module_t * module - pointer to module descriptor */
/* Output : None */
/* Return : 0 if OK, otherwise - (-1) */
int egalax_init(input_module_t *module)
{
struct data *dp = module->data;
ThreadCtl( _NTO_TCTL_IO, 0 );
if( !module->data ) {
if( !(dp = module->data = calloc(sizeof *dp, 1)) ) {
return (-1);
}
SIGEV_INTR_INIT( &(dp->event) );
dp->flags = ABSOLUTE | ABS_UNCALIBRATED | FLAG_RESET;
dp->state = 0;
}
ps2_init();
return (0);
}
void* inter_wait_cycle( input_module_t *module )
{
int id;
struct data *dp = module->data;
id = InterruptAttachEvent( AUX_IRQ, &dp->event, _NTO_INTR_FLAGS_END );
if ( id == -1 ) {
fprintf(stderr, "Mouse interrupt attach failed\n" );
exit ( -1 );
}
uint8_t data[DATA_PACKAGE_SIZE];
int count = 0;
for (;;)
{
InterruptWait( 0, NULL );
data[count++] = in8( PS2_DATA_PORT );
InterruptUnmask( AUX_IRQ, id );
if ( count == DATA_PACKAGE_SIZE ) {
(module->input)( module, DATA_PACKAGE_SIZE, data );
count = 0;
}
}
return NULL;
}
int egalax_devctrl(input_module_t *module, int event, void *ptr)
{
struct data *dp = module->data;
input_module_t *down = module->down;
switch(event) {
case DEVCTL_GETDEVFLAGS:
*(unsigned short *)ptr = (dp->flags & FLAGS_GLOBAL);
break;
case DEVCTL_GETPTRBTNS:
*(unsigned long *)ptr = 1L;
break;
case DEVCTL_GETPTRCOORD:
*(unsigned char *)ptr = '\02';
break;
case DEVCTL_GETPTRPRESS:
*(unsigned char *)ptr = (dp->flags & ABS_PRESS_DATA)?1:0;
break;
case DEVCTL_GETCOORDRNG: {
struct devctl_coord_range *range = ptr;
// TODO: look for coord range
range->min = 0;
range->max = 4095;
break;
}
case DEVCTL_GETPRESSRNG: {
// for all smartset devices at present the range is 0-255
struct devctl_coord_range *range = ptr;
range->min = 0;
range->max = 255;
break;
}
default:
return (-1);
}
return (0);
}
/* Description: this callback funtion is called when the module is linked into the */
/* event bus;it is used to set initial module state on the protocol */
/* level */
/* Input : input_module_t * module - pointer to module descriptor */
/* Output : None */
/* Return : 0 if OK, otherwise -1 */
int egalax_reset(input_module_t * module)
{
struct data *dp = module->data;
input_module_t *down = module->down;
if((dp->flags & FLAG_INIT) == 0) { // if not initialized
pthread_attr_t attr;
aux_reset();
pthread_attr_init( &attr );
if ( pthread_create( NULL, &attr, &inter_wait_cycle, module ) != EOK ) {
fprintf(stderr, "Unable to create interrupt handler thread\n" );
exit ( -1 );
}
dp->flags |= FLAG_INIT;
}
// if (dp->flags & FLAG_RESET)
// aux_reset();
dp->state = 0;
return 0;
}
/* Description: main protocol processing function. It will be called by the */
/* device layer to pass it data to process. Its job is to interpret */
/* the data according to the Elographics touch screen protocol, create */
/* a data structure, fill it in and hand it off to the filter layer */
/* module above it. The protocol is processed using simple state */
/* machine. State info is kept in module's private data */
/* Input : input_module_t * module - pointer to module descriptor */
/* int num - number of bytes to process */
/* void * arg - raw data to process */
/* Output : None */
/* Return : 0 if OK, otherwise -1 */
int egalax_input( input_module_t *module, int num, void *ptr )
{
int i, enqueue = 0;
uint8_t *p = (uint8_t *)ptr;
struct data *dp = module->data;
input_module_t *up = module->up;
if(verbosity >= 5)
{
fprintf( stderr, "Received : ");
for(i = 0; i < num; ++i)
fprintf( stderr, "%#x ", (int)*((_uint8 *)ptr + i));
fprintf( stderr, "\n");
}
if( p[0] & 0x01 ) dp->tp.buttons = 4L;
if( (p[0] & 0x01) == 0 ) dp->tp.buttons = 0;
dp->tp.y = ( (p[1] & 0x7f) << 7) | (p[2] & 0x7f);
dp->tp.x = ( (p[3] & 0x7f) << 7) | (p[4] & 0x7f);
dp->state = 0;
dp->tp.flags = dp->flags;
clk_get(&dp->tp.timestamp);
int ret = (up->input)(up, 1, &dp->tp); // send data upwards
if(verbosity >= 5)
fprintf( stderr, "Translated: x = %d, y = %d; ret = %d (%s)\n", dp->tp.x, dp->tp.y, ret, up->name );
return (0);
}
/* Description: this is a callback function for command line parameter processing */
/* (all valid parameters for device module are listed in smartset.args)*/
/* Input : input_module_t * module - pointer to module descriptor */
/* int opt - parameter code */
/* char * optarg - optional parameter value */
/* Output : None */
/* Return : 0 if OK, otherwise -1 */
int egalax_parm(input_module_t *module, int opt, char *optarg)
{
struct data *dp = module->data;
if(verbosity >= 5)
fprintf(stderr, "(%s): params\n", module->name);
switch (opt) {
case 'R':
dp->flags &= ~FLAG_RESET;
break;
default:
return (-1);
}
return (0);
}
/* Description: this is a callback function which is called when resourse manager */
/* is shutting down */
/* Input : input_module_t * module - pointer to module descriptor */
/* int delay - program doesn't use this parameter */
/* Output : None */
/* Return : 0 if OK, otherwise -1 */
/* Comment : Does nothing for the protocol level */
int egalax_shutdown(input_module_t *module, int delay)
{
return (0);
}
int drain_input_buffer()
{
int nTries;
for (nTries = TRY_LIMIT; nTries && ( in8( PS2_STATUS_REGISTER ) & IN_BUFF_FULL); nTries--) {
nanospin_ns( TIME_DELAY );
}
return (nTries == 0);
}
int drain_output_buffer()
{
int nTries;
for (nTries = TRY_LIMIT; nTries && ( in8( PS2_STATUS_REGISTER ) & OUT_BUFF_FULL ); nTries--) {
nanospin_ns( TIME_DELAY );
in8( PS2_DATA_PORT );
}
return (nTries == 0);
}
int ps2_wait_reply()
{
int nTries;
uint8_t status;
int ret = -1;
// Poll bit 0 (0x01 mask) of the Status Register ("Input buffer empty/full")
// until it becomes full, or until your time-out expires
for ( nTries = TRY_LIMIT; nTries; nTries-- )
{
status = in8 ( PS2_STATUS_REGISTER );
if ( (status & OUT_BUFF_FULL) ) {
ret = in8( PS2_DATA_PORT );
break;
}
nanospin_ns( TIME_DELAY );
}
return ret;
}
int ps2_send_command( uint8_t cmd, int n, uint8_t *reply )
{
int i;
drain_output_buffer();
drain_input_buffer();
out8( PS2_COMMAND_REGISTER, cmd );
for ( i = 0; i < n; ++i )
reply[i] = ps2_wait_reply();
return i;
}
int ps2_send_data( uint8_t data, int n, uint8_t *reply )
{
int nTries, i;
uint8_t status;
int ret = -1;
for ( nTries = TRY_LIMIT; nTries; --nTries )
{
status = in8 ( PS2_STATUS_REGISTER );
if ( ( status & IN_BUFF_FULL ) == 0 ) { // Input buffer status (0 = empty, 1 = full)
out8( PS2_DATA_PORT, data );
break;
}
nanospin_ns( TIME_DELAY );
}
if ( nTries == 0 )
return -1;
for ( i = 0; i < n; ++i )
reply[i] = ps2_wait_reply();
return i;
}
int ps2_init( void )
{
uint8_t reply[1];
int ret = 0;
//aux_send_command( AUX_DISABLE_1PORT, 0, NULL );
ps2_send_command( AUX_DISABLE, 0, NULL );
ps2_send_command( PS2_TEST_CONTROLLER, 1, reply );
if ( reply[0] != PS2_SELFTEST_SUCCESS ) {
fprintf( stderr, "PS2 controller selftest failed (0x%x)\n", reply[0] );
ret = -1;
}
ps2_send_command( PS2_AUX_TEST, 1, reply );
if ( reply[0] != 0 ) {
fprintf( stderr, "PS2 second port test failed (0x%x)\n", reply[0] );
ret = -1;
}
ps2_send_command( PS2_READ_CONFBYTE, 1, reply );
reply[0] |= 0x3; // Enable interrupts (two first bits)
ps2_send_command( PS2_WRITE_CONFBYTE, 0, NULL );
ps2_send_data( reply[0], 0, NULL );
// Enable device - we are interested only in mouse
ps2_send_command( AUX_ENABLE, 0, NULL );
return ret;
}
int aux_reset( void )
{
uint8_t egalax_diag[] = { 0x0A, 1, 'A' };
uint8_t reply[4];
int ret = 0, i;
reply[0] = 0;
ps2_send_command( PS2_AUX_WRITE, 0, NULL );
if ( ps2_send_data( AUX_RESET, 1, reply ) == -1 || reply[0] != ACK ) {
fprintf( stderr, "Error while reseting aux device\n" );
ret = -1;
}
reply[0] = 0;
ps2_send_command( PS2_AUX_WRITE, 0, NULL );
ps2_send_data( AUX_STREAM_MODE, 1, reply );
if ( reply[0] != ACK )
fprintf( stderr, "Error transmitting data to aux device\n" );
reply[0] = 0;
ps2_send_command( PS2_AUX_WRITE, 0, NULL );
ps2_send_data( egalax_diag[0], 1, reply );
if ( reply[0] != ACK )
fprintf( stderr, "Error transmitting data to aux device\n" );
reply[0] = 0;
ps2_send_command( PS2_AUX_WRITE, 0, NULL );
ps2_send_data( egalax_diag[1], 1, reply );
if ( reply[0] != ACK )
fprintf( stderr, "Error transmitting data to aux device\n" );
reply[0] = 0;
ps2_send_command( PS2_AUX_WRITE, 0, NULL );
ps2_send_data( egalax_diag[2], 4, reply );
if ( reply[0] != ACK )
fprintf( stderr, "Error transmitting data to aux device\n" );
for ( i = 1; i <= 3; ++i )
if ( reply[i] != egalax_diag[i-1] )
break;
if ( i != 4 ) {
fprintf( stderr, "Error transmitting egalax diag\n" );
ret = -1;
}
reply[0] = 0;
ps2_send_command( PS2_AUX_WRITE, 0, NULL );
ps2_send_data( AUX_ENABLE_XFER, 1, reply );
if ( reply[0] != ACK )
fprintf( stderr, "Error transmitting data to aux device\n" );
/* ps2_send_command( PS2_AUX_WRITE, 0, NULL );
ps2_send_data( 0xE9, 4, reply );
if ( reply[0] == ACK )
fprintf( stderr, "status = %#x,%#x,%#x\n", reply[1], reply[2], reply[3] );*/
return ret;
}

17
devi/egalax/main.c Normal file
View File

@ -0,0 +1,17 @@
/*
* (c) 2016, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include "devi.h"
extern input_module_t egalax;
input_module_t *modules[] = {
&egalax,
NULL
};
int main(int argc, char *argv[])
{
return begin(argc, argv);
}

2
devi/egalax/nto/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 @@
include ../../../../common.mk

7
devi/egalax/pinfo.mk Normal file
View File

@ -0,0 +1,7 @@
#
# (c) 2016, SWD Embedded Systems Limited, http://www.kpda.ru
#
define PINFO
PINFO DESCRIPTION=Elographics input manager for Photon
endef

9
devi/egalax/private.mk Normal file
View File

@ -0,0 +1,9 @@
#
# (c) 2016, SWD Embedded Systems Limited, http://www.kpda.ru
#
EXTRA_LIBVPATH+=$(PROJECT_ROOT)/lib/$(OS)/$(CPU)/a.$(LIB_VARIANT).shared $(PROJECT_ROOT)/keymap/$(OS)/$(CPU)/a.$(LIB_VARIANT).shared
LIBS=inputS keymapS ph gf
CCFLAGS += $(CCFLAGS_$(TYPE))
EXTRA_DEPS=$(PROJECT_ROOT)/lib/$(OS)/$(CPU)/a.$(LIB_VARIANT).shared/libinputS.a $(PROJECT_ROOT)/keymap/$(OS)/$(CPU)/a.$(LIB_VARIANT).shared/libkeymapS.a

2
devi/hid/Makefile Normal file
View File

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

253
devi/hid/control.c Normal file
View File

@ -0,0 +1,253 @@
/*
* (c) 2010, SWD Embedded Systems Limited, http://www.kpda.ru
*/
/*
* Предостережение:
*
* Предоставленный исходный код драйвера devi-hid рекомендуется использовать
* только для отладочных целей при разработке HID-драйверов. Для всех остальных
* задач следует использовать штатный системный драйвер devi-hid.
*
* В общем случае не существует задач, которые требуется решать в этом драйвере
* при поддержке нового оборудования (для этого должен быть написан/модифицирован
* отдельный драйвер ввода или HID-драйвер).
*/
/*
* control.c
*
* The HID USB control combined device/protocol module.
*
*/
#include <sys/devi.h>
#include "hid.h"
#include <assert.h>
#define FLAG_INIT 0x0100
#define FLAG_RESET 0x0200
#define FLAG_KIOSK_MODE 0x0400
#define controlED 1
#define RELEASED 0
/* Protocol module private data */
struct private_data {
int flags; /* see valid values before */
int nDev; /* USB device number */
int state;
void * hid_module_handle; /* HID module_handle */
};
/* forward declarations */
static int control_init(input_module_t *module);
static int control_devctrl(input_module_t *module, int event, void *ptr);
static int control_reset(input_module_t *module);
static int control_input(input_module_t *module, int num, void *arg);
static int control_parm(input_module_t *module, int opt, char *optarg);
static int control_shutdown(input_module_t *module, int delay);
/* Our protocol module is represented by the following input_module_t data structure */
input_module_t control = {
NULL,
NULL,
NULL,
0,
DEVI_CLASS_CONTROL | DEVI_MODULE_TYPE_PROTO | DEVI_MODULE_TYPE_DEVICE,
"control",
__DATE__,
"Ku:",
NULL,
control_init,
control_reset,
control_input,
NULL,
NULL,
control_parm,
control_devctrl,
control_shutdown
};
/* Description: callback initialisation function; it is called when input module is */
/* initialising the input system */
/* Input : input_module_t * module - pointer to module descriptor */
/* Output : None */
/* Return : 0 if OK, otherwise - (-1) */
int control_init(input_module_t *module)
{
struct private_data *dp = module->data;
if(!module->data)
{
if(!(dp = module->data = _scalloc(sizeof *dp)))
{
return (-1);
}
}
dp -> nDev = HIDD_CONNECT_WILDCARD;
dp->state = RELEASED;
return (0);
}
/* Description: this is a callback function for DEVCTRL command processing */
/* Input : input_module_t * module - pointer to module descriptor */
/* int event - DEVCTRL command code */
/* void * ptr - pointer to data exchange block */
/* Output : None */
/* Return : 0 if OK, otherwise -1 */
int control_devctrl(input_module_t *module, int event, void *ptr)
{
struct private_data *dp = module->data;
int rc = 0;
switch(event)
{
case DEVCTL_GETDEVFLAGS:
*(unsigned short *)ptr = (dp->flags & FLAGS_GLOBAL);
break;
case DEVCTL_GETPTRBTNS:
*(unsigned long *)ptr = 5L;
break;
case DEVCTL_GETPTRCOORD:
*(unsigned char *)ptr='\02';
break;
default:
rc = devi_hid_devctrl(dp -> hid_module_handle, event, ptr, HIDD_CONNECT_WILDCARD );
break;
}
return (rc);
}
/* Description: this callback funtion is called when the module is linked into the */
/* event bus;it is used to set initial module state on the protocol */
/* level */
/* Input : input_module_t * module - pointer to module descriptor */
/* Output : None */
/* Return : 0 if OK, otherwise -1 */
int control_reset(input_module_t *module)
{
struct private_data *dp = module->data;
if(!(dp->flags & FLAG_INIT))
{
if(NULL == (dp -> hid_module_handle = devi_hid_register_client(module, dp -> nDev)))
return (-1);
}
dp->flags |= FLAG_INIT;
return (0);
}
/* Description: main protocol processing function. It will be called by the */
/* device layer to pass it data to process. Its job is to interpret */
/* the data according to the MS wheel control protocol, create a */
/* data structure, fill it in and hand it off to the filter layer */
/* module above it. The protocol is processed using simple state */
/* machine. State info is kept in module's private data */
/* Input : input_module_t * module - pointer to module descriptor */
/* int num - number of bytes to process */
/* void * arg - raw data to process */
/* Output : None */
/* Return : 0 if OK, otherwise -1 */
/* Comment : driver uses one of two input modules depending on device data */
/* protocol */
int control_input(input_module_t *module, int num, void *arg)
{
pControl_raw_data_t control_raw_data = (pControl_raw_data_t)arg;
struct packet_control mp;
struct private_data *dp = module->data;
input_module_t *up = module->up;
assert(num == sizeof(control_raw_data_t)); // Desynchronized exchange format
if(dp->flags & FLAG_INIT)
{
mp.Rx = control_raw_data->Rx;
mp.Ry = control_raw_data->Ry;
mp.Rz = control_raw_data->Rz;
mp.button_state = control_raw_data->button_state;
}
if (verbosity > 1)
fprintf (stderr, "Device Module Level: Rx:%d, Ry:%d, Rz:%d, Buttons %x\n", mp.Rx, mp.Ry, mp.Rz, mp.button_state);
(up->input)(up, 1, &mp);
return (0);
}
/* Description: this is a callback function for command line parameter processing */
/* (all valid parameters for device module are listed in control.args) */
/* Input : input_module_t * module - pointer to module descriptor */
/* int opt - parameter code */
/* char * optarg - optional parameter value */
/* Output : None */
/* Return : 0 if OK, otherwise -1 */
/* Comment : we don't accept any parameter for this module at the protocol level */
int control_parm(input_module_t *module, int opt, char *optarg)
{
/* Now empty */
struct private_data *dp = module->data;
switch (opt)
{
case 'u':
{
if(NULL != optarg)
dp->nDev = atoi(optarg);
break;
}
case 'K':
{
dp->flags |= FLAG_KIOSK_MODE;
break;
}
default:
break;
}
return (0);
}
/* Description: this is a callback function which is called when resourse manager */
/* is shutting down */
/* Input : input_module_t * module - pointer to module descriptor */
/* int ms - program doesn't use this parameter */
/* Output : None */
/* Return : 0 if OK, otherwise -1 */
/* Comment : Does nothing for the protocol level */
int control_shutdown(input_module_t *module, int delay)
{
struct private_data *dp = module->data;
if( (NULL != dp) && (NULL != dp -> hid_module_handle))
devi_unregister_hid_client(dp -> hid_module_handle);
return (0);
}

104
devi/hid/devi-hid.use Normal file
View File

@ -0,0 +1,104 @@
%C [general_opts] protocol* [protocol_opts]* filter* [filter_opts]*
%C : HID input manager
This driver doesn't care about physical interfaces of real devices.
It just relies on io-hid resource manager and supplementary input
modules service.
(!!!) Do not use this source code to modify default devi-hid driver.
General opts:
-b prevent CASB exit (default allow CASB)
-d photon device (default /dev/photon | PHOTON env var)
-g input group (default 1)
-l list List the internal modules. Modules are listed in
the following format:
module name | date last compiled | revision | class
where: class is comprised of (P)rotocol and/or (F)ilter
-P disable photon interface (default start Photon interface)
-r start resource manager interface (only use if not using Photon)
-v increment verbosity (default 0)
protocol modules and their options:
kbd HID compliant keyboard
-k rate[,delay] Keyboard rate(Hz)/delay(ms) (default 150Hz, 500ms)
-u device optional: USB device number
mouse HID compliant mouse
touch HID compliant touch screen
-K Kiosk Mode (cursor does not drag).
-m size Touchscreen Matrix size (default 1023). This is used for
calculated transformation points.
-u device optional: USB device number
filter modules and their options:
keyboard Translate scan codes to UNICODE
-k kbd_file File to use for keyboard mapping
-L [N][C][S]
Set the initial state of the keyboard and its LEDs (default all off):
- C turn CapsLock on.
- N turn NumLock on.
- S turn ScrollLock on.
rel Filters and compresses relative coordinate "mouse" events
-a wheel acceleration parameter (default 10); the more this
value, the more mouse wheel acceleration effect
-G gain Motion multiplier (default 1)
-l Swap right and left buttons around
-T threshold Speed doubling threshold in mickeys (100)
-x Reverse X
-y Reverse Y
abs Transform and compresses absolute coordinate "touch" events
-a {3/4} Transformation algorithm, available algorithms 3 point and
4 point (default 3 point).
-b Touching the screen is a right mouse button (default left)
-c Calibrate mode - don't transform coordinates
-f filename Calibration file name
(default /etc/system/config/calib.{hostname}).
Note: If You want use vmware mouse, your calibration file need
has size 0
-o x,y Origin of display region (default, origin of graphics region)
-s x,y Coordinates of lower right corner of display region
(default, width and height of graphics region)
-x Reverse X
-y Reverse Y
-D pixels Differential filter that will filter out packets that are
within a number of pixels of the last touch. This prevents
sending repeat coordinates.
-N pixels Noise filter that will filter out packets that are outside
the max number of pixels. This filters out jittery events
from some touchscreens.
-S ms Soft Button release, emulates a release event after X ms of
inactivity from the touch controller. This is helpful for
screens that are not very sensitive, so every event received
before X number of ms expire is treated as a pen down event.
-O origin Touch screen origin (0,0). This is used for the calibration
free transformation. If no calibration file is specified
the driver will attempt to calculate the X,Y position based
on screen resolution and touch screen matrix size (if known).
Possible values are:
Upper Left = 0
Lower Left = 1
Lower Right = 2
Upper Right = 3
Example:
-------
%C kbd mouse
Start the HID driver with a keyboard and mouse
%C kbd touch abs -a4
Start the HID driver keyboard and touchscreen and tell the touchscreen to use the
older, four point calibration algorithm.

257
devi/hid/joystick.c Normal file
View File

@ -0,0 +1,257 @@
/*
* (c) 2010, SWD Embedded Systems Limited, http://www.kpda.ru
*/
/*
* Предостережение:
*
* Предоставленный исходный код драйвера devi-hid рекомендуется использовать
* только для отладочных целей при разработке HID-драйверов. Для всех остальных
* задач следует использовать штатный системный драйвер devi-hid.
*
* В общем случае не существует задач, которые требуется решать в этом драйвере
* при поддержке нового оборудования (для этого должен быть написан/модифицирован
* отдельный драйвер ввода или HID-драйвер).
*/
/*
* joystick.c
*
* The HID USB joystick combined device/protocol module.
*
*/
#include <sys/devi.h>
#include "hid.h"
#include <assert.h>
#define FLAG_INIT 0x0100
#define FLAG_RESET 0x0200
#define FLAG_KIOSK_MODE 0x0400
#define joystickED 1
#define RELEASED 0
/* Protocol module private data */
struct private_data {
int flags; /* see valid values before */
int nDev; /* USB device number */
int state;
void * hid_module_handle; /* HID module_handle */
};
/* forward declarations */
static int joystick_init(input_module_t *module);
static int joystick_devctrl(input_module_t *module, int event, void *ptr);
static int joystick_reset(input_module_t *module);
static int joystick_input(input_module_t *module, int num, void *arg);
static int joystick_parm(input_module_t *module, int opt, char *optarg);
static int joystick_shutdown(input_module_t *module, int delay);
/* Our protocol module is represented by the following input_module_t data structure */
input_module_t joystick = {
NULL,
NULL,
NULL,
0,
DEVI_CLASS_JOYSTICK | DEVI_MODULE_TYPE_PROTO | DEVI_MODULE_TYPE_DEVICE,
"joystick",
__DATE__,
"u:",
NULL,
joystick_init,
joystick_reset,
joystick_input,
NULL,
NULL,
joystick_parm,
joystick_devctrl,
joystick_shutdown
};
/* Description: callback initialisation function; it is called when input module is */
/* initialising the input system */
/* Input : input_module_t * module - pointer to module descriptor */
/* Output : None */
/* Return : 0 if OK, otherwise - (-1) */
int joystick_init(input_module_t *module)
{
struct private_data *dp = module->data;
if(!module->data)
{
if(!(dp = module->data = _scalloc(sizeof *dp)))
{
return (-1);
}
}
dp -> nDev = HIDD_CONNECT_WILDCARD;
dp->state = RELEASED;
return (0);
}
/* Description: this is a callback function for DEVCTRL command processing */
/* Input : input_module_t * module - pointer to module descriptor */
/* int event - DEVCTRL command code */
/* void * ptr - pointer to data exchange block */
/* Output : None */
/* Return : 0 if OK, otherwise -1 */
int joystick_devctrl(input_module_t *module, int event, void *ptr)
{
struct private_data *dp = module->data;
int rc = 0;
switch(event)
{
case DEVCTL_GETDEVFLAGS