Драйвер devh-egalax для ЗОСРВ "Нейтрино" редакции 2020
Этот коммит содержится в:
Коммит
13333b0126
2
Makefile
Обычный файл
2
Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=hardware
|
||||
include recurse.mk
|
93
README.md
Обычный файл
93
README.md
Обычный файл
@ -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
Обычный файл
2
devu/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=USB
|
||||
include recurse.mk
|
2
devu/class/Makefile
Обычный файл
2
devu/class/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=CLASS
|
||||
include recurse.mk
|
53
devu/class/common.mk
Обычный файл
53
devu/class/common.mk
Обычный файл
@ -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
Обычный файл
2
devu/class/keyboard/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=CPU
|
||||
include recurse.mk
|
2
devu/class/keyboard/arm/Makefile
Обычный файл
2
devu/class/keyboard/arm/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/keyboard/arm/le.v7/Makefile
Обычный файл
1
devu/class/keyboard/arm/le.v7/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/keyboard/arm/le/Makefile
Обычный файл
1
devu/class/keyboard/arm/le/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
197
devu/class/keyboard/buffer.c
Обычный файл
197
devu/class/keyboard/buffer.c
Обычный файл
@ -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
Обычный файл
13
devu/class/keyboard/devu-kbd.use
Обычный файл
@ -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
Обычный файл
2
devu/class/keyboard/e2k/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/keyboard/e2k/le/Makefile
Обычный файл
1
devu/class/keyboard/e2k/le/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
806
devu/class/keyboard/keyb.c
Обычный файл
806
devu/class/keyboard/keyb.c
Обычный файл
@ -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
Обычный файл
191
devu/class/keyboard/keyb.h
Обычный файл
@ -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
Обычный файл
2
devu/class/keyboard/mips/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/keyboard/mips/be/Makefile
Обычный файл
1
devu/class/keyboard/mips/be/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/keyboard/mips/le.mc/Makefile
Обычный файл
1
devu/class/keyboard/mips/le.mc/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/keyboard/mips/le/Makefile
Обычный файл
1
devu/class/keyboard/mips/le/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
5
devu/class/keyboard/override.mk
Обычный файл
5
devu/class/keyboard/override.mk
Обычный файл
@ -0,0 +1,5 @@
|
||||
#
|
||||
# (c) 2010, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
#
|
||||
|
||||
SECTION=kbd
|
7
devu/class/keyboard/pinfo.mk
Обычный файл
7
devu/class/keyboard/pinfo.mk
Обычный файл
@ -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
Обычный файл
2
devu/class/keyboard/ppc/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/keyboard/ppc/be.spe/Makefile
Обычный файл
1
devu/class/keyboard/ppc/be.spe/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/keyboard/ppc/be/Makefile
Обычный файл
1
devu/class/keyboard/ppc/be/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
2
devu/class/keyboard/x86/Makefile
Обычный файл
2
devu/class/keyboard/x86/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/keyboard/x86/o/Makefile
Обычный файл
1
devu/class/keyboard/x86/o/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
2
devu/class/mouse/Makefile
Обычный файл
2
devu/class/mouse/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=CPU
|
||||
include recurse.mk
|
2
devu/class/mouse/arm/Makefile
Обычный файл
2
devu/class/mouse/arm/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/mouse/arm/le.v7/Makefile
Обычный файл
1
devu/class/mouse/arm/le.v7/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/mouse/arm/le/Makefile
Обычный файл
1
devu/class/mouse/arm/le/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
197
devu/class/mouse/buffer.c
Обычный файл
197
devu/class/mouse/buffer.c
Обычный файл
@ -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/mouse/devu-mouse.use
Обычный файл
13
devu/class/mouse/devu-mouse.use
Обычный файл
@ -0,0 +1,13 @@
|
||||
%C Class Driver for USB mice (BOOT mode HID).
|
||||
|
||||
Syntax:
|
||||
devu-mouse [options*] &
|
||||
|
||||
Options:
|
||||
-n name Set device name. default "/dev/usbmouse0"
|
||||
-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-mouse &
|
2
devu/class/mouse/e2k/Makefile
Обычный файл
2
devu/class/mouse/e2k/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/mouse/e2k/le/Makefile
Обычный файл
1
devu/class/mouse/e2k/le/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
2
devu/class/mouse/mips/Makefile
Обычный файл
2
devu/class/mouse/mips/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/mouse/mips/be/Makefile
Обычный файл
1
devu/class/mouse/mips/be/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/mouse/mips/le.mc/Makefile
Обычный файл
1
devu/class/mouse/mips/le.mc/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/mouse/mips/le/Makefile
Обычный файл
1
devu/class/mouse/mips/le/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
574
devu/class/mouse/mouse.c
Обычный файл
574
devu/class/mouse/mouse.c
Обычный файл
@ -0,0 +1,574 @@
|
||||
/*
|
||||
* (c) 2010-2019, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
*/
|
||||
|
||||
// Module Description: mouse class driver
|
||||
|
||||
#include <mouse.h>
|
||||
|
||||
mouse_ctrl_t MouseCtrl;
|
||||
|
||||
int mouse_free( mouse_t *mouse )
|
||||
{
|
||||
int status;
|
||||
|
||||
mouse->status &= ~( MOUSE_PRESENT | MOUSE_ON );
|
||||
|
||||
if( mouse->ep_int ) { // Stop the Interrupt In endpoint
|
||||
usbd_abort_pipe( mouse->ep_int );
|
||||
}
|
||||
|
||||
pthread_sleepon_lock( );
|
||||
pthread_sleepon_signal( mouse->rbuf );
|
||||
pthread_sleepon_unlock( );
|
||||
|
||||
if( status = rsrcdbmgr_devno_detach( mouse->attr.rdev, 0 ) ) {
|
||||
fprintf( stderr, "mouse_free: rsrcddbmgr_devno_detach %d\n", errno );
|
||||
}
|
||||
if( status = resmgr_detach( MouseCtrl.dispatch, mouse->resmgr_id, _RESMGR_DETACH_ALL | _RESMGR_DETACH_CLOSE ) ) {
|
||||
fprintf( stderr, "mouse_free: resmgr_detach %d\n", status );
|
||||
}
|
||||
usbd_free_urb( mouse->urb );
|
||||
usbd_free( mouse->ep_int_buf );
|
||||
buff_destroy( mouse->rbuf );
|
||||
TAILQ_REMOVE( &MouseCtrl.dlist, mouse, dlink );
|
||||
if( status = usbd_detach( mouse->device ) ) {
|
||||
fprintf( stderr, "mouse_free: usbd_detach %x\n", status );
|
||||
}
|
||||
return( status );
|
||||
}
|
||||
|
||||
void mouse_signal_handler( )
|
||||
{
|
||||
siginfo_t info;
|
||||
sigset_t set;
|
||||
mouse_t *mouse;
|
||||
mouse_t *nmouse;
|
||||
|
||||
sigfillset( &set );
|
||||
sigdelset( &set, SIGTERM );
|
||||
sigprocmask( SIG_BLOCK, &set, NULL );
|
||||
|
||||
sigemptyset( &set );
|
||||
sigaddset( &set, SIGTERM );
|
||||
while( SignalWaitinfo( &set, &info ) == -1 )
|
||||
;
|
||||
|
||||
for( mouse = TAILQ_FIRST( &MouseCtrl.dlist ); mouse; mouse = nmouse ) {
|
||||
nmouse = TAILQ_NEXT( mouse, dlink );
|
||||
mouse_free( mouse );
|
||||
}
|
||||
}
|
||||
|
||||
int mouse_process( mouse_t *mouse )
|
||||
{
|
||||
uint8_t mp[3];
|
||||
uint8_t *p;
|
||||
|
||||
// convert report packet to microsoft packet
|
||||
p = mouse->ep_int_buf;
|
||||
mp[0] = 0x40;
|
||||
mp[0] |= (*(p+1) >> 6) & 0x03;
|
||||
mp[0] |= (*(p+2) >> 4) & 0x0C;
|
||||
mp[0] |= (*(p+0) & 0x01) ? 0x20: 0x00; // left mouse button
|
||||
mp[0] |= (*(p+0) & 0x02) ? 0x10: 0x00; // right mouse button
|
||||
mp[1] = *(p+1) & 0x3F;
|
||||
mp[2] = *(p+2) & 0x3F;
|
||||
// mp[3] = (*(p+0) & 0x04) ? 0x10: 0x00; // middle mouse button
|
||||
|
||||
buff_append( mouse->rbuf, (char *)mp, 1 );
|
||||
|
||||
pthread_sleepon_lock( ); // wakeup anyone blocked
|
||||
pthread_sleepon_signal( mouse->rbuf );
|
||||
pthread_sleepon_unlock( );
|
||||
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
void mouse_int_cbf( struct usbd_urb *urb, struct usbd_pipe *pipe, void *hdl )
|
||||
{
|
||||
mouse_t *mouse;
|
||||
_uint32 ustatus;
|
||||
_uint32 alen;
|
||||
|
||||
mouse = (mouse_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( MouseCtrl.verbose ) {
|
||||
fprintf( stderr, "mouse_int_cbf: ustatus %x\n", ustatus );
|
||||
}
|
||||
}
|
||||
else {
|
||||
mouse_process( mouse );
|
||||
}
|
||||
|
||||
if( mouse->status & MOUSE_ON ) { // re-hook interrupt endpoint
|
||||
usbd_setup_interrupt( mouse->urb, URB_DIR_IN|URB_SHORT_XFER_OK, mouse->ep_int_buf, mouse->ep_int_size );
|
||||
if( usbd_io( mouse->urb, mouse->ep_int, mouse_int_cbf, mouse, USBD_TIME_INFINITY ) ) {
|
||||
pthread_sleepon_lock( );
|
||||
mouse->status &= ~( MOUSE_ON | MOUSE_PRESENT );
|
||||
pthread_sleepon_signal( mouse->rbuf );
|
||||
pthread_sleepon_unlock( );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int mouse_io_unblock( resmgr_context_t *ctp, io_pulse_t *msg, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
mouse_t *mouse;
|
||||
|
||||
mouse = (mouse_t *)ocb->attr;
|
||||
|
||||
pthread_sleepon_lock( );
|
||||
mouse->status |= MOUSE_UNBLOCK;
|
||||
pthread_sleepon_signal( mouse->rbuf );
|
||||
pthread_sleepon_unlock( );
|
||||
|
||||
return( _RESMGR_NOREPLY );
|
||||
}
|
||||
|
||||
int mouse_io_open( resmgr_context_t *ctp, io_open_t *msg, RESMGR_HANDLE_T *handle, void *extra )
|
||||
{
|
||||
mouse_t *mouse;
|
||||
int status;
|
||||
|
||||
mouse = (mouse_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( !( mouse->status & MOUSE_ON ) ) { // hook callback
|
||||
usbd_setup_interrupt( mouse->urb, URB_DIR_IN|URB_SHORT_XFER_OK, mouse->ep_int_buf, mouse->ep_int_size );
|
||||
if( status = usbd_io( mouse->urb, mouse->ep_int, mouse_int_cbf, mouse, USBD_TIME_INFINITY ) ) {
|
||||
return( status );
|
||||
}
|
||||
mouse->status |= MOUSE_ON;
|
||||
}
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
int mouse_io_close( resmgr_context_t *ctp, void *reserved, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
mouse_t *mouse;
|
||||
|
||||
mouse = (mouse_t *)ocb->attr;
|
||||
|
||||
iofunc_attr_lock( ocb->attr );
|
||||
if( iofunc_ocb_detach( ctp, ocb ) & IOFUNC_OCB_LAST_READER ) {
|
||||
mouse->status &= ~MOUSE_ON;
|
||||
}
|
||||
iofunc_ocb_free( ocb );
|
||||
iofunc_attr_unlock( &mouse->attr );
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
int mouse_io_read( resmgr_context_t *ctp, io_read_t *msg, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
mouse_t *mouse;
|
||||
buffer_t *bptr;
|
||||
char mbuf[3];
|
||||
int pos;
|
||||
int nbytes;
|
||||
|
||||
mouse = (mouse_t *)ocb->attr;
|
||||
bptr = mouse->rbuf;
|
||||
pos = 0;
|
||||
nbytes = msg->i.nbytes;
|
||||
mouse->status &= ~MOUSE_UNBLOCK;
|
||||
|
||||
if( !( mouse->status & MOUSE_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 >= 3 && buff_delete( bptr, mbuf, 1 ) > 0 ) {
|
||||
resmgr_msgwrite( ctp, mbuf, 3, pos );
|
||||
nbytes -=3;
|
||||
pos += 3;
|
||||
}
|
||||
|
||||
if( !nbytes || pos >= mouse->tios.c_cc[VMIN] || nbytes < 3 ) {
|
||||
break;
|
||||
}
|
||||
pthread_sleepon_lock( );
|
||||
while( buff_waiting( bptr ) == 0 ) {
|
||||
if( mouse->status & MOUSE_UNBLOCK ) {
|
||||
pthread_sleepon_unlock( );
|
||||
return( EINTR );
|
||||
}
|
||||
if( !( mouse->status & MOUSE_PRESENT ) ) {
|
||||
pthread_sleepon_unlock( );
|
||||
return( ENODEV );
|
||||
}
|
||||
pthread_sleepon_wait( bptr );
|
||||
}
|
||||
pthread_sleepon_unlock( );
|
||||
}
|
||||
|
||||
_IO_SET_READ_NBYTES( ctp, pos );
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
int mouse_io_devctl( resmgr_context_t *ctp, io_devctl_t *msg, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
mouse_t *mouse;
|
||||
uint32_t *data;
|
||||
int nbytes;
|
||||
int status;
|
||||
|
||||
nbytes = 0;
|
||||
data = (uint32_t *)_DEVCTL_DATA( msg->i );
|
||||
mouse = (mouse_t *)ocb->attr;
|
||||
|
||||
if( !( mouse->status & MOUSE_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, &mouse->tios, nbytes );
|
||||
break;
|
||||
|
||||
case DCMD_CHR_TCSETATTR:
|
||||
nbytes = sizeof( struct termios );
|
||||
memcpy( &mouse->tios, data, nbytes );
|
||||
break;
|
||||
|
||||
case DCMD_CHR_TCFLUSH:
|
||||
buff_flush( mouse->rbuf );
|
||||
break;
|
||||
|
||||
case DCMD_CHR_TTYINFO: {
|
||||
struct _ttyinfo *ttyinfo;
|
||||
|
||||
ttyinfo = (struct _ttyinfo *)data;
|
||||
strcpy( ttyinfo->ttyname, "ser" );
|
||||
ttyinfo->opencount = mouse->attr.count;
|
||||
nbytes = sizeof( *ttyinfo );
|
||||
break;
|
||||
}
|
||||
|
||||
case DCMD_CHR_LINESTATUS:
|
||||
case DCMD_CHR_SERCTL:
|
||||
default:
|
||||
status = ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
msg->o.ret_val = status;
|
||||
return( _RESMGR_PTR( ctp, &msg->o, sizeof( msg->o ) + nbytes ) );
|
||||
}
|
||||
|
||||
int mouse_get_devnum( )
|
||||
{
|
||||
int cnt;
|
||||
int match;
|
||||
mouse_t *mouse;
|
||||
|
||||
for( cnt = 0; cnt < 16; cnt++ ) {
|
||||
for( match = 0, mouse = TAILQ_FIRST( &MouseCtrl.dlist ); mouse; mouse = TAILQ_NEXT( mouse, dlink ) ) {
|
||||
if( minor( mouse->devnum ) == cnt ) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( !match ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return( cnt );
|
||||
}
|
||||
|
||||
int mouse_io_lock_ocb( resmgr_context_t *ctp, void *reserved, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
int mouse_io_unlock_ocb( resmgr_context_t *ctp, void *reserved, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
int mouse_resmgr_attach( mouse_t *mouse )
|
||||
{
|
||||
char name[255];
|
||||
|
||||
// setup termios structure
|
||||
mouse->tios.c_cc[VMIN] = 3;
|
||||
iofunc_attr_init( &mouse->attr, 0600 | S_IFCHR, 0, 0 );
|
||||
iofunc_func_init( _RESMGR_CONNECT_NFUNCS, &mouse->resmgr_connect_funcs, _RESMGR_IO_NFUNCS, &mouse->resmgr_io_funcs );
|
||||
if( ( mouse->attr.rdev = rsrcdbmgr_devno_attach( "usb", -1, 0 ) ) != -1 ) {
|
||||
mouse->devnum = mouse_get_devnum( );
|
||||
sprintf( name, "/dev/%s%d", MouseCtrl.prefix, mouse->devnum );
|
||||
mouse->resmgr_connect_funcs.open = mouse_io_open;
|
||||
mouse->resmgr_io_funcs.close_ocb = mouse_io_close;
|
||||
mouse->resmgr_io_funcs.unlock_ocb = mouse_io_unlock_ocb;
|
||||
mouse->resmgr_io_funcs.lock_ocb = mouse_io_lock_ocb;
|
||||
mouse->resmgr_io_funcs.read = mouse_io_read;
|
||||
mouse->resmgr_io_funcs.devctl = mouse_io_devctl;
|
||||
mouse->resmgr_io_funcs.unblock = mouse_io_unblock;
|
||||
if( ( mouse->resmgr_id = resmgr_attach( MouseCtrl.dispatch, NULL, name, _FTYPE_ANY, 0,
|
||||
&mouse->resmgr_connect_funcs, &mouse->resmgr_io_funcs, &mouse->attr ) ) != -1 ) {
|
||||
resmgr_devino( mouse->resmgr_id, &mouse->io_mount.dev, &mouse->attr.inode );
|
||||
if( ( mouse->rbuf = buff_create( BUFF_OVERWRITE, 3 * 64, 3 ) ) ) {
|
||||
return( EOK );
|
||||
}
|
||||
else {
|
||||
fprintf( stderr, "Mouse: cannot alloc ring buffer\n" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf( stderr, "Mouse: resmgr_attach\n" );
|
||||
}
|
||||
rsrcdbmgr_devno_detach( mouse->attr.rdev, 0 );
|
||||
}
|
||||
else {
|
||||
fprintf( stderr, "Unable to acquire devno\n" );
|
||||
}
|
||||
|
||||
return( EIO );
|
||||
}
|
||||
|
||||
int mouse_parse_descriptors( mouse_t *mouse )
|
||||
{
|
||||
_uint32 eix;
|
||||
_uint32 scan;
|
||||
_uint32 found;
|
||||
usbd_descriptors_t *desc;
|
||||
struct usbd_desc_node *ifc, *ept;
|
||||
|
||||
scan = MOUSE_CONTROL_EP | MOUSE_INTIN_EP;
|
||||
found = 0;
|
||||
|
||||
if( usbd_interface_descriptor( mouse->device, mouse->instance.config, mouse->instance.iface, mouse->instance.alternate, &ifc ) ) {
|
||||
for( eix = 0; ( desc = usbd_parse_descriptors( mouse->device, ifc, USB_DESC_ENDPOINT, eix, &ept ) ) != NULL; ++eix ) {
|
||||
switch( desc->endpoint.bmAttributes ) {
|
||||
case USB_ATTRIB_CONTROL:
|
||||
if( usbd_open_pipe( mouse->device, desc, &mouse->ep_cntl ) == EOK ) {
|
||||
found |= MOUSE_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( mouse->device, desc,
|
||||
&mouse->ep_int ) == EOK ) {
|
||||
mouse->ep_int_size = desc->endpoint.wMaxPacketSize;
|
||||
found |= MOUSE_INTIN_EP;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return( ( found == scan ) ? EOK : ENODEV );
|
||||
}
|
||||
|
||||
void mouse_insertion( struct usbd_connection *connection, usbd_device_instance_t *instance )
|
||||
{
|
||||
mouse_t *mouse;
|
||||
struct usbd_device *device;
|
||||
int status;
|
||||
|
||||
if( ( status = usbd_attach( connection, instance, sizeof( mouse_t ), &device ) ) == EOK ) {
|
||||
mouse = usbd_device_extra( device );
|
||||
mouse->device = device;
|
||||
mouse->instance = *instance;
|
||||
if( mouse_parse_descriptors( mouse ) == EOK ) {
|
||||
if( mouse->ep_int_buf = usbd_alloc( mouse->ep_int_size ) ) {
|
||||
if( mouse->urb = usbd_alloc_urb( NULL ) ) {
|
||||
if( mouse_resmgr_attach( mouse ) == EOK ) {
|
||||
mouse->status = MOUSE_PRESENT;
|
||||
TAILQ_INSERT_TAIL( &MouseCtrl.dlist, mouse, dlink );
|
||||
return;
|
||||
}
|
||||
usbd_free_urb( mouse->urb );
|
||||
}
|
||||
usbd_free( mouse->ep_int_buf );
|
||||
}
|
||||
}
|
||||
usbd_detach( device );
|
||||
}
|
||||
}
|
||||
|
||||
void mouse_removal( struct usbd_connection *connection, usbd_device_instance_t *instance )
|
||||
{
|
||||
struct usbd_device *device;
|
||||
mouse_t *mouse;
|
||||
|
||||
if( ( device = usbd_device_lookup( connection, instance ) ) != NULL ) {
|
||||
mouse = usbd_device_extra( device );
|
||||
mouse_free( mouse );
|
||||
}
|
||||
}
|
||||
|
||||
int mouse_resmgr_init( )
|
||||
{
|
||||
resmgr_attr_t attr;
|
||||
|
||||
if( procmgr_daemon( EXIT_SUCCESS, PROCMGR_DAEMON_NOCLOSE | PROCMGR_DAEMON_NODEVNULL ) == -1 ) {
|
||||
fprintf( stderr, "Mouse: procmgr_daemon\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( ( MouseCtrl.dispatch = dispatch_create( ) ) == NULL ) {
|
||||
fprintf( stderr, "Unable to allocate dispatch context\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
memset( &MouseCtrl.pool_attr, 0, sizeof( MouseCtrl.pool_attr ) );
|
||||
if( ( MouseCtrl.pool_attr.attr = malloc( sizeof( *MouseCtrl.pool_attr.attr ) ) ) == NULL ) {
|
||||
fprintf( stderr, "Unable to alloc pool attr\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
pthread_attr_init( MouseCtrl.pool_attr.attr );
|
||||
pthread_attr_setstacksize( MouseCtrl.pool_attr.attr, 8192 );
|
||||
|
||||
MouseCtrl.pool_attr.handle = MouseCtrl.dispatch;
|
||||
MouseCtrl.pool_attr.context_alloc = resmgr_context_alloc;
|
||||
MouseCtrl.pool_attr.block_func = resmgr_block;
|
||||
MouseCtrl.pool_attr.handler_func = (void *)dispatch_handler;
|
||||
MouseCtrl.pool_attr.context_free = resmgr_context_free;
|
||||
MouseCtrl.pool_attr.lo_water = 1;
|
||||
MouseCtrl.pool_attr.hi_water = 2;
|
||||
MouseCtrl.pool_attr.increment = 1;
|
||||
MouseCtrl.pool_attr.maximum = 2;
|
||||
|
||||
if( ( MouseCtrl.thread_pool = thread_pool_create( &MouseCtrl.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( MouseCtrl.dispatch, &attr, NULL, 0, 0, NULL, NULL, NULL ) == -1 ) {
|
||||
fprintf( stderr, "Unable to attach name\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( thread_pool_start( MouseCtrl.thread_pool ) ) {
|
||||
fprintf( stderr, "Unable to initialize thread_pool\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int mouse_start_driver( int argc, char *argv[] )
|
||||
{
|
||||
struct usbd_connection *connection;
|
||||
usbd_funcs_t funcs = { _USBDI_NFUNCS, mouse_insertion, mouse_removal, NULL };
|
||||
usbd_device_ident_t interest = { USBD_CONNECT_WILDCARD, USBD_CONNECT_WILDCARD, USB_CLASS_HID, USB_SUBCLASS_HID_BOOT, USB_PROTOCOL_MOUSE };
|
||||
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( &MouseCtrl.dlist );
|
||||
MouseCtrl.prefix = "usbmouse";
|
||||
|
||||
while( ( opt = getopt( argc, argv, "vn:s:w:" ) ) != -1 ) {
|
||||
switch( opt ) {
|
||||
case 'n':
|
||||
MouseCtrl.prefix = optarg;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
MouseCtrl.verbose++;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
parm.path = optarg;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
parm.connect_wait = strtol( optarg, 0, 0 );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( ( MouseCtrl.chid = ChannelCreate( _NTO_CHF_DISCONNECT | _NTO_CHF_UNBLOCK ) ) == -1 ||
|
||||
( MouseCtrl.coid = ConnectAttach( 0, 0, MouseCtrl.chid, _NTO_SIDE_CHANNEL, 0 ) ) == -1 ) {
|
||||
fprintf( stderr, "Unable to attach channel and connection\n" );
|
||||
return( errno );
|
||||
}
|
||||
|
||||
if( mouse_resmgr_init( ) ) {
|
||||
fprintf( stderr, "Mouse: Resmgr Init Failure\n" );
|
||||
return( errno );
|
||||
}
|
||||
|
||||
if( ( status = usbd_connect( &parm, &connection ) ) != EOK ) {
|
||||
fprintf( stderr, "Mouse Class/init - %s\n", strerror( status ) );
|
||||
return( status );
|
||||
}
|
||||
return( status );
|
||||
}
|
||||
|
||||
int main( int argc, char *argv[] )
|
||||
{
|
||||
if( mouse_start_driver( argc, argv ) ) {
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
mouse_signal_handler( );
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
117
devu/class/mouse/mouse.h
Обычный файл
117
devu/class/mouse/mouse.h
Обычный файл
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* (c) 2010-2019, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
*/
|
||||
|
||||
// Module Description: header for mouse 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;
|
||||
};
|
||||
|
||||
// MOUSE CLASS DRIVER STRUCTURE
|
||||
typedef struct _mouse {
|
||||
iofunc_attr_t attr;
|
||||
TAILQ_ENTRY( _mouse ) 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
|
||||
} mouse_t;
|
||||
|
||||
typedef struct _mouse_ctrl {
|
||||
TAILQ_HEAD(,_mouse) 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;
|
||||
} mouse_ctrl_t;
|
||||
|
||||
// MOUSE HID DEFINITION
|
||||
#define USB_SUBCLASS_HID_BOOT 1
|
||||
#define USB_PROTOCOL_MOUSE 2
|
||||
|
||||
// MOUSE BUFFER REPORT DEFINITION
|
||||
typedef struct _mouse_report {
|
||||
_uint8 buttons;
|
||||
_uint8 horizontal_position;
|
||||
_uint8 vertical_position;
|
||||
} mouse_report_t;
|
||||
|
||||
// MOUSE DEFINITION
|
||||
#define MOUSE_OFF 0
|
||||
#define MOUSE_ON 1
|
||||
#define MOUSE_UNBLOCK 2
|
||||
#define MOUSE_PRESENT 4
|
||||
|
||||
#define MOUSE_CONTROL_EP 1
|
||||
#define MOUSE_INTIN_EP 2
|
||||
|
||||
#define MOUSE_BUTTON_1 1
|
||||
#define MOUSE_BUTTON_2 2
|
||||
#define MOUSE_BUTTON_3 4
|
||||
#define MOUSE_BUTTON_LAST_1 8
|
||||
#define MOUSE_BUTTON_LAST_2 0x10
|
||||
#define MOUSE_BUTTON_LAST_3 0x20
|
||||
#define MOUSE_INCREMENTS 5
|
||||
|
||||
#define MOUSE_MOVE 1
|
||||
#define MOUSE_LEFT_PRESSED 2
|
||||
#define MOUSE_LEFT_RELEASED 4
|
||||
#define MOUSE_RIGHT_PRESSED 8
|
||||
#define MOUSE_RIGHT_RELEASED 0x10
|
||||
#define MOUSE_MIDDLE_PRESSED 0x20
|
||||
#define MOUSE_MIDDLE_RELEASED 0x40
|
||||
|
||||
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 );
|
7
devu/class/mouse/pinfo.mk
Обычный файл
7
devu/class/mouse/pinfo.mk
Обычный файл
@ -0,0 +1,7 @@
|
||||
#
|
||||
# (c) 2010, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
#
|
||||
|
||||
define PINFO
|
||||
PINFO DESCRIPTION=Mouse class driver
|
||||
endef
|
2
devu/class/mouse/ppc/Makefile
Обычный файл
2
devu/class/mouse/ppc/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/mouse/ppc/be.spe/Makefile
Обычный файл
1
devu/class/mouse/ppc/be.spe/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/mouse/ppc/be/Makefile
Обычный файл
1
devu/class/mouse/ppc/be/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
2
devu/class/mouse/x86/Makefile
Обычный файл
2
devu/class/mouse/x86/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/mouse/x86/o/Makefile
Обычный файл
1
devu/class/mouse/x86/o/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
2
devu/class/printer/Makefile
Обычный файл
2
devu/class/printer/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=CPU
|
||||
include recurse.mk
|
2
devu/class/printer/arm/Makefile
Обычный файл
2
devu/class/printer/arm/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/printer/arm/le.v7/Makefile
Обычный файл
1
devu/class/printer/arm/le.v7/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/printer/arm/le/Makefile
Обычный файл
1
devu/class/printer/arm/le/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
13
devu/class/printer/devu-prn.use
Обычный файл
13
devu/class/printer/devu-prn.use
Обычный файл
@ -0,0 +1,13 @@
|
||||
%C Class Driver for USB printers.
|
||||
|
||||
Syntax:
|
||||
devu-prn [options*] &
|
||||
|
||||
Options:
|
||||
-n name Set device name. default "/dev/usbpar0"
|
||||
-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-prn &
|
2
devu/class/printer/e2k/Makefile
Обычный файл
2
devu/class/printer/e2k/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/printer/e2k/le/Makefile
Обычный файл
1
devu/class/printer/e2k/le/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
2
devu/class/printer/mips/Makefile
Обычный файл
2
devu/class/printer/mips/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/printer/mips/be/Makefile
Обычный файл
1
devu/class/printer/mips/be/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/printer/mips/le.mc/Makefile
Обычный файл
1
devu/class/printer/mips/le.mc/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/printer/mips/le/Makefile
Обычный файл
1
devu/class/printer/mips/le/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
5
devu/class/printer/override.mk
Обычный файл
5
devu/class/printer/override.mk
Обычный файл
@ -0,0 +1,5 @@
|
||||
#
|
||||
# (c) 2010, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
#
|
||||
|
||||
SECTION=prn
|
7
devu/class/printer/pinfo.mk
Обычный файл
7
devu/class/printer/pinfo.mk
Обычный файл
@ -0,0 +1,7 @@
|
||||
#
|
||||
# (c) 2010, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
#
|
||||
|
||||
define PINFO
|
||||
PINFO DESCRIPTION=Printer class driver
|
||||
endef
|
2
devu/class/printer/ppc/Makefile
Обычный файл
2
devu/class/printer/ppc/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/printer/ppc/be.spe/Makefile
Обычный файл
1
devu/class/printer/ppc/be.spe/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
1
devu/class/printer/ppc/be/Makefile
Обычный файл
1
devu/class/printer/ppc/be/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
736
devu/class/printer/printer.c
Обычный файл
736
devu/class/printer/printer.c
Обычный файл
@ -0,0 +1,736 @@
|
||||
/*
|
||||
* (c) 2010-2019, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
*/
|
||||
|
||||
// Module Description: printer class driver
|
||||
|
||||
#include <printer.h>
|
||||
|
||||
prn_ctrl_t PrnCtrl;
|
||||
|
||||
int prn_free( prn_t *prn )
|
||||
{
|
||||
int status;
|
||||
|
||||
if( prn->ep_out ) { // Stop the Bulk Out endpoint
|
||||
usbd_abort_pipe( prn->ep_out );
|
||||
}
|
||||
|
||||
if( prn->ep_in ) { // Stop the Bulk In endpoint
|
||||
usbd_abort_pipe( prn->ep_in );
|
||||
}
|
||||
|
||||
pthread_sleepon_lock( );
|
||||
prn->status &= ~PRN_PRESENT;
|
||||
pthread_sleepon_signal( &prn->urb );
|
||||
pthread_sleepon_unlock( );
|
||||
|
||||
if( status = rsrcdbmgr_devno_detach( prn->attr.rdev, 0 ) ) {
|
||||
fprintf( stderr, "prn_free: rsrcddbmgr_devno_detach %d\n", errno );
|
||||
}
|
||||
if( status = resmgr_detach( PrnCtrl.dispatch, prn->resmgr_id, _RESMGR_DETACH_ALL | _RESMGR_DETACH_CLOSE ) ) {
|
||||
fprintf( stderr, "prn_free: resmgr_detach %d\n", status );
|
||||
}
|
||||
usbd_free( prn->buffer );
|
||||
usbd_free_urb( prn->urb );
|
||||
TAILQ_REMOVE( &PrnCtrl.dlist, prn, dlink );
|
||||
if( status = usbd_detach( prn->device ) ) {
|
||||
fprintf( stderr, "prn_free: pending I/O\n" );
|
||||
}
|
||||
return( status );
|
||||
}
|
||||
|
||||
void prn_signal_handler( )
|
||||
{
|
||||
siginfo_t info;
|
||||
sigset_t set;
|
||||
prn_t *prn;
|
||||
prn_t *nprn;
|
||||
|
||||
sigfillset( &set );
|
||||
sigdelset( &set, SIGTERM );
|
||||
sigprocmask( SIG_BLOCK, &set, NULL );
|
||||
|
||||
sigemptyset( &set );
|
||||
sigaddset( &set, SIGTERM );
|
||||
while( SignalWaitinfo( &set, &info ) == -1 )
|
||||
;
|
||||
|
||||
for( prn = TAILQ_FIRST( &PrnCtrl.dlist ); prn; prn = nprn ) {
|
||||
nprn = TAILQ_NEXT( prn, dlink );
|
||||
prn_free( prn );
|
||||
}
|
||||
}
|
||||
|
||||
void prn_bulk_cbf( struct usbd_urb *urb, struct usbd_pipe *pipe, void *hdl )
|
||||
{
|
||||
pipe = pipe, hdl = hdl;
|
||||
|
||||
pthread_sleepon_lock( );
|
||||
pthread_sleepon_signal( urb );
|
||||
pthread_sleepon_unlock( );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int prn_bulk_wait( prn_t *prn, struct usbd_urb *urb, struct usbd_pipe *pipe )
|
||||
{
|
||||
_uint32 ustatus;
|
||||
_uint32 alen;
|
||||
|
||||
pthread_sleepon_lock( );
|
||||
while( usbd_urb_status( urb, &ustatus, &alen ) == EBUSY &&
|
||||
!( prn->status & PRN_UNBLOCK ) ) {
|
||||
pthread_sleepon_wait( urb );
|
||||
}
|
||||
pthread_sleepon_unlock( );
|
||||
|
||||
// check for a stall condition and clear it
|
||||
if( ( ustatus & USBD_USB_STATUS_MASK ) == USBD_STATUS_STALL ) {
|
||||
usbd_reset_pipe( pipe );
|
||||
}
|
||||
|
||||
if( prn->status & PRN_UNBLOCK ) {
|
||||
return( EINTR );
|
||||
}
|
||||
|
||||
return( ( ustatus & USBD_URB_STATUS_MASK ) == USBD_STATUS_CMP ? EOK : EIO );
|
||||
}
|
||||
|
||||
int prn_io( prn_t *prn, struct usbd_pipe *pipe, _uint32 flags, _uint8 *buffer, _uint32 length )
|
||||
{
|
||||
_uint32 status;
|
||||
|
||||
usbd_setup_bulk( prn->urb, flags, buffer, length );
|
||||
if( ( status = usbd_io( prn->urb, pipe, prn_bulk_cbf, prn, USBD_TIME_INFINITY ) ) == EOK ) {
|
||||
return( prn_bulk_wait( prn, prn->urb, pipe ) );
|
||||
}
|
||||
return( status );
|
||||
}
|
||||
|
||||
int prn_device_id( prn_t *prn, char *buffer, uint32_t length )
|
||||
{
|
||||
_uint32 status;
|
||||
struct usbd_urb *urb;
|
||||
|
||||
if( urb = usbd_alloc_urb( NULL ) ) {
|
||||
usbd_setup_vendor( urb, URB_DIR_IN, 0, USB_TYPE_CLASS | USB_RECIPIENT_INTERFACE, 0, 0, buffer, length );
|
||||
if( ( status = usbd_io( urb, prn->ep_cntl, NULL, prn, USBD_TIME_INFINITY ) ) == EOK ) {
|
||||
}
|
||||
usbd_free_urb( urb );
|
||||
}
|
||||
else {
|
||||
status = ENOMEM;
|
||||
}
|
||||
|
||||
return( status );
|
||||
}
|
||||
|
||||
int prn_reset( prn_t *prn )
|
||||
{
|
||||
_uint32 status;
|
||||
struct usbd_urb *urb;
|
||||
|
||||
// Note: version 1.0 of the spec incorrectly stated that
|
||||
// the recipient should be other, version 1.1 states that
|
||||
// it should be interface
|
||||
|
||||
status = ENOMEM;
|
||||
if( urb = usbd_alloc_urb( NULL ) ) {
|
||||
usbd_setup_vendor( urb, URB_DIR_OUT, PRN_SOFT_RESET, USB_TYPE_CLASS |
|
||||
( ( prn->bcdUSB & 0x10 ) ? USB_RECIPIENT_INTERFACE : USB_RECIPIENT_OTHER ),
|
||||
0, 0, NULL, 0 );
|
||||
if( ( status = usbd_io( urb, prn->ep_cntl, NULL, prn, USBD_TIME_INFINITY ) ) == EOK ) {
|
||||
}
|
||||
usbd_free_urb( urb );
|
||||
}
|
||||
|
||||
return( status );
|
||||
}
|
||||
|
||||
int prn_status( prn_t *prn )
|
||||
{
|
||||
_uint32 status;
|
||||
struct usbd_urb *urb;
|
||||
_uint8 *buffer;
|
||||
|
||||
status = ENOMEM;
|
||||
if( urb = usbd_alloc_urb( NULL ) ) {
|
||||
if( buffer = usbd_alloc( 1 ) ) {
|
||||
usbd_setup_vendor( urb, URB_DIR_IN, 1, USB_TYPE_CLASS | USB_RECIPIENT_INTERFACE, 0, 0, buffer, 1 );
|
||||
if( ( status = usbd_io( urb, prn->ep_cntl, NULL, prn, USBD_TIME_INFINITY ) ) == EOK ) {
|
||||
prn->query_status = ( prn->query_status & ~0xff ) | *buffer;
|
||||
}
|
||||
usbd_free( buffer );
|
||||
}
|
||||
usbd_free_urb( urb );
|
||||
}
|
||||
|
||||
return( status );
|
||||
}
|
||||
|
||||
int prn_io_unblock( resmgr_context_t *ctp, io_pulse_t *msg, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
prn_t *prn;
|
||||
|
||||
prn = (prn_t *)ocb->attr;
|
||||
|
||||
pthread_sleepon_lock( );
|
||||
prn->status |= PRN_UNBLOCK;
|
||||
pthread_sleepon_signal( prn->urb );
|
||||
pthread_sleepon_unlock( );
|
||||
|
||||
return( _RESMGR_NOREPLY );
|
||||
}
|
||||
|
||||
int prn_io_open( resmgr_context_t *ctp, io_open_t *msg, RESMGR_HANDLE_T *handle, void *extra )
|
||||
{
|
||||
prn_t *prn;
|
||||
int status;
|
||||
|
||||
prn = (prn_t *)handle;
|
||||
|
||||
if( !( prn->status & PRN_PRESENT ) ) {
|
||||
return( ENODEV );
|
||||
}
|
||||
|
||||
if( status = iofunc_open_default( ctp, msg, handle, extra ) ) {
|
||||
return( status );
|
||||
}
|
||||
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
int prn_io_close( resmgr_context_t *ctp, void *reserved, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
prn_t *prn;
|
||||
|
||||
prn = (prn_t *)ocb->attr;
|
||||
|
||||
iofunc_attr_lock( ocb->attr );
|
||||
if( iofunc_ocb_detach( ctp, ocb ) & IOFUNC_OCB_LAST_WRITER ) {
|
||||
// terminate the printer transfer with a null Bulk Out packet
|
||||
if( prn->status & PRN_PRESENT ) {
|
||||
if( prn_io( prn, prn->ep_out, URB_DIR_OUT, prn->buffer, 0 ) ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
iofunc_ocb_free( ocb );
|
||||
iofunc_attr_unlock( &prn->attr );
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
int prn_io_read( resmgr_context_t *ctp, io_read_t *msg, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
prn_t *prn;
|
||||
_uint32 pos;
|
||||
_uint8 *ibuf;
|
||||
_uint32 nbytes;
|
||||
_uint32 status;
|
||||
_uint32 alen;
|
||||
|
||||
prn = (prn_t *)ocb->attr;
|
||||
pos = 0;
|
||||
ibuf = prn->buffer;
|
||||
nbytes = msg->i.nbytes;
|
||||
|
||||
if( !( prn->status & PRN_PRESENT ) ) {
|
||||
return( ENODEV );
|
||||
}
|
||||
|
||||
if( prn->protocol != USB_PROTOCOL_PRN_BIDIR ) {
|
||||
return( ENXIO );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
if( atomic_set_value( &prn->status, PRN_READING ) & PRN_READING ) {
|
||||
return( EBUSY );
|
||||
}
|
||||
|
||||
prn->status &= ~PRN_UNBLOCK;
|
||||
while( 1 ) {
|
||||
if( status = prn_io( prn, prn->ep_in, URB_DIR_IN, ibuf, min( nbytes, MAX_PRN_BUFFER ) ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
usbd_urb_status( prn->urb, NULL, &alen );
|
||||
resmgr_msgwrite( ctp, ibuf, alen, pos );
|
||||
nbytes -= alen;
|
||||
pos += alen;
|
||||
|
||||
if( prn->status & PRN_UNBLOCK ) {
|
||||
status = EINTR;
|
||||
break;
|
||||
}
|
||||
|
||||
if( !nbytes || !alen ) {
|
||||
atomic_clr_value( &prn->status, PRN_READING );
|
||||
_IO_SET_READ_NBYTES( ctp, pos );
|
||||
return( EOK );
|
||||
}
|
||||
}
|
||||
|
||||
atomic_clr_value( &prn->status, PRN_READING );
|
||||
return( status );
|
||||
}
|
||||
|
||||
int prn_io_write( resmgr_context_t *ctp, io_write_t *msg, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
prn_t *prn;
|
||||
uint8_t *ibuf;
|
||||
uint8_t *obuf;
|
||||
int off, iidx, oidx;
|
||||
int rlen;
|
||||
int ilen;
|
||||
int opost;
|
||||
int olen;
|
||||
int status;
|
||||
|
||||
prn = (prn_t *)ocb->attr;
|
||||
rlen = msg->i.nbytes;
|
||||
|
||||
if( !( prn->status & PRN_PRESENT ) ) {
|
||||
return( ENODEV );
|
||||
}
|
||||
|
||||
if( ( msg->i.xtype & _IO_XTYPE_MASK ) != _IO_XTYPE_NONE ) {
|
||||
return( EINVAL );
|
||||
}
|
||||
|
||||
if( !( ocb->ioflag & _IO_FLAG_WR ) ) {
|
||||
return( EBADF );
|
||||
}
|
||||
|
||||
ocb->flags |= IOFUNC_ATTR_ATIME;
|
||||
|
||||
if( rlen == 0 ) {
|
||||
_IO_SET_WRITE_NBYTES( ctp, 0 );
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
if( atomic_set_value( &prn->status, PRN_WRITING ) & PRN_WRITING ) {
|
||||
return( EBUSY );
|
||||
}
|
||||
|
||||
prn->status &= ~PRN_UNBLOCK;
|
||||
opost = prn->tios.c_oflag & OPOST;
|
||||
off = sizeof( io_write_t );
|
||||
ibuf = prn->buffer;
|
||||
obuf = ibuf + ( opost ? 512 : 0 );
|
||||
while( rlen ) {
|
||||
ilen = ( rlen <= MAX_PRN_BUFFER ) ? rlen : MAX_PRN_BUFFER;
|
||||
if( ( olen = resmgr_msgread( ctp, ibuf, ilen, off ) ) != ilen ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if( opost ) {
|
||||
for( iidx = 0, oidx = 0; iidx < ilen; iidx++, oidx++ ) {
|
||||
if( ibuf[iidx] == 0xa ) {
|
||||
obuf[oidx++] = 0xd;
|
||||
olen++;
|
||||
}
|
||||
obuf[oidx] = ibuf[iidx];
|
||||
}
|
||||
}
|
||||
|
||||
if( status = prn_io( prn, prn->ep_out, URB_DIR_OUT, obuf, olen ) ) {
|
||||
atomic_clr_value( &prn->status, PRN_WRITING );
|
||||
return( status );
|
||||
}
|
||||
rlen -= ilen;
|
||||
off += MAX_PRN_BUFFER;
|
||||
}
|
||||
|
||||
atomic_clr_value( &prn->status, PRN_WRITING );
|
||||
_IO_SET_WRITE_NBYTES( ctp, msg->i.nbytes - rlen );
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
int prn_io_devctl( resmgr_context_t *ctp, io_devctl_t *msg, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
prn_t *prn;
|
||||
uint32_t *data;
|
||||
int nbytes;
|
||||
int status;
|
||||
|
||||
nbytes = 0;
|
||||
data = (uint32_t *)_DEVCTL_DATA( msg->i );
|
||||
prn = (prn_t *)ocb->attr;
|
||||
|
||||
if( !( prn->status & PRN_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, &prn->tios, nbytes );
|
||||
break;
|
||||
|
||||
case DCMD_CHR_TCSETATTR:
|
||||
nbytes = sizeof( struct termios );
|
||||
memcpy( &prn->tios, data, nbytes );
|
||||
break;
|
||||
|
||||
case DCMD_CHR_TCFLUSH:
|
||||
break;
|
||||
|
||||
case DCMD_CHR_TTYINFO: {
|
||||
struct _ttyinfo *ttyinfo;
|
||||
|
||||
ttyinfo = (struct _ttyinfo *)data;
|
||||
sprintf( ttyinfo->ttyname, "/dev/%s%d", PrnCtrl.prefix, prn->devnum );
|
||||
ttyinfo->opencount = prn->attr.count;
|
||||
nbytes = sizeof( *ttyinfo );
|
||||
break;
|
||||
}
|
||||
|
||||
case DCMD_CHR_LINESTATUS:
|
||||
prn_status( prn );
|
||||
*data = prn->query_status;
|
||||
nbytes = sizeof( *data );
|
||||
break;
|
||||
|
||||
case DCMD_CHR_PARCTL:
|
||||
if( *data & 0x4 ) {
|
||||
status = prn_reset( prn );
|
||||
}
|
||||
break;
|
||||
|
||||
case DCMD_CHR_SERCTL:
|
||||
break;
|
||||
|
||||
case DCMD_CHR_PNPTEXT: {
|
||||
char *id;
|
||||
|
||||
if( id = usbd_alloc( MAX_PRN_DEVICE_NAME ) ) {
|
||||
prn_device_id( prn, id, MAX_PRN_DEVICE_NAME );
|
||||
nbytes = min( ENDIAN_BE16( *((uint16_t *)id ) ), msg->i.nbytes );
|
||||
strncpy( (void *)data, id + 2, nbytes );
|
||||
usbd_free( id );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
status = ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
msg->o.ret_val = status;
|
||||
return( _RESMGR_PTR( ctp, &msg->o, sizeof( msg->o ) + nbytes ) );
|
||||
}
|
||||
|
||||
int prn_get_devnum( )
|
||||
{
|
||||
int cnt;
|
||||
int match;
|
||||
prn_t *prn;
|
||||
|
||||
for( cnt = 0; cnt < 16; cnt++ ) {
|
||||
for( match = 0, prn = TAILQ_FIRST( &PrnCtrl.dlist ); prn; prn = TAILQ_NEXT( prn, dlink ) ) {
|
||||
if( minor( prn->devnum ) == cnt ) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( !match ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return( cnt );
|
||||
}
|
||||
|
||||
int prn_io_lock_ocb( resmgr_context_t *ctp, void *reserved, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
int prn_io_unlock_ocb( resmgr_context_t *ctp, void *reserved, RESMGR_OCB_T *ocb )
|
||||
{
|
||||
return( EOK );
|
||||
}
|
||||
|
||||
int prn_resmgr_attach( prn_t *prn )
|
||||
{
|
||||
char name[255];
|
||||
|
||||
// setup termios structure
|
||||
prn->tios.c_oflag = 0; // OPOST;
|
||||
prn->query_status = 0x418;
|
||||
iofunc_attr_init( &prn->attr, 0600 | S_IFCHR, 0, 0 );
|
||||
iofunc_func_init( _RESMGR_CONNECT_NFUNCS, &prn->resmgr_connect_funcs, _RESMGR_IO_NFUNCS, &prn->resmgr_io_funcs );
|
||||
if( ( prn->attr.rdev = rsrcdbmgr_devno_attach( "usb", -1, 0 ) ) != -1 ) {
|
||||
prn->devnum = prn_get_devnum( );
|
||||
sprintf( name, "/dev/%s%d", PrnCtrl.prefix, prn->devnum );
|
||||
prn->resmgr_connect_funcs.open = prn_io_open;
|
||||
prn->resmgr_io_funcs.close_ocb = prn_io_close;
|
||||
prn->resmgr_io_funcs.unlock_ocb = prn_io_unlock_ocb;
|
||||
prn->resmgr_io_funcs.lock_ocb = prn_io_lock_ocb;
|
||||
prn->resmgr_io_funcs.read = prn_io_read;
|
||||
prn->resmgr_io_funcs.write = prn_io_write;
|
||||
prn->resmgr_io_funcs.devctl = prn_io_devctl;
|
||||
prn->resmgr_io_funcs.unblock = prn_io_unblock;
|
||||
if( ( prn->resmgr_id = resmgr_attach( PrnCtrl.dispatch, NULL, name, _FTYPE_ANY, 0,
|
||||
&prn->resmgr_connect_funcs, &prn->resmgr_io_funcs, &prn->attr ) ) != -1 ) {
|
||||
resmgr_devino( prn->resmgr_id, &prn->io_mount.dev, &prn->attr.inode );
|
||||
return( EOK );
|
||||
}
|
||||
else {
|
||||
fprintf( stderr, "PRN: resmgr_attach\n" );
|
||||
}
|
||||
rsrcdbmgr_devno_detach( prn->attr.rdev, 0 );
|
||||
}
|
||||
else {
|
||||
fprintf( stderr, "Unable to acquire devno\n" );
|
||||
}
|
||||
|
||||
return( EIO );
|
||||
}
|
||||
|
||||
int prn_parse_descriptors( prn_t *prn )
|
||||
{
|
||||
_uint32 eix;
|
||||
_uint32 scan;
|
||||
_uint32 found;
|
||||
usbd_descriptors_t *desc;
|
||||
usbd_device_descriptor_t *ddesc;
|
||||
usbd_interface_descriptor_t *idesc;
|
||||
struct usbd_desc_node *dev, *ifc, *ept;
|
||||
int alternate;
|
||||
|
||||
scan = PRN_CONTROL_EP | PRN_BULKOUT_EP;
|
||||
found = 0;
|
||||
|
||||
if( ddesc = usbd_device_descriptor( prn->device, &dev ) ) {
|
||||
prn->bcdUSB = ddesc->bcdUSB;
|
||||
// look for interface with bi-directional or uni-directional protocol (No support for IEEE 1284.4 multi function devices)
|
||||
for ( alternate = 0 ; ( idesc = usbd_interface_descriptor( prn->device, prn->instance.config, prn->instance.iface, alternate, &ifc ) ) ; alternate++ ) {
|
||||
if( (idesc->bInterfaceProtocol != USB_PROTOCOL_PRN_BIDIR) && (idesc->bInterfaceProtocol != USB_PROTOCOL_PRN_UNIDIR) )
|
||||
continue;
|
||||
|
||||
if( ( prn->protocol = idesc->bInterfaceProtocol ) == USB_PROTOCOL_PRN_BIDIR ) {
|
||||
scan |= PRN_BULKIN_EP;
|
||||
}
|
||||
usbd_select_interface( prn->device, prn->instance.iface, alternate );
|
||||
for( eix = 0; ( desc = usbd_parse_descriptors( prn->device, ifc, USB_DESC_ENDPOINT, eix, &ept ) ) != NULL; ++eix ) {
|
||||
switch( desc->endpoint.bmAttributes ) {
|
||||
case USB_ATTRIB_CONTROL:
|
||||
if( usbd_open_pipe( prn->device, desc, &prn->ep_cntl ) == EOK ) {
|
||||
found |= PRN_CONTROL_EP;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_ATTRIB_ISOCHRONOUS:
|
||||
break;
|
||||
|
||||
case USB_ATTRIB_BULK:
|
||||
switch( desc->endpoint.bEndpointAddress & USB_ENDPOINT_IN ) {
|
||||
case USB_ENDPOINT_OUT:
|
||||
if( usbd_open_pipe( prn->device, desc,
|
||||
&prn->ep_out ) == EOK ) {
|
||||
found |= PRN_BULKOUT_EP;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_IN:
|
||||
if( ( scan & PRN_BULKIN_EP ) &&
|
||||
usbd_open_pipe( prn->device, desc,
|
||||
&prn->ep_in ) == EOK ) {
|
||||
found |= PRN_BULKIN_EP;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_ATTRIB_INTERRUPT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( found == scan )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return( ( found == scan ) ? EOK : ENODEV );
|
||||
}
|
||||
|
||||
void prn_insertion( struct usbd_connection *connection, usbd_device_instance_t *instance )
|
||||
{
|
||||
prn_t *prn;
|
||||
struct usbd_device *device;
|
||||
int status;
|
||||
if( ( status = usbd_attach( connection, instance, sizeof( prn_t ), &device ) ) == EOK ) {
|
||||
prn = usbd_device_extra( device );
|
||||
prn->device = device;
|
||||
prn->instance = *instance;
|
||||
if( prn_parse_descriptors( prn ) == EOK ) {
|
||||
if( prn->buffer = usbd_alloc( PRN_BUFFER_SIZE ) ) {
|
||||
if( prn->urb = usbd_alloc_urb( NULL ) ) {
|
||||
if( prn_resmgr_attach( prn ) == EOK ) {
|
||||
prn->status = PRN_PRESENT;
|
||||
TAILQ_INSERT_TAIL( &PrnCtrl.dlist, prn, dlink );
|
||||
return;
|
||||
}
|
||||
usbd_free_urb( prn->urb );
|
||||
}
|
||||
usbd_free( prn->buffer );
|
||||
}
|
||||
}
|
||||
usbd_detach( device );
|
||||
}
|
||||
}
|
||||
|
||||
void prn_removal( struct usbd_connection *connection, usbd_device_instance_t *instance )
|
||||
{
|
||||
struct usbd_device *device;
|
||||
prn_t *prn;
|
||||
|
||||
if( ( device = usbd_device_lookup( connection, instance ) ) != NULL ) {
|
||||
prn = usbd_device_extra( device );
|
||||
prn_free( prn );
|
||||
}
|
||||
}
|
||||
|
||||
int prn_resmgr_init( )
|
||||
{
|
||||
resmgr_attr_t attr;
|
||||
|
||||
if( procmgr_daemon( EXIT_SUCCESS, PROCMGR_DAEMON_NOCLOSE | PROCMGR_DAEMON_NODEVNULL ) == -1 ) {
|
||||
fprintf( stderr, "Prn: procmgr_daemon\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( ( PrnCtrl.dispatch = dispatch_create( ) ) == NULL ) {
|
||||
fprintf( stderr, "Unable to allocate dispatch context\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
memset( &PrnCtrl.pool_attr, 0, sizeof( PrnCtrl.pool_attr ) );
|
||||
if( ( PrnCtrl.pool_attr.attr = malloc( sizeof( *PrnCtrl.pool_attr.attr ) ) ) == NULL ) {
|
||||
fprintf( stderr, "Unable to alloc pool attr\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
pthread_attr_init( PrnCtrl.pool_attr.attr );
|
||||
pthread_attr_setstacksize( PrnCtrl.pool_attr.attr, 8192 );
|
||||
|
||||
PrnCtrl.pool_attr.handle = PrnCtrl.dispatch;
|
||||
PrnCtrl.pool_attr.context_alloc = resmgr_context_alloc;
|
||||
PrnCtrl.pool_attr.block_func = resmgr_block;
|
||||
PrnCtrl.pool_attr.handler_func = (void *)dispatch_handler;
|
||||
PrnCtrl.pool_attr.context_free = resmgr_context_free;
|
||||
PrnCtrl.pool_attr.lo_water = 1;
|
||||
PrnCtrl.pool_attr.hi_water = 2;
|
||||
PrnCtrl.pool_attr.increment = 1;
|
||||
PrnCtrl.pool_attr.maximum = 2;
|
||||
|
||||
if( ( PrnCtrl.thread_pool = thread_pool_create( &PrnCtrl.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( PrnCtrl.dispatch, &attr, NULL, 0, 0, NULL, NULL, NULL ) == -1 ) {
|
||||
fprintf( stderr, "Unable to attach name\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( thread_pool_start( PrnCtrl.thread_pool ) ) {
|
||||
fprintf( stderr, "Unable to initialize thread_pool\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int prn_start_driver( int argc, char *argv[] )
|
||||
{
|
||||
struct usbd_connection *connection;
|
||||
usbd_funcs_t funcs = { _USBDI_NFUNCS, prn_insertion, prn_removal, NULL };
|
||||
usbd_device_ident_t interest = { USBD_CONNECT_WILDCARD, USBD_CONNECT_WILDCARD, USB_CLASS_PRN, USB_SUBCLASS_PRN, USBD_CONNECT_WILDCARD };
|
||||
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( &PrnCtrl.dlist );
|
||||
PrnCtrl.prefix = "usbpar";
|
||||
|
||||
while( ( opt = getopt( argc, argv, "vn:s:w:" ) ) != -1 ) {
|
||||
switch( opt ) {
|
||||
case 'n':
|
||||
PrnCtrl.prefix = optarg;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
PrnCtrl.verbose++;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
parm.path = optarg;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
parm.connect_wait = strtol( optarg, 0, 0 );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( ( PrnCtrl.chid = ChannelCreate( _NTO_CHF_DISCONNECT | _NTO_CHF_UNBLOCK ) ) == -1 ||
|
||||
( PrnCtrl.coid = ConnectAttach( 0, 0, PrnCtrl.chid, _NTO_SIDE_CHANNEL, 0 ) ) == -1 ) {
|
||||
fprintf( stderr, "Unable to attach channel and connection\n" );
|
||||
return( errno );
|
||||
}
|
||||
|
||||
if( prn_resmgr_init( ) ) {
|
||||
fprintf( stderr, "Printer: Resmgr Init Failure\n" );
|
||||
return( errno );
|
||||
}
|
||||
|
||||
if( ( status = usbd_connect( &parm, &connection ) ) != EOK ) {
|
||||
fprintf( stderr, "Prn Class/init - %s\n", strerror( status ) );
|
||||
return( status );
|
||||
}
|
||||
|
||||
return( status );
|
||||
}
|
||||
|
||||
int main( int argc, char *argv[] )
|
||||
{
|
||||
if( prn_start_driver( argc, argv ) ) {
|
||||
exit( EXIT_FAILURE );
|
||||
}
|
||||
prn_signal_handler( );
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
93
devu/class/printer/printer.h
Обычный файл
93
devu/class/printer/printer.h
Обычный файл
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* (c) 2010-2019, SWD Embedded Systems Limited, http://www.kpda.ru
|
||||
*/
|
||||
|
||||
// Module Description: header for printer class driver
|
||||
|
||||
#include <share.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <atomic.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>
|
||||
|
||||
// PRINTER CLASS DRIVER STRUCTURE
|
||||
typedef struct _prn {
|
||||
iofunc_attr_t attr;
|
||||
TAILQ_ENTRY( _prn ) 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_in;
|
||||
struct usbd_pipe *ep_out;
|
||||
struct usbd_urb *urb;
|
||||
_uint32 bcdUSB;
|
||||
_uint32 protocol;
|
||||
_uint32 query_status;
|
||||
_uint8 *buffer;
|
||||
} prn_t;
|
||||
|
||||
typedef struct _prn_ctrl {
|
||||
TAILQ_HEAD(,_prn) dlist; // linked list of prn's
|
||||
_uint32 cflags;
|
||||
_uint32 verbose;
|
||||
char *prefix;
|
||||
int coid;
|
||||
int chid;
|
||||
thread_pool_t *thread_pool;
|
||||
dispatch_t *dispatch;
|
||||
thread_pool_attr_t pool_attr;
|
||||
} prn_ctrl_t;
|
||||
|
||||
// PRINTER CLASS DEFINITION
|
||||
#ifndef USB_CLASS_PRN
|
||||
#define USB_CLASS_PRN 7
|
||||
#endif
|
||||
#define USB_SUBCLASS_PRN 1
|
||||
#define USB_PROTOCOL_PRN_UNIDIR 1
|
||||
#define USB_PROTOCOL_PRN_BIDIR 2
|
||||
#define GET_DEVICE_ID 0
|
||||
#define GET_PORT_STATUS 1
|
||||
#define SOFT_RESET 2
|
||||
|
||||
#define PRN_OFF 0x00
|
||||
#define PRN_ON 0x01
|
||||
#define PRN_UNBLOCK 0x02
|
||||
#define PRN_PRESENT 0x04
|
||||
#define PRN_READING 0x08
|
||||
#define PRN_WRITING 0x10
|
||||
|
||||
#define PRN_CONTROL_EP 1
|
||||
#define PRN_BULKIN_EP 2
|
||||
#define PRN_BULKOUT_EP 4
|
||||
|
||||
#define MAX_PRN_BUFFER 512
|
||||
#define MAX_PRN_DEVICE_NAME 512
|
||||
#define PRN_MAX_ENDPOINT 16
|
||||
#define PRN_BUFFER_SIZE 1536
|
||||
|
||||
#define PRN_GET_DEVICE_ID 0
|
||||
#define PRN_GET_PORT_STATUS 1
|
||||
#define PRN_SOFT_RESET 2
|
2
devu/class/printer/x86/Makefile
Обычный файл
2
devu/class/printer/x86/Makefile
Обычный файл
@ -0,0 +1,2 @@
|
||||
LIST=VARIANT
|
||||
include recurse.mk
|
1
devu/class/printer/x86/o/Makefile
Обычный файл
1
devu/class/printer/x86/o/Makefile
Обычный файл
@ -0,0 +1 @@
|
||||
include ../../../common.mk
|
Загрузка…
Ссылка в новой задаче
Block a user