Драйвер devh-egalax для ЗОСРВ "Нейтрино" редакции 2020
This commit is contained in:
commit
13333b0126
93
README.md
Normal file
93
README.md
Normal file
@ -0,0 +1,93 @@
|
||||
## Общая структура USB-стека
|
||||
|
||||
```
|
||||
┌─────────────────────────────┐ ┌─────────────────────────────┐
|
||||
│ │ │ │
|
||||
│ Контроллер USB шины ◂────*────▸ USB устройство │
|
||||
│ │ │ │
|
||||
└──────────────▴──────────────┘ └─────────────────────────────┘
|
||||
│
|
||||
┌──────────────┴──────────────┐
|
||||
│ │
|
||||
│ Драйвер контроллера │
|
||||
│ USB шины (devu-*hci.so) │
|
||||
│ │
|
||||
└──────────────▴──────────────┘
|
||||
│
|
||||
*
|
||||
│
|
||||
┌──────────────┴──────────────┐ ┌───────────────────────────┐
|
||||
│ │ │ │
|
||||
│ Менеджер USB-стека (io-usb) ◂─── * ───┤ USB драйвер (devu-*) ◂───▸ /dev/usb***X
|
||||
│ │ │ │ ▴
|
||||
└─────────────────────────────┘ ▲ └───────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────▾─────────────┐
|
||||
Интерфейс libusbdi ───────┘ │ │
|
||||
│ Клиентское приложение │
|
||||
│ │
|
||||
└───────────────────────────┘
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Дерево исходных кодов
|
||||
|
||||
```
|
||||
|- devu/
|
||||
| |- keyboard/ - Исходный код драйвера поддержки USB-клавиатур
|
||||
| |- mouse/ - Исходный код драйвера USB-мыши
|
||||
| |- printer/ - Исходный код драйвера класса для USB-принтеров
|
||||
| |- 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
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Запуск драйвера
|
||||
|
||||
Общая схема запуска драйвера (не относится к драйверам контроллеров USB шин):
|
||||
|
||||
```
|
||||
devu-* <опции_драйвера> &
|
||||
```
|
||||
|
||||
Примеры:
|
||||
|
||||
```
|
||||
devu-kbd -n /dev/usbkbd0 &
|
||||
└───┬───┘ └───────┬───────┘
|
||||
│ │
|
||||
│ Опции
|
||||
Драйвер
|
||||
|
||||
|
||||
|
||||
devu-mouse -n /dev/usbmouse0 -vvvv &
|
||||
└────┬────┘ └───────────┬───────────┘
|
||||
│ │
|
||||
│ Опции
|
||||
Драйвер
|
||||
|
||||
|
||||
|
||||
devu-prn -n /dev/usbpar0 -s /dev/io-usb/io-usb &
|
||||
└───┬───┘ └──────────────────┬──────────────────┘
|
||||
│ │
|
||||
│ Опции
|
||||
Драйвер
|
||||
```
|
||||
|
2
devu/Makefile
Normal file
2
devu/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
LIST=USB
|
||||
include recurse.mk
|
2
devu/class/Makefile
Normal file
2
devu/class/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
LIST=CLASS
|
||||
include recurse.mk
|
53
devu/class/common.mk
Normal file
53
devu/class/common.mk
Normal file
@ -0,0 +1,53 @@
|
||||
#
|
||||
# (c) 2010-2019, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
#
|
||||
|
||||
ifndef QCONFIG
|
||||
QCONFIG=qconfig.mk
|
||||
endif
|
||||
include $(QCONFIG)
|
||||
|
||||
LIB_VARIANT = $(patsubst so.,so,$(subst $(space),.,so $(filter wcc be le amanda,$(VARIANTS))))
|
||||
BOARD_VARIANT = $(patsubst amanda,-amanda,$(subst $(space),,$(filter wcc amanda,$(VARIANTS))))
|
||||
|
||||
EXTRA_CCDEPS = $(wildcard $(PROJECT_ROOT)/*.h $(SECTION_ROOT)/*.h $(PRODUCT_ROOT)/usbdi/public/sys/*.h $(PRODUCT_ROOT)/usbdi/internals.h )
|
||||
EXTRA_INCVPATH = $(PRODUCT_ROOT)/devu $(PRODUCT_ROOT)/usbdi/public $(PRODUCT_ROOT)/include $(PRODUCT_ROOT)/usbdi $(PRODUCT_ROOT)/hcd
|
||||
EXTRA_LIBVPATH += $(PRODUCT_ROOT)/usbdi/$(CPU)/$(LIB_VARIANT)
|
||||
|
||||
define PINFO
|
||||
PINFO DESCRIPTION=
|
||||
endef
|
||||
|
||||
include $(MKFILES_ROOT)/qmacros.mk
|
||||
|
||||
TYPE = $(firstword $(filter a o, $(VARIANTS)) o)
|
||||
|
||||
USEFILE_o = $(SECTION_ROOT)/devu-$(SECTION).use
|
||||
USEFILE_a =
|
||||
USEFILE = $(USEFILE_$(TYPE))
|
||||
|
||||
INSTALLDIR_a = lib
|
||||
INSTALLDIR_o = sbin
|
||||
INSTALLDIR = $(INSTALLDIR_$(TYPE))
|
||||
|
||||
NAME_o = devu-$(SECTION)
|
||||
EXTRA_SILENT_VARIANTS+=$(VARIANT3)
|
||||
NAME_a = $(SECTION)
|
||||
EXTRA_SILENT_VARIANTS+=$(VARIANT3)
|
||||
NAME = $(NAME_$(TYPE))
|
||||
EXTRA_SILENT_VARIANTS+=$(VARIANT3)
|
||||
|
||||
LIBS_o = usbdi$(BOARD_VARIANT)
|
||||
LIBS_a =
|
||||
LIBS = $(LIBS_$(TYPE))
|
||||
|
||||
CCFLAGS_o =
|
||||
CCFLAGS_a = -Dmain=main_$(SECTION)
|
||||
CCFLAGS += $(CCFLAGS_$(TYPE))
|
||||
CCFLAGS_e2k += -fkernel
|
||||
CCFLAGS += $(CCFLAGS_$(CPU))
|
||||
|
||||
-include $(SECTION_ROOT)/override.mk
|
||||
|
||||
include $(MKFILES_ROOT)/qtargets.mk
|
||||
-include $(SECTION_ROOT)/pinfo.mk
|
2
devu/class/keyboard/Makefile
Normal file
2
devu/class/keyboard/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
LIST=CPU
|
||||
include recurse.mk
|
2
devu/class/keyboard/arm/Makefile
Normal file
2
devu/class/keyboard/arm/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/keyboard/arm/le.v7/Makefile
Normal file
1
devu/class/keyboard/arm/le.v7/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/keyboard/arm/le/Makefile
Normal file
1
devu/class/keyboard/arm/le/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
197
devu/class/keyboard/buffer.c
Normal file
197
devu/class/keyboard/buffer.c
Normal file
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* (c) 2010, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define MAX_BUFF_BYTES 1024
|
||||
typedef struct buffer buffer_t;
|
||||
|
||||
#define BUFF_OVERWRITE 0x01
|
||||
struct buffer {
|
||||
int head;
|
||||
int tail;
|
||||
int bufsize;
|
||||
int recsize;
|
||||
char *ptr;
|
||||
unsigned mode;
|
||||
int min;
|
||||
};
|
||||
|
||||
extern buffer_t *buff_create( unsigned mode, unsigned size, unsigned rsize );
|
||||
extern int buff_destroy( buffer_t *bptr );
|
||||
extern int buff_append( buffer_t *bptr, char *dptr, int n );
|
||||
extern int buff_delete( buffer_t *bptr, char *dptr, int n );
|
||||
extern int buff_flush( buffer_t *bptr );
|
||||
extern int buff_putc( buffer_t *bptr, char c );
|
||||
extern int buff_getc( buffer_t *bptr );
|
||||
extern int buff_waiting( buffer_t *bptr );
|
||||
|
||||
int buff_destroy( buffer_t *bptr )
|
||||
{
|
||||
free( bptr->ptr );
|
||||
free( bptr );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
buffer_t *buff_create( unsigned mode, unsigned size, unsigned rsize )
|
||||
{
|
||||
struct buffer *cbptr;
|
||||
|
||||
if( cbptr = calloc( sizeof( *cbptr ), 1 ) ) {
|
||||
cbptr->recsize = rsize ? rsize : ( rsize = 1 );
|
||||
cbptr->bufsize = size ? size * rsize : MAX_BUFF_BYTES - ( MAX_BUFF_BYTES % rsize );
|
||||
if( cbptr->ptr = calloc( cbptr->bufsize, 1 ) ) {
|
||||
cbptr->mode = mode;
|
||||
}
|
||||
else {
|
||||
free( cbptr );
|
||||
cbptr = 0;
|
||||
}
|
||||
}
|
||||
return( cbptr );
|
||||
}
|
||||
|
||||
int buff_append( buffer_t *bptr, char *dptr, int n )
|
||||
{
|
||||
int t;
|
||||
|
||||
pthread_sleepon_lock( );
|
||||
n *= bptr->recsize;
|
||||
if( ( t = bptr->tail - bptr->head ) <= 0 ) {
|
||||
t += bptr->bufsize; // calc free size
|
||||
}
|
||||
if( t <= n ) {
|
||||
if( bptr->mode & BUFF_OVERWRITE ) {
|
||||
bptr->tail += ( n - t );
|
||||
if( bptr->tail >= bptr->bufsize ) {
|
||||
bptr->tail = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
n = t;
|
||||
}
|
||||
}
|
||||
while( n ) {
|
||||
t = min( n, bptr->bufsize - bptr->head );
|
||||
if( t ) {
|
||||
memcpy( bptr->ptr + bptr->head, dptr, t );
|
||||
bptr->head += t;
|
||||
if( bptr->head >= bptr->bufsize ) {
|
||||
bptr->head = 0;
|
||||
}
|
||||
dptr += t;
|
||||
n -= t;
|
||||
}
|
||||
}
|
||||
if( ( t = bptr->head - bptr->tail ) < 0 ) {
|
||||
t += bptr->bufsize;
|
||||
}
|
||||
pthread_sleepon_unlock( );
|
||||
return( t );
|
||||
}
|
||||
|
||||
int buff_delete( buffer_t *bptr, char *dptr, int n )
|
||||
{
|
||||
int t, v = 0;
|
||||
|
||||
pthread_sleepon_lock( );
|
||||
n *= bptr->recsize;
|
||||
if( ( t = bptr->head - bptr->tail ) < 0 ) {
|
||||
t += bptr->bufsize;
|
||||
}
|
||||
if( n > t ) {
|
||||
n = t;
|
||||
}
|
||||
while( n ) {
|
||||
t = min( n, max( 0, bptr->bufsize - bptr->tail ) );
|
||||
if( t ) {
|
||||
memcpy( dptr, bptr->ptr + bptr->tail, t );
|
||||
bptr->tail += t;
|
||||
if( bptr->tail >= bptr->bufsize ) {
|
||||
bptr->tail = 0;
|
||||
}
|
||||
dptr += t;
|
||||
n -= t;
|
||||
v += t;
|
||||
}
|
||||
else {
|
||||
n = 0;
|
||||
}
|
||||
}
|
||||
pthread_sleepon_unlock( );
|
||||
return( v );
|
||||
}
|
||||
|
||||
int buff_flush( buffer_t *bptr )
|
||||
{
|
||||
pthread_sleepon_lock( );
|
||||
bptr->tail = bptr->head;
|
||||
pthread_sleepon_unlock( );
|
||||
if( bptr->min < 0 ) {
|
||||
bptr->min = 1;
|
||||
}
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int buff_putc( buffer_t *bptr, char c )
|
||||
{
|
||||
int t;
|
||||
|
||||
pthread_sleepon_lock( );
|
||||
if( bptr->recsize > 1 ) {
|
||||
pthread_sleepon_unlock( );
|
||||
return( -1 );
|
||||
}
|
||||
if( ( t = bptr->tail - bptr->head ) <= 0 ) {
|
||||
t += bptr->bufsize; // calc free size
|
||||
}
|
||||
if( t <= 1 ) {
|
||||
if( bptr->mode & BUFF_OVERWRITE ) {
|
||||
if( ++bptr->tail >= bptr->bufsize ) {
|
||||
bptr->tail = 0;
|
||||
}
|
||||
t++;
|
||||
}
|
||||
}
|
||||
if( t ) {
|
||||
t--;
|
||||
bptr->ptr[bptr->head++] = c;
|
||||
if( bptr->head >= bptr->bufsize ) {
|
||||
bptr->head = 0;
|
||||
}
|
||||
}
|
||||
pthread_sleepon_unlock( );
|
||||
return( bptr->bufsize - t );
|
||||
}
|
||||
|
||||
int buff_getc( buffer_t *bptr )
|
||||
{
|
||||
int c;
|
||||
|
||||
pthread_sleepon_lock( );
|
||||
if( bptr->recsize > 1 || bptr->head == bptr->tail ) {
|
||||
pthread_sleepon_unlock( );
|
||||
return( -1 );
|
||||
}
|
||||
c = bptr->ptr[bptr->tail];
|
||||
if( ++bptr->tail >= bptr->bufsize ) {
|
||||
bptr->tail = 0;
|
||||
}
|
||||
pthread_sleepon_unlock( );
|
||||
return( c );
|
||||
}
|
||||
|
||||
int buff_waiting( buffer_t *bptr )
|
||||
{
|
||||
int t;
|
||||
|
||||
// pthread_sleepon_lock( );
|
||||
if( ( t = bptr->head - bptr->tail ) < 0 ) {
|
||||
t += bptr->bufsize;
|
||||
}
|
||||
// pthread_sleepon_unlock( );
|
||||
return( t / bptr->recsize );
|
||||
}
|
13
devu/class/keyboard/devu-kbd.use
Normal file
13
devu/class/keyboard/devu-kbd.use
Normal file
@ -0,0 +1,13 @@
|
||||
%C Class Driver for USB keyboards (BOOT mode HID).
|
||||
|
||||
Syntax:
|
||||
devu-kbd [options*] &
|
||||
|
||||
Options:
|
||||
-n name Set device name. default "/dev/usbkbd0"
|
||||
-v Be verbose.
|
||||
-w sec Wait 'sec' seconds for USB stack (default 60 seconds).
|
||||
-s stack Name of stack to attach to (default /dev/usb).
|
||||
|
||||
Examples:
|
||||
devu-kbd &
|
2
devu/class/keyboard/e2k/Makefile
Normal file
2
devu/class/keyboard/e2k/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/keyboard/e2k/le/Makefile
Normal file
1
devu/class/keyboard/e2k/le/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
806
devu/class/keyboard/keyb.c
Normal file
806
devu/class/keyboard/keyb.c
Normal file
@ -0,0 +1,806 @@
|
||||
/*
|
||||
* (c) 2010-2019, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
*/
|
||||
|
||||
// Portions Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This code is derived from software contributed to The NetBSD Foundation
|
||||
// by Lennart Augustsson (lennart@augustsson.net) at
|
||||
// Carlstedt Research & Technology.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// 3. All advertising materials mentioning features or use of this software
|
||||
// must display the following acknowledgement:
|
||||
// This product includes software developed by the NetBSD
|
||||
// Foundation, Inc. and its contributors.
|
||||
// 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Module Description: keyboard class driver
|
||||
|
||||
#include <keyb.h>
|
||||
|
||||
keyb_ctrl_t KeybCtrl;
|
||||
|
||||
int keyb_free( keyb_t *keyb )
|
||||
{
|
||||
int status;
|
||||
|
||||
keyb->status &= ~( KEYBOARD_PRESENT | KEYBOARD_IN_USE );
|
||||
if( keyb->ep_int ) { // Stop the Interrupt In endpoint
|
||||
usbd_abort_pipe( keyb->ep_int );
|
||||
}
|
||||
|
||||
pthread_sleepon_lock( );
|
||||
pthread_sleepon_signal( keyb->rbuf );
|
||||
pthread_sleepon_unlock( );
|
||||
|
||||
if( status = rsrcdbmgr_devno_detach( keyb->attr.rdev, 0 ) ) {
|
||||
fprintf( stderr, "keyb_free: rsrcddbmgr_devno_detach %d\n", errno );
|
||||
}
|
||||
if( status = resmgr_detach( KeybCtrl.dispatch, keyb->resmgr_id, _RESMGR_DETACH_ALL | _RESMGR_DETACH_CLOSE ) ) {
|
||||
fprintf( stderr, "keyb_free: resmgr_detach %d\n", status );
|
||||
}
|
||||
usbd_free_urb( keyb->urb );
|
||||
usbd_free( keyb->ks_ndata );
|
||||
usbd_free( keyb->ks_odata );
|
||||
buff_destroy( keyb->rbuf );
|
||||
TAILQ_REMOVE( &KeybCtrl.dlist, keyb, dlink );
|
||||
if( status = usbd_detach( keyb->device ) ) {
|
||||
fprintf( stderr, "keyb_free: usbd_detach %x\n", status );
|
||||
}
|
||||
return( status );
|
||||
}
|
||||
|
||||
void keyb_signal_handler( )
|
||||
{
|
||||
siginfo_t info;
|
||||
sigset_t set;
|
||||
keyb_t *keyb;
|
||||
keyb_t *nkeyb;
|
||||
|
||||
sigfillset( &set );
|
||||
sigdelset( &set, SIGTERM );
|
||||
sigprocmask( SIG_BLOCK, &set, NULL );
|
||||
|
||||
sigemptyset( &set );
|
||||
sigaddset( &set, SIGTERM );
|
||||
while( SignalWaitinfo( &set, &info ) == -1 )
|
||||
;
|
||||
|
||||
for( keyb = TAILQ_FIRST( &KeybCtrl.dlist ); keyb; keyb = nkeyb ) {
|
||||
nkeyb = TAILQ_NEXT( keyb, dlink );
|
||||
keyb_free( keyb );
|
||||
}
|
||||
}
|
||||
|
||||
int keyb_process_keys( keyb_t *keyb )
|
||||
{
|
||||
keyb_report_t *nd;
|
||||
keyb_report_t *od;
|
||||
struct timespec tv;
|
||||
_uint32 now;
|
||||
int mod, omod;
|
||||
_uint16 ibuf[MAXKEYS]; // char events
|
||||
int nkeys, i, j;
|
||||
int key;
|
||||
#define ADDKEY(c) ibuf[nkeys++] = (c)
|
||||
|
||||
nd = (keyb_report_t *)keyb->ks_ndata;
|
||||
od = (keyb_report_t *)keyb->ks_odata;
|
||||
|
||||
if( nd->keycode[0] == KEY_ERROR ) {
|
||||
return( EOK ); // ignore
|
||||
}
|
||||
|
||||
clock_gettime( CLOCK_REALTIME, &tv );
|
||||
now = (_uint32)tv.tv_sec * 1000 + (_uint32)tv.tv_nsec / 1000000;
|
||||
|
||||
nkeys = 0;
|
||||
mod = nd->modifiers;
|
||||
omod = od->modifiers;
|
||||
if( mod != omod ) {
|
||||
for (i = 0; i < NMOD; i++) {
|
||||
if (( mod & ukbd_mods[i].mask) != (omod & ukbd_mods[i].mask ) ) {
|
||||
ADDKEY( ukbd_mods[i].key | ( mod & ukbd_mods[i].mask ? PRESS : RELEASE ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
if( memcmp( nd->keycode, od->keycode, NKEYCODE) != 0 ) {
|
||||
// Check for released keys
|
||||
for( i = 0; i < NKEYCODE; i++) {
|
||||
key = od->keycode[i];
|
||||
if( key == 0 ) {
|
||||
continue;
|
||||
}
|
||||
for( j = 0; j < NKEYCODE; j++ ) {
|
||||
if( key == nd->keycode[j] ) {
|
||||
goto rfound;
|
||||
}
|
||||
}
|
||||
ADDKEY( key | RELEASE );
|
||||
rfound:
|
||||
;
|
||||
}
|
||||
|
||||
/* Check for pressed keys. */
|
||||
for( i = 0; i < NKEYCODE; i++ ) {
|
||||
key = nd->keycode[i];
|
||||
if( key == 0 ) {
|
||||
continue;
|
||||
}
|
||||
for( j = 0; j < NKEYCODE; j++ ) {
|
||||
if( key == od->keycode[j] ) {
|
||||
goto pfound;
|
||||
}
|
||||
}
|
||||
ADDKEY( key | PRESS );
|
||||
pfound:
|
||||
;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( keyb->ks_nrep && now > keyb->ks_ntime ) {
|
||||
// buff_append( keyb->rbuf, keyb->ks_rep, 1 );
|
||||
buff_append( keyb->rbuf, keyb->ks_rep, keyb->ks_nrep );
|
||||
keyb->ks_ntime = now + 10;
|
||||
|
||||
// wakeup anyone blocked
|
||||
pthread_sleepon_lock( );
|
||||
pthread_sleepon_signal( keyb->rbuf );
|
||||
pthread_sleepon_unlock( );
|
||||
return( EOK );
|
||||
}
|
||||
}
|
||||
|
||||
*od = *nd;
|
||||
|
||||
if( nkeys == 0 ) {
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
if( 1 ) {
|
||||
char cbuf[MAXKEYS * 2];
|
||||
int c;
|
||||
int npress;
|
||||
|
||||
for( npress = i = j = 0; i < nkeys; i++ ) {
|
||||
key = ibuf[i];
|
||||
c = ukbd_trtab[key & CODEMASK];
|
||||
if( c == NN ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// special case control break/pause
|
||||
if( c == 0x7f ) {
|
||||
if( ( mod & ( MOD_CONTROL_L | MOD_CONTROL_R ) ) ) {
|
||||
cbuf[j++] = 0xe0, cbuf[j++] = 0x46;
|
||||
cbuf[j++] = 0xe0, cbuf[j++] = 0xc6;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
cbuf[j++] = 0xe1, cbuf[j++] = 0x1d, cbuf[j++] = 0x45;
|
||||
cbuf[j++] = 0xe1, cbuf[j++] = 0x9d, cbuf[j++] = 0xc5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( c & 0x80 ) {
|
||||
cbuf[j++] = 0xe0;
|
||||
}
|
||||
cbuf[j] = c & 0x7f;
|
||||
if( key & RELEASE ) {
|
||||
cbuf[j] |= 0x80;
|
||||
}
|
||||
else {
|
||||
// remember pressed keys for autorepeat
|
||||
if( c & 0x80 ) {
|
||||
keyb->ks_rep[npress++] = 0xe0;
|
||||
}
|
||||
keyb->ks_rep[npress++] = c & 0x7f;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
buff_append( keyb->rbuf, cbuf, j );
|
||||
if( npress != 0 ) {
|
||||
keyb->ks_nrep = npress;
|
||||
keyb->ks_ntime = now + 200;
|
||||
}
|
||||
else {
|
||||
keyb->ks_nrep = 0;
|
||||
}
|
||||
|
||||
// wakeup anyone blocked
|
||||
pthread_sleepon_lock( );
|
||||
pthread_sleepon_signal( keyb->rbuf );
|
||||
pthread_sleepon_unlock( );
|
||||
}
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
void keyb_int_cbf( struct usbd_urb *urb, struct usbd_pipe *pipe, void *hdl )
|
||||
{
|
||||
keyb_t *keyb;
|
||||
_uint32 ustatus;
|
||||
_uint32 alen;
|
||||
|
||||
keyb = (keyb_t *)hdl;
|
||||
usbd_urb_status( urb, &ustatus, &alen );
|
||||
|
||||
if( ( ustatus & USBD_URB_STATUS_MASK ) != USBD_STATUS_CMP ) {
|
||||
// check for a stall condition and clear it
|
||||
if( ( ustatus & USBD_USB_STATUS_MASK ) == USBD_STATUS_STALL ) {
|
||||
usbd_reset_pipe( pipe );
|
||||
}
|
||||
if( KeybCtrl.verbose ) {
|
||||
fprintf( stderr, "keyb_int_cbf: ustatus %x\n", ustatus );
|
||||
}
|
||||
}
|
||||
else {
|
||||
keyb_process_keys( keyb );
|
||||
}
|
||||
|
||||
if( keyb->status & KEYBOARD_IN_USE ) { // re-hook interrupt endpoint
|
||||
usbd_setup_interrupt( keyb->urb, URB_DIR_IN, keyb->ks_ndata, keyb->ep_int_size );
|
||||
if( usbd_io( keyb->urb, keyb->ep_int, keyb_int_cbf, keyb, USBD_TIME_INFINITY ) ) {
|
||||
keyb->status &= ~( KEYBOARD_IN_USE | KEYBOARD_PRESENT );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int keyb_set_idle( keyb_t *keyb )
|
||||
{
|
||||
_uint32 status;
|
||||
struct usbd_urb *urb;
|
||||
_uint8 *buffer;
|
||||
int retry=3;
|
||||
|
||||
status = ENOMEM;
|
||||
|
||||
if( !(urb = usbd_alloc_urb( NULL ) ) )
|
||||
return( status );
|
||||
if ( (buffer = usbd_alloc( 1 ) ) ) {
|
||||
while ( retry-- ) {
|
||||
usbd_setup_vendor( urb, URB_DIR_OUT, 10, USB_TYPE_CLASS | USB_RECIPIENT_INTERFACE, 8 << 8, 0, NULL, 0 );
|
||||
if( ( status = usbd_io( urb, keyb->ep_cntl, NULL, keyb, USBD_TIME_INFINITY ) ) == EOK ) {
|
||||
// get idle and make sure it was set.. fix for IBM Sillitek keayboard
|
||||
usbd_setup_vendor( urb, URB_DIR_IN, 2, USB_TYPE_CLASS | USB_RECIPIENT_INTERFACE, 0, 0, buffer, 1 );
|
||||
if( ( ( status = usbd_io( urb, keyb->ep_cntl, NULL, keyb, USBD_TIME_INFINITY ) ) == EOK ) && (*buffer != 0) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
usbd_free( buffer );
|
||||
}
|
||||
|
||||
usbd_free_urb( urb );
|
||||
|
||||
return( status );
|
||||
}
|
||||
|
||||
int keyb_set_report( keyb_t *keyb, _uint32 lchng )
|
||||
{
|
||||
_uint32 status;
|
||||
struct usbd_urb *urb;
|
||||
_uint8 *buffer;
|
||||
|
||||
status = ENOMEM;
|
||||
if( urb = usbd_alloc_urb( NULL ) ) {
|
||||
if( buffer = usbd_alloc( 1 ) ) {
|
||||
*buffer = lchng;
|
||||
usbd_setup_vendor( urb, URB_DIR_OUT, HID_SET_REPORT, USB_TYPE_CLASS | USB_RECIPIENT_INTERFACE, HID_REPORT_OUT, keyb->instance.iface, buffer, 1 );
|
||||
if( ( status = usbd_io( urb, keyb->ep_cntl, NULL, keyb, USBD_TIME_INFINITY ) ) == EOK ) {
|
||||
keyb->leds = *buffer;
|
||||
}
|
||||
usbd_free_urb( urb );
|
||||
}
|
||||
usbd_free( buffer );
|
||||
}
|
||||
|
||||
return( status );
|
||||
}
|
||||
|
||||
int keyb_io_unblock( resmgr_context_t *ctp, io_pulse_t *msg, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
keyb_t *keyb;
|
||||
|
||||
keyb = (keyb_t *)ocb->attr;
|
||||
|
||||
pthread_sleepon_lock( );
|
||||
keyb->status |= KEYBOARD_UNBLOCK;
|
||||
pthread_sleepon_signal( keyb->rbuf );
|
||||
pthread_sleepon_unlock( );
|
||||
|
||||
return( _RESMGR_NOREPLY );
|
||||
}
|
||||
|
||||
int keyb_io_open( resmgr_context_t *ctp, io_open_t *msg, RESMGR_HANDLE_T *handle, void *extra )
|
||||
{
|
||||
keyb_t *keyb;
|
||||
int status;
|
||||
|
||||
keyb = (keyb_t *)handle;
|
||||
|
||||
if( msg->connect.ioflag & _IO_FLAG_RD ) {
|
||||
msg->connect.sflag = SH_DENYRD;
|
||||
}
|
||||
|
||||
if( msg->connect.ioflag & _IO_FLAG_WR ) {
|
||||
msg->connect.sflag = SH_DENYWR;
|
||||
}
|
||||
|
||||
if( status = iofunc_open_default( ctp, msg, handle, extra ) ) {
|
||||
return( status );
|
||||
}
|
||||
|
||||
if( !( keyb->status & KEYBOARD_IN_USE ) ) { // hook callback
|
||||
usbd_setup_interrupt( keyb->urb, URB_DIR_IN, keyb->ks_ndata, keyb->ep_int_size );
|
||||
if( status = usbd_io( keyb->urb, keyb->ep_int, keyb_int_cbf, keyb, USBD_TIME_INFINITY ) ) {
|
||||
return( status );
|
||||
}
|
||||
keyb->status |= KEYBOARD_IN_USE;
|
||||
}
|
||||
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
int keyb_io_close( resmgr_context_t *ctp, void *reserved, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
keyb_t *keyb;
|
||||
|
||||
keyb = (keyb_t *)ocb->attr;
|
||||
|
||||
iofunc_attr_lock( ocb->attr );
|
||||
if( iofunc_ocb_detach( ctp, ocb ) & IOFUNC_OCB_LAST_READER ) {
|
||||
keyb->status &= ~KEYBOARD_IN_USE;
|
||||
}
|
||||
iofunc_ocb_free( ocb );
|
||||
iofunc_attr_unlock( &keyb->attr );
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
int keyb_io_read( resmgr_context_t *ctp, io_read_t *msg, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
keyb_t *keyb;
|
||||
buffer_t *bptr;
|
||||
char kbuf[1];
|
||||
int pos;
|
||||
int nbytes;
|
||||
|
||||
keyb = (keyb_t *)ocb->attr;
|
||||
bptr = keyb->rbuf;
|
||||
pos = 0;
|
||||
nbytes = msg->i.nbytes;
|
||||
keyb->status &= ~KEYBOARD_UNBLOCK;
|
||||
|
||||
if( !( keyb->status & KEYBOARD_PRESENT ) ) {
|
||||
return( ENODEV );
|
||||
}
|
||||
|
||||
if( ( msg->i.xtype & _IO_XTYPE_MASK ) != _IO_XTYPE_NONE ) {
|
||||
return( EINVAL );
|
||||
}
|
||||
|
||||
if( !( ocb->ioflag & _IO_FLAG_RD ) ) {
|
||||
return( EBADF );
|
||||
}
|
||||
|
||||
ocb->flags |= IOFUNC_ATTR_ATIME;
|
||||
|
||||
if( nbytes == 0 ) {
|
||||
_IO_SET_READ_NBYTES( ctp, 0 );
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
while( 1 ) {
|
||||
// Fix: optimization buff_delete more than one packet at a time
|
||||
while( nbytes && buff_delete( bptr, kbuf, 1 ) > 0 ) {
|
||||
resmgr_msgwrite( ctp, kbuf, 1, pos );
|
||||
nbytes--;
|
||||
pos++;
|
||||
}
|
||||
|
||||
if( !nbytes || pos >= keyb->tios.c_cc[VMIN] ) {
|
||||
break;
|
||||
}
|
||||
pthread_sleepon_lock( );
|
||||
while( buff_waiting( bptr ) == 0 ) {
|
||||
if( keyb->status & KEYBOARD_UNBLOCK ) {
|
||||
pthread_sleepon_unlock( );
|
||||
return( EINTR );
|
||||
}
|
||||
if( !( keyb->status & KEYBOARD_PRESENT ) ) {
|
||||
pthread_sleepon_unlock( );
|
||||
return( ENODEV );
|
||||
}
|
||||
pthread_sleepon_wait( bptr );
|
||||
}
|
||||
pthread_sleepon_unlock( );
|
||||
}
|
||||
|
||||
_IO_SET_READ_NBYTES( ctp, pos );
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
int keyb_io_devctl( resmgr_context_t *ctp, io_devctl_t *msg, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
keyb_t *keyb;
|
||||
_uint32 *data;
|
||||
int nbytes;
|
||||
int status;
|
||||
|
||||
nbytes = 0;
|
||||
data = (_uint32 *)_DEVCTL_DATA( msg->i );
|
||||
keyb = (keyb_t *)ocb->attr;
|
||||
|
||||
if( !( keyb->status & KEYBOARD_PRESENT ) ) {
|
||||
return( ENODEV );
|
||||
}
|
||||
|
||||
// Let common code handle DCMD_ALL_* cases
|
||||
if( ( status = iofunc_devctl_default( ctp, msg, ocb ) ) != _RESMGR_DEFAULT ) {
|
||||
return( status );
|
||||
}
|
||||
|
||||
status = EOK;
|
||||
|
||||
switch( msg->i.dcmd ) {
|
||||
case DCMD_CHR_TCGETATTR:
|
||||
nbytes = sizeof( struct termios );
|
||||
memcpy( data, &keyb->tios, nbytes );
|
||||
break;
|
||||
|
||||
case DCMD_CHR_TCSETATTR:
|
||||
nbytes = sizeof( struct termios );
|
||||
memcpy( &keyb->tios, data, nbytes );
|
||||
break;
|
||||
|
||||
case DCMD_CHR_TCFLUSH:
|
||||
buff_flush( keyb->rbuf );
|
||||
break;
|
||||
|
||||
case DCMD_CHR_TTYINFO: {
|
||||
struct _ttyinfo *ttyinfo;
|
||||
|
||||
ttyinfo = (struct _ttyinfo *)data;
|
||||
strcpy( ttyinfo->ttyname, "kbd" );
|
||||
ttyinfo->opencount = keyb->attr.count;
|
||||
nbytes = sizeof( *ttyinfo );
|
||||
break;
|
||||
}
|
||||
|
||||
case DCMD_CHR_LINESTATUS:
|
||||
if( keyb->leds & SCROLLLOCK_MAP ) {
|
||||
*data |= _LINESTATUS_CON_SCROLL;
|
||||
}
|
||||
if( keyb->leds & NUMLOCK_MAP ) {
|
||||
*data |= _LINESTATUS_CON_NUM;
|
||||
}
|
||||
if( keyb->leds & CAPSLOCK_MAP ) {
|
||||
*data |= _LINESTATUS_CON_CAPS;
|
||||
}
|
||||
nbytes = sizeof( *data );
|
||||
break;
|
||||
|
||||
case DCMD_CHR_SERCTL: {
|
||||
_uint32 leds = 0;
|
||||
|
||||
if( *data & _CONCTL_NUM ) leds |= NUMLOCK_MAP;
|
||||
if( *data & _CONCTL_CAPS ) leds |= CAPSLOCK_MAP;
|
||||
if( *data & _CONCTL_SCROLL ) leds |= SCROLLLOCK_MAP;
|
||||
keyb_set_report( keyb, leds );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
status = ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
msg->o.ret_val = status;
|
||||
return( _RESMGR_PTR( ctp, &msg->o, sizeof( msg->o ) + nbytes ) );
|
||||
}
|
||||
|
||||
int keyb_io_lock_ocb( resmgr_context_t *ctp, void *reserved, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
int keyb_io_unlock_ocb( resmgr_context_t *ctp, void *reserved, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
int keyb_get_devnum( )
|
||||
{
|
||||
int cnt;
|
||||
int match;
|
||||
keyb_t *keyb;
|
||||
|
||||
for( cnt = 0; cnt < 16; cnt++ ) {
|
||||
for( match = 0, keyb = TAILQ_FIRST( &KeybCtrl.dlist ); keyb; keyb = TAILQ_NEXT( keyb, dlink ) ) {
|
||||
if( minor( keyb->devnum ) == cnt ) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( !match ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( cnt ) {
|
||||
fprintf( stderr, "get_devnum\n" );
|
||||
}
|
||||
return( cnt );
|
||||
}
|
||||
|
||||
int keyb_resmgr_attach( keyb_t *keyb )
|
||||
{
|
||||
char name[255];
|
||||
|
||||
// setup termios structure
|
||||
keyb->tios.c_cc[VMIN] = 1;
|
||||
iofunc_attr_init( &keyb->attr, 0600 | S_IFCHR, 0, 0 );
|
||||
iofunc_func_init( _RESMGR_CONNECT_NFUNCS, &keyb->resmgr_connect_funcs, _RESMGR_IO_NFUNCS, &keyb->resmgr_io_funcs );
|
||||
if( ( keyb->attr.rdev = rsrcdbmgr_devno_attach( "usb", -1, 0 ) ) != -1 ) {
|
||||
keyb->devnum = keyb_get_devnum( );
|
||||
sprintf( name, "/dev/%s%d", KeybCtrl.prefix, keyb->devnum );
|
||||
keyb->resmgr_connect_funcs.open = keyb_io_open;
|
||||
keyb->resmgr_io_funcs.close_ocb = keyb_io_close;
|
||||
keyb->resmgr_io_funcs.unlock_ocb = keyb_io_unlock_ocb;
|
||||
keyb->resmgr_io_funcs.lock_ocb = keyb_io_lock_ocb;
|
||||
keyb->resmgr_io_funcs.read = keyb_io_read;
|
||||
keyb->resmgr_io_funcs.devctl = keyb_io_devctl;
|
||||
keyb->resmgr_io_funcs.unblock = keyb_io_unblock;
|
||||
if( ( keyb->resmgr_id = resmgr_attach( KeybCtrl.dispatch, NULL, name, _FTYPE_ANY, 0,
|
||||
&keyb->resmgr_connect_funcs, &keyb->resmgr_io_funcs, &keyb->attr ) ) != -1 ) {
|
||||
resmgr_devino( keyb->resmgr_id, &keyb->io_mount.dev, &keyb->attr.inode );
|
||||
if( ( keyb->rbuf = buff_create( 0, 64, 1 ) ) ) {
|
||||
return( EOK );
|
||||
}
|
||||
else {
|
||||
fprintf( stderr, "Keyb: cannot alloc ring buffer\n" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf( stderr, "Keyb: resmgr_attach\n" );
|
||||
}
|
||||
rsrcdbmgr_devno_detach( keyb->attr.rdev, 0 );
|
||||
}
|
||||
else {
|
||||
fprintf( stderr, "Unable to acquire devno\n" );
|
||||
}
|
||||
|
||||
return( EIO );
|
||||
}
|
||||
|
||||
int keyb_parse_descriptors( keyb_t *keyb )
|
||||
{
|
||||
_uint32 eix;
|
||||
_uint32 scan;
|
||||
_uint32 found;
|
||||
usbd_descriptors_t *desc;
|
||||
struct usbd_desc_node *ifc, *ept;
|
||||
|
||||
scan = KEYBOARD_CONTROL_EP | KEYBOARD_INTIN_EP;
|
||||
found = 0;
|
||||
|
||||
if( usbd_interface_descriptor( keyb->device, keyb->instance.config, keyb->instance.iface, keyb->instance.alternate, &ifc ) ) {
|
||||
for( eix = 0; ( desc = usbd_parse_descriptors( keyb->device, ifc, USB_DESC_ENDPOINT, eix, &ept ) ) != NULL; ++eix ) {
|
||||
switch( desc->endpoint.bmAttributes ) {
|
||||
case USB_ATTRIB_CONTROL:
|
||||
if( usbd_open_pipe( keyb->device, desc, &keyb->ep_cntl ) == EOK ) {
|
||||
found |= KEYBOARD_CONTROL_EP;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_ATTRIB_ISOCHRONOUS:
|
||||
break;
|
||||
|
||||
case USB_ATTRIB_BULK:
|
||||
break;
|
||||
|
||||
case USB_ATTRIB_INTERRUPT:
|
||||
switch( desc->endpoint.bEndpointAddress & USB_ENDPOINT_IN ) {
|
||||
case USB_ENDPOINT_OUT:
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_IN:
|
||||
if( usbd_open_pipe( keyb->device, desc,
|
||||
&keyb->ep_int ) == EOK ) {
|
||||
keyb->ep_int_size = desc->endpoint.wMaxPacketSize;
|
||||
found |= KEYBOARD_INTIN_EP;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return( ( found == scan ) ? EOK : ENODEV );
|
||||
}
|
||||
|
||||
void keyb_insertion( struct usbd_connection *connection, usbd_device_instance_t *instance )
|
||||
{
|
||||
keyb_t *keyb;
|
||||
struct usbd_device *device;
|
||||
int status;
|
||||
|
||||
if( ( status = usbd_attach( connection, instance, sizeof( keyb_t ), &device ) ) == EOK ) {
|
||||
keyb = usbd_device_extra( device );
|
||||
keyb->device = device;
|
||||
keyb->instance = *instance;
|
||||
if( keyb_parse_descriptors( keyb ) == EOK ) {
|
||||
if( keyb->urb = usbd_alloc_urb( NULL ) ) {
|
||||
if( ( keyb->ks_ndata = usbd_alloc( keyb->ep_int_size ) ) ) {
|
||||
if( ( keyb->ks_odata = usbd_alloc( keyb->ep_int_size ) ) ) {
|
||||
keyb_set_idle( keyb );
|
||||
if( keyb_resmgr_attach( keyb ) == EOK ) {
|
||||
keyb->status = KEYBOARD_PRESENT;
|
||||
TAILQ_INSERT_TAIL( &KeybCtrl.dlist, keyb, dlink );
|
||||
return;
|
||||
}
|
||||
usbd_free( keyb->ks_odata );
|
||||
}
|
||||
usbd_free( keyb->ks_ndata );
|
||||
}
|
||||
usbd_free_urb( keyb->urb );
|
||||
}
|
||||
}
|
||||
usbd_detach( device );
|
||||
}
|
||||
}
|
||||
|
||||
void keyb_removal( struct usbd_connection *connection, usbd_device_instance_t *instance )
|
||||
{
|
||||
struct usbd_device *device;
|
||||
keyb_t *keyb;
|
||||
|
||||
if( ( device = usbd_device_lookup( connection, instance ) ) != NULL ) {
|
||||
keyb = usbd_device_extra( device );
|
||||
keyb_free( keyb );
|
||||
}
|
||||
}
|
||||
|
||||
int keyb_resmgr_init( )
|
||||
{
|
||||
resmgr_attr_t attr;
|
||||
|
||||
if( procmgr_daemon( EXIT_SUCCESS, PROCMGR_DAEMON_NOCLOSE | PROCMGR_DAEMON_NODEVNULL ) == -1 ) {
|
||||
fprintf( stderr, "Keyb: procmgr_daemon\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( ( KeybCtrl.dispatch = dispatch_create( ) ) == NULL ) {
|
||||
fprintf( stderr, "Unable to allocate dispatch context\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
memset( &KeybCtrl.pool_attr, 0, sizeof( KeybCtrl.pool_attr ) );
|
||||
if( ( KeybCtrl.pool_attr.attr = malloc( sizeof( *KeybCtrl.pool_attr.attr ) ) ) == NULL ) {
|
||||
fprintf( stderr, "Unable to alloc pool attr\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
pthread_attr_init( KeybCtrl.pool_attr.attr );
|
||||
pthread_attr_setstacksize( KeybCtrl.pool_attr.attr, 8192 );
|
||||
|
||||
KeybCtrl.pool_attr.handle = KeybCtrl.dispatch;
|
||||
KeybCtrl.pool_attr.context_alloc = resmgr_context_alloc;
|
||||
KeybCtrl.pool_attr.block_func = resmgr_block;
|
||||
KeybCtrl.pool_attr.handler_func = (void *)dispatch_handler;
|
||||
KeybCtrl.pool_attr.context_free = resmgr_context_free;
|
||||
KeybCtrl.pool_attr.lo_water = 1;
|
||||
KeybCtrl.pool_attr.hi_water = 2;
|
||||
KeybCtrl.pool_attr.increment = 1;
|
||||
KeybCtrl.pool_attr.maximum = 2;
|
||||
|
||||
if( ( KeybCtrl.thread_pool = thread_pool_create( &KeybCtrl.pool_attr, 0 ) ) == NULL ) {
|
||||
fprintf( stderr, "Unable to initialize thread pool\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
memset( &attr, 0, sizeof( attr ) );
|
||||
attr.nparts_max = 10;
|
||||
attr.msg_max_size = 0;
|
||||
|
||||
if( resmgr_attach( KeybCtrl.dispatch, &attr, NULL, 0, 0, NULL, NULL, NULL ) == -1 ) {
|
||||
fprintf( stderr, "Unable to attach name\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( thread_pool_start( KeybCtrl.thread_pool ) ) {
|
||||
fprintf( stderr, "Unable to initialize thread_pool\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int keyb_start_driver( int argc, char *argv[] )
|
||||
{
|
||||
struct usbd_connection *connection;
|
||||
usbd_funcs_t funcs = { _USBDI_NFUNCS, keyb_insertion, keyb_removal, NULL };
|
||||
usbd_device_ident_t interest = { USBD_CONNECT_WILDCARD, USBD_CONNECT_WILDCARD, USB_CLASS_HID, USB_SUBCLASS_HID_BOOT, USB_PROTOCOL_KEYBOARD };
|
||||
usbd_connect_parm_t parm = { NULL, USB_VERSION, USBD_VERSION, 0, argc, argv, 0, &interest, &funcs, USBD_CONNECT_WAIT };
|
||||
int status;
|
||||
int opt;
|
||||
sigset_t signals;
|
||||
|
||||
sigfillset( &signals ); // No signals to resmgr threads
|
||||
pthread_sigmask( SIG_BLOCK, &signals, NULL );
|
||||
|
||||
TAILQ_INIT( &KeybCtrl.dlist );
|
||||
KeybCtrl.prefix = "usbkbd";
|
||||
|
||||
while( ( opt = getopt( argc, argv, "vn:s:w:" ) ) != -1 ) {
|
||||
switch( opt ) {
|
||||
case 'n':
|
||||
KeybCtrl.prefix = optarg;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
KeybCtrl.verbose++;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
parm.path = optarg;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
parm.connect_wait = strtol( optarg, 0, 0 );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( ( KeybCtrl.chid = ChannelCreate( _NTO_CHF_DISCONNECT | _NTO_CHF_UNBLOCK ) ) == -1 ||
|
||||
( KeybCtrl.coid = ConnectAttach( 0, 0, KeybCtrl.chid, _NTO_SIDE_CHANNEL, 0 ) ) == -1 ) {
|
||||
fprintf( stderr, "Unable to attach channel and connection\n" );
|
||||
return( errno );
|
||||
}
|
||||
|
||||
if( keyb_resmgr_init( ) ) {
|
||||
fprintf( stderr, "Keyb: Resmgr Init Failure\n" );
|
||||
return( errno );
|
||||
}
|
||||
|
||||
if( ( status = usbd_connect( &parm, &connection ) ) != EOK ) {
|
||||
fprintf( stderr, "Keyb Class/init - %s\n", strerror( status ) );
|
||||
return( status );
|
||||
}
|
||||
|
||||
return( status );
|
||||
}
|
||||
|
||||
int main( int argc, char *argv[] )
|
||||
{
|
||||
if( keyb_start_driver( argc, argv ) ) {
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
keyb_signal_handler( );
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
191
devu/class/keyboard/keyb.h
Normal file
191
devu/class/keyboard/keyb.h
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* (c) 2010-2019, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
*/
|
||||
|
||||
// Module Description: header for keyboard class driver
|
||||
|
||||
#include <share.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <gulliver.h>
|
||||
#include <sys/usbdi.h>
|
||||
#include <sys/iofunc.h>
|
||||
#include <sys/resmgr.h>
|
||||
#include <sys/procmgr.h>
|
||||
#include <sys/dcmd_chr.h>
|
||||
#include <sys/dispatch.h>
|
||||
#include <sys/neutrino.h>
|
||||
#include <sys/rsrcdbmgr.h>
|
||||
|
||||
// private headers
|
||||
#include <queue.h>
|
||||
|
||||
typedef struct buffer buffer_t;
|
||||
|
||||
#define BUFF_OVERWRITE 0x01
|
||||
struct buffer {
|
||||
int head;
|
||||
int tail;
|
||||
int bufsize;
|
||||
int recsize;
|
||||
char *ptr;
|
||||
unsigned mode;
|
||||
int min;
|
||||
};
|
||||
|
||||
// KEYBOARD BUFFER REPORT DEFINITION
|
||||
#define NKEYCODE 6
|
||||
#define NMOD 8
|
||||
|
||||
#define PRESS 0x000
|
||||
#define RELEASE 0x100
|
||||
#define CODEMASK 0x0ff
|
||||
|
||||
#define KEY_ERROR 0x01
|
||||
#define MAXKEYS (NMOD+2*NKEYCODE)
|
||||
|
||||
#define MOD_CONTROL_L 0x01
|
||||
#define MOD_CONTROL_R 0x10
|
||||
#define MOD_SHIFT_L 0x02
|
||||
#define MOD_SHIFT_R 0x20
|
||||
#define MOD_ALT_L 0x04
|
||||
#define MOD_ALT_R 0x40
|
||||
#define MOD_WIN_L 0x08
|
||||
#define MOD_WIN_R 0x80
|
||||
|
||||
typedef struct _keyb_report {
|
||||
uint8_t modifiers;
|
||||
uint8_t reserved;
|
||||
uint8_t keycode[NKEYCODE];
|
||||
} keyb_report_t;
|
||||
|
||||
typedef struct _keyb {
|
||||
iofunc_attr_t attr;
|
||||
TAILQ_ENTRY( _keyb ) dlink;
|
||||
int resmgr_id;
|
||||
_uint32 devnum;
|
||||
resmgr_connect_funcs_t resmgr_connect_funcs;
|
||||
resmgr_io_funcs_t resmgr_io_funcs;
|
||||
iofunc_mount_t io_mount;
|
||||
struct termios tios;
|
||||
struct usbd_connection *connection;
|
||||
usbd_device_instance_t instance;
|
||||
struct usbd_device *device;
|
||||
_uint32 status;
|
||||
struct usbd_pipe *ep_cntl;
|
||||
struct usbd_pipe *ep_int;
|
||||
uint32_t ep_int_size;
|
||||
struct usbd_urb *urb;
|
||||
_uint8 *ep_int_buf;
|
||||
buffer_t *rbuf; // ring buffer
|
||||
|
||||
uint8_t leds;
|
||||
uint8_t rsvd[3];
|
||||
|
||||
keyb_report_t *ks_ndata;
|
||||
keyb_report_t *ks_odata;
|
||||
uint32_t ks_ntime;
|
||||
int ks_nrep;
|
||||
char ks_rep[MAXKEYS];
|
||||
} keyb_t;
|
||||
|
||||
typedef struct _keyb_ctrl {
|
||||
TAILQ_HEAD(,_keyb) dlist; // linked list of mice
|
||||
_uint32 cflags;
|
||||
_uint32 verbose;
|
||||
char *prefix;
|
||||
int coid;
|
||||
int chid;
|
||||
thread_pool_t *thread_pool;
|
||||
dispatch_t *dispatch;
|
||||
thread_pool_attr_t pool_attr;
|
||||
} keyb_ctrl_t;
|
||||
|
||||
static struct {
|
||||
int mask, key;
|
||||
} ukbd_mods[NMOD] = {
|
||||
{ MOD_CONTROL_L, 0xe0 },
|
||||
{ MOD_CONTROL_R, 0xe4 },
|
||||
{ MOD_SHIFT_L, 0xe1 },
|
||||
{ MOD_SHIFT_R, 0xe5 },
|
||||
{ MOD_ALT_L, 0xe2 },
|
||||
{ MOD_ALT_R, 0xe6 },
|
||||
{ MOD_WIN_L, 0xe3 },
|
||||
{ MOD_WIN_R, 0xe7 },
|
||||
};
|
||||
|
||||
#define NN 0 // no translation
|
||||
// Translate USB keycodes to US keyboard AT/XT scancodes.
|
||||
// Scancodes >= 128 represent EXTENDED keycodes.
|
||||
static _uint8 ukbd_trtab[256] = {
|
||||
NN, NN, NN, NN, 30, 48, 46, 32, /* 00 - 07 */
|
||||
18, 33, 34, 35, 23, 36, 37, 38, /* 08 - 0F */
|
||||
50, 49, 24, 25, 16, 19, 31, 20, /* 10 - 17 */
|
||||
22, 47, 17, 45, 21, 44, 2, 3, /* 18 - 1F */
|
||||
4, 5, 6, 7, 8, 9, 10, 11, /* 20 - 27 */
|
||||
28, 1, 14, 15, 57, 12, 13, 26, /* 28 - 2F */
|
||||
27, 43, 43, 39, 40, 41, 51, 52, /* 30 - 37 */
|
||||
53, 58, 59, 60, 61, 62, 63, 64, /* 38 - 3F */
|
||||
65, 66, 67, 68, 87, 88, 183, 70, /* 40 - 47 */
|
||||
127, 210, 199, 201, 211, 207, 209, 205, /* 48 - 4F */
|
||||
203, 208, 200, 69, 181, 55, 74, 78, /* 50 - 57 */
|
||||
156, 79, 80, 81, 75, 76, 77, 71, /* 58 - 5F */
|
||||
72, 73, 82, 83, 86, 221, NN, NN, /* 60 - 67 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* 68 - 6F */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* 70 - 77 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* 78 - 7F */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* 80 - 87 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* 88 - 8F */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* 90 - 97 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9F */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* A0 - A7 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* A8 - AF */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* B0 - B7 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* B8 - BF */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* C0 - C7 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* C8 - CF */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* D0 - D7 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* D8 - DF */
|
||||
29, 42, 56, 219, 157, 54, 184,220, /* E0 - E7 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* E8 - EF */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* F0 - F7 */
|
||||
NN, NN, NN, NN, NN, NN, NN, NN, /* F8 - FF */
|
||||
};
|
||||
|
||||
// KEYBOARD STATUS DEFINITION
|
||||
#define KEYBOARD_NOT_IN_USE 0
|
||||
#define KEYBOARD_IN_USE 1
|
||||
#define KEYBOARD_IN_SHUTDOWN 2
|
||||
#define KEYBOARD_UNBLOCK 4
|
||||
#define KEYBOARD_PRESENT 8
|
||||
|
||||
#define KEYBOARD_CONTROL_EP 1
|
||||
#define KEYBOARD_INTIN_EP 2
|
||||
|
||||
// KEYBOARD HID DEFINITION
|
||||
#define USB_SUBCLASS_HID_BOOT 1
|
||||
#define USB_PROTOCOL_KEYBOARD 1
|
||||
|
||||
// REPORTS EQUIVALENCES
|
||||
#define HID_SET_REPORT 9
|
||||
#define HID_REPORT_IN (1 << 8)
|
||||
#define HID_REPORT_OUT (2 << 8)
|
||||
#define HID_REPORT_FEATURE (3 << 8)
|
||||
|
||||
// KEYBOARD LEDS EQUIVALENCES
|
||||
#define NUMLOCK_MAP 1
|
||||
#define CAPSLOCK_MAP 2
|
||||
#define SCROLLLOCK_MAP 4
|
||||
|
||||
extern buffer_t *buff_create( unsigned mode, unsigned size, unsigned rsize );
|
||||
extern int buff_destroy( buffer_t *bptr );
|
||||
extern int buff_append( buffer_t *bptr, char *dptr, int n );
|
||||
extern int buff_delete( buffer_t *bptr, char *dptr, int n );
|
||||
extern int buff_flush( buffer_t *bptr );
|
||||
extern int buff_putc( buffer_t *bptr, char c );
|
||||
extern int buff_getc( buffer_t *bptr );
|
||||
extern int buff_waiting( buffer_t *bptr );
|
2
devu/class/keyboard/mips/Makefile
Normal file
2
devu/class/keyboard/mips/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/keyboard/mips/be/Makefile
Normal file
1
devu/class/keyboard/mips/be/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/keyboard/mips/le.mc/Makefile
Normal file
1
devu/class/keyboard/mips/le.mc/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/keyboard/mips/le/Makefile
Normal file
1
devu/class/keyboard/mips/le/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
5
devu/class/keyboard/override.mk
Normal file
5
devu/class/keyboard/override.mk
Normal file
@ -0,0 +1,5 @@
|
||||
#
|
||||
# (c) 2010, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
#
|
||||
|
||||
SECTION=kbd
|
7
devu/class/keyboard/pinfo.mk
Normal file
7
devu/class/keyboard/pinfo.mk
Normal file
@ -0,0 +1,7 @@
|
||||
#
|
||||
# (c) 2010, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
#
|
||||
|
||||
define PINFO
|
||||
PINFO DESCRIPTION=Keyboard class driver
|
||||
endef
|
2
devu/class/keyboard/ppc/Makefile
Normal file
2
devu/class/keyboard/ppc/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/keyboard/ppc/be.spe/Makefile
Normal file
1
devu/class/keyboard/ppc/be.spe/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/keyboard/ppc/be/Makefile
Normal file
1
devu/class/keyboard/ppc/be/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
2
devu/class/keyboard/x86/Makefile
Normal file
2
devu/class/keyboard/x86/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|