1
1

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

Этот коммит содержится в:
Коммит 13333b0126
66 изменённых файлов: 3196 добавлений и 0 удалений

2
Makefile Обычный файл
Просмотреть файл

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

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 Обычный файл
Просмотреть файл

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

2
devu/class/Makefile Обычный файл
Просмотреть файл

@ -0,0 +1,2 @@
LIST=CLASS
include recurse.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 Обычный файл
Просмотреть файл

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

2
devu/class/keyboard/arm/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/keyboard/arm/le.v7/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/keyboard/arm/le/Makefile Обычный файл
Просмотреть файл

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

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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

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

1
devu/class/keyboard/e2k/le/Makefile Обычный файл
Просмотреть файл

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

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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

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

1
devu/class/keyboard/mips/be/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/keyboard/mips/le.mc/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/keyboard/mips/le/Makefile Обычный файл
Просмотреть файл

@ -0,0 +1 @@
include ../../../common.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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

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

1
devu/class/keyboard/ppc/be.spe/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/keyboard/ppc/be/Makefile Обычный файл
Просмотреть файл

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

2
devu/class/keyboard/x86/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/keyboard/x86/o/Makefile Обычный файл
Просмотреть файл

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

2
devu/class/mouse/Makefile Обычный файл
Просмотреть файл

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

2
devu/class/mouse/arm/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/mouse/arm/le.v7/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/mouse/arm/le/Makefile Обычный файл
Просмотреть файл

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

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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

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

1
devu/class/mouse/e2k/le/Makefile Обычный файл
Просмотреть файл

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

2
devu/class/mouse/mips/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/mouse/mips/be/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/mouse/mips/le.mc/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/mouse/mips/le/Makefile Обычный файл
Просмотреть файл

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

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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

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

1
devu/class/mouse/ppc/be.spe/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/mouse/ppc/be/Makefile Обычный файл
Просмотреть файл

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

2
devu/class/mouse/x86/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/mouse/x86/o/Makefile Обычный файл
Просмотреть файл

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

2
devu/class/printer/Makefile Обычный файл
Просмотреть файл

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

2
devu/class/printer/arm/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/printer/arm/le.v7/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/printer/arm/le/Makefile Обычный файл
Просмотреть файл

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

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 Обычный файл
Просмотреть файл

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

1
devu/class/printer/e2k/le/Makefile Обычный файл
Просмотреть файл

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

2
devu/class/printer/mips/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/printer/mips/be/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/printer/mips/le.mc/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/printer/mips/le/Makefile Обычный файл
Просмотреть файл

@ -0,0 +1 @@
include ../../../common.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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

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

1
devu/class/printer/ppc/be.spe/Makefile Обычный файл
Просмотреть файл

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

1
devu/class/printer/ppc/be/Makefile Обычный файл
Просмотреть файл

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

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 Обычный файл
Просмотреть файл

@ -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 Обычный файл
Просмотреть файл

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

1
devu/class/printer/x86/o/Makefile Обычный файл
Просмотреть файл

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