333 строки
12 KiB
C
333 строки
12 KiB
C
/*
|
|
* (c) 2010, SWD Embedded Systems Limited, http://www.kpda.ru
|
|
*/
|
|
|
|
/*
|
|
* Предостережение:
|
|
*
|
|
* Предоставленный исходный код драйвера devi-hid рекомендуется использовать
|
|
* только для отладочных целей при разработке HID-драйверов. Для всех остальных
|
|
* задач следует использовать штатный системный драйвер devi-hid.
|
|
*
|
|
* В общем случае не существует задач, которые требуется решать в этом драйвере
|
|
* при поддержке нового оборудования (для этого должен быть написан/модифицирован
|
|
* отдельный драйвер ввода или HID-драйвер).
|
|
*/
|
|
|
|
/*
|
|
* kbd.c
|
|
*
|
|
* The HID USB keyboard combined protocol/device module.
|
|
*
|
|
*/
|
|
|
|
#include <sys/devi.h>
|
|
#include "hid.h"
|
|
#include "pthread.h"
|
|
|
|
|
|
/* forward declarations */
|
|
static int kbd_init(input_module_t *module);
|
|
static int kbd_devctrl(input_module_t *module, int event, void *ptr);
|
|
static int kbd_reset(input_module_t *module);
|
|
static int kbd_input(input_module_t *module, int num, void *arg);
|
|
static int kbd_parm(input_module_t *module, int opt, char *optarg);
|
|
static int kbd_shutdown(input_module_t *module, int delay);
|
|
|
|
/* Our protocol module is represented by the following input_module_t data structure */
|
|
|
|
input_module_t kbd = {
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
DEVI_CLASS_KBD | DEVI_MODULE_TYPE_PROTO | DEVI_MODULE_TYPE_DEVICE,
|
|
"Kbd",
|
|
__DATE__,
|
|
"k:f:p:u:",
|
|
NULL, /* initialized by us (in init) */
|
|
kbd_init,
|
|
kbd_reset,
|
|
kbd_input,
|
|
NULL,
|
|
NULL,
|
|
kbd_parm,
|
|
kbd_devctrl,
|
|
kbd_shutdown
|
|
};
|
|
|
|
#define FLAG_INIT 0x1000
|
|
#define FLAG_SYM 0x8000 /* DEvice level supplies valid symbols */
|
|
|
|
/* Protocol module private data */
|
|
struct data {
|
|
int flags;
|
|
int rate; /* kbd delay */
|
|
int delay; /* kbd rate */
|
|
void * hid_module_handle; /* HID module_handle */
|
|
int nDev; /* USB device number */
|
|
int fId; /* For debug mode (-f parameter) - write input to file */
|
|
int fifo; /* For debug mode (-p parameter) - write input to FIFO file */
|
|
char fifo_name[100];
|
|
};
|
|
|
|
void * open_pipe(void * parm)
|
|
{
|
|
struct data * dp = (struct data *)parm;
|
|
int pipe_no;
|
|
|
|
dp -> fifo = 0;
|
|
// Block until O_RDONLY pipe will be opened
|
|
pipe_no = open(dp -> fifo_name, O_WRONLY );
|
|
close(pipe_no);
|
|
// Wait a peer process re-opens pipe
|
|
sleep(1);
|
|
// Open non-blocked pipe
|
|
dp -> fifo = open(dp -> fifo_name, O_WRONLY | O_NONBLOCK );
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* Description: callback initialisation function; it is called when input module is */
|
|
/* initialising the input system */
|
|
/* Input : input_module_t * module - pointer to module descriptor */
|
|
/* Output : None */
|
|
/* Return : 0 if OK, otherwise - (-1) */
|
|
int kbd_init(input_module_t *module)
|
|
{
|
|
struct data *dp=module->data;
|
|
|
|
if(!module->data) {
|
|
if(!(dp = module->data = calloc(sizeof *dp, 1))) {
|
|
return -1;
|
|
}
|
|
dp->flags = 0;
|
|
dp->fId = 0;
|
|
dp -> fifo = 0;
|
|
dp -> rate = 33; /* In times per second * 10 */
|
|
dp -> delay= 500; /* In milliseconds */
|
|
signal(SIGPIPE, SIG_IGN);
|
|
}
|
|
|
|
dp -> nDev = HIDD_CONNECT_WILDCARD;
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* Description: this is a callback function for DEVCTRL command processing */
|
|
/* Input : input_module_t * module - pointer to module descriptor */
|
|
/* int event - DEVCTRL command code */
|
|
/* void * ptr - pointer to data exchange block */
|
|
/* Output : None */
|
|
/* Return : 0 if OK, otherwise -1 */
|
|
int kbd_devctrl(input_module_t *module,int event,void *ptr)
|
|
{
|
|
struct data *dp=module->data;
|
|
int rc = EOK;
|
|
|
|
switch(event)
|
|
{
|
|
case DEVCTL_RESET_KBD:
|
|
rc = ENOTSUP;
|
|
break;
|
|
case DEVCTL_GETKBD:
|
|
if(NULL != ptr)
|
|
{ // Get keyboard parameters - delay & rate
|
|
struct devctl_getkbd * pDevctl = (struct devctl_getkbd *)ptr;
|
|
pDevctl -> rate = dp -> rate;
|
|
pDevctl -> delay = dp -> delay;
|
|
}
|
|
break;
|
|
|
|
case DEVCTL_SETKBD:
|
|
if(NULL != ptr)
|
|
{
|
|
struct devctl_setkbd * pDevctl = (struct devctl_setkbd *)ptr;
|
|
dp -> delay = pDevctl -> delay;
|
|
dp -> rate = pDevctl -> rate;
|
|
}
|
|
default:
|
|
if(dp -> hid_module_handle)
|
|
rc = devi_hid_devctrl(dp -> hid_module_handle, event, ptr, HIDD_CONNECT_WILDCARD);
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/* Description: this callback funtion is called when the module is linked into the */
|
|
/* event bus; it is used to set initial module state on the protocol */
|
|
/* level */
|
|
/* Input : input_module_t * module - pointer to module descriptor */
|
|
/* Output : None */
|
|
/* Return : 0 if OK, otherwise -1 */
|
|
int kbd_reset(input_module_t *module)
|
|
{
|
|
struct data *dp = module->data;
|
|
struct devctl_setkbd devctl;
|
|
int rc = EOK;
|
|
|
|
if((dp->flags & FLAG_INIT) == 0)
|
|
{
|
|
if(NULL == (dp -> hid_module_handle = devi_hid_register_client(module, dp -> nDev)))
|
|
{
|
|
return (-1);
|
|
}
|
|
dp->flags |= FLAG_INIT;
|
|
}
|
|
else
|
|
{
|
|
if(module -> up)
|
|
rc = module -> up -> reset(module -> up);
|
|
if(EOK != rc)
|
|
return rc;
|
|
}
|
|
|
|
devctl.delay = dp -> delay;
|
|
devctl.rate = dp -> rate;
|
|
kbd_devctrl(module, DEVCTL_SETKBD, &devctl);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* Description: main protocol processing function. It will be called by the */
|
|
/* device layer to pass it data to process. Its job is very simple: */
|
|
/* just to hand data off to the filter layer module above it. */
|
|
/* Input : input_module_t * module - pointer to module descriptor */
|
|
/* int num - number of bytes to process */
|
|
/* void * arg - raw data to process */
|
|
/* Output : None */
|
|
/* Return : 0 if OK, otherwise -1 */
|
|
int kbd_input(input_module_t *module, int num, void *ptr)
|
|
{
|
|
struct data *dp=module->data;
|
|
input_module_t *up=module->up;
|
|
struct packet_kbd kbuf;
|
|
USBKCode *tmp=ptr;
|
|
_uint8 buf[10]; // Buffer for scan codes
|
|
int nLen;
|
|
int i, j;
|
|
|
|
if(dp->flags & FLAG_INIT)
|
|
{
|
|
|
|
kbuf.bMakeBreak = *tmp++;
|
|
clk_get(&kbuf.timestamp);
|
|
|
|
for(i = 1; i < (num / sizeof(USBKCode)); i++)
|
|
{
|
|
memset(&kbuf.key, 0x00, sizeof kbuf.key);
|
|
|
|
|
|
if(0 < dp -> fId)
|
|
write(dp -> fId, tmp, sizeof(USBKCode));
|
|
|
|
if(0 < dp -> fifo)
|
|
{
|
|
if(0 > write(dp -> fifo, tmp, sizeof(USBKCode)))
|
|
{
|
|
dp -> fifo = 0;
|
|
pthread_create(NULL, NULL, open_pipe, dp);
|
|
}
|
|
}
|
|
/* The device level supplies USB usages */
|
|
/* get scan codes for them */
|
|
kbuf.nUSBCode = 0;
|
|
nLen = sizeof(buf);
|
|
if(EOK == devi_usb_to_scan(*tmp, kbuf.bMakeBreak, buf, &nLen))
|
|
for(j = 0; j < nLen; ++j)
|
|
{
|
|
kbuf.key.key_scan = buf[j];
|
|
kbuf.key.flags = KEY_SCAN_VALID;
|
|
if(j == (nLen - 1)) // Last package carries USB code as well
|
|
kbuf.nUSBCode = *tmp;
|
|
(up->input)(up, 1, &kbuf);
|
|
}
|
|
else {
|
|
kbuf.nUSBCode = *tmp;
|
|
(up->input)(up, 1, &kbuf);
|
|
}
|
|
++tmp;
|
|
}
|
|
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* Description: this is a callback function for command line parameter processing */
|
|
/* (all valid parameters for device module are listed in kbd.args) */
|
|
/* Input : input_module_t * module - pointer to module descriptor */
|
|
/* int opt - parameter code */
|
|
/* char * optarg - optional parameter value */
|
|
/* Output : None */
|
|
/* Return : 0 if OK, otherwise -1 */
|
|
int kbd_parm(input_module_t *module,int opt,char *optarg)
|
|
{
|
|
struct data *dp=module->data;
|
|
|
|
switch(opt) {
|
|
case 'k': /* specify key repeat rate and delay */
|
|
dp->rate = strtol(optarg, (char **)&optarg, 10) * 10;
|
|
if(*optarg == '.' && *++optarg >= '0' && *optarg <= '9') {
|
|
dp->rate += *optarg++ - '0';
|
|
}
|
|
if ( dp->rate )
|
|
dp->rate = 10000/dp->rate; /* convert to ms delay between succesive reports */
|
|
if(*optarg == ',') {
|
|
dp->delay = strtol(++optarg, 0, 10);
|
|
}
|
|
break;
|
|
case 'f':
|
|
dp -> fId = open(optarg, O_CREAT | O_WRONLY | O_TRUNC,
|
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
|
break;
|
|
case 'p':
|
|
if(access(optarg, F_OK))
|
|
{
|
|
if(mkfifo(optarg, S_IRUSR | S_IWUSR))
|
|
{
|
|
printf("Cannot open FIFO (%s), error = %i\n", optarg, errno);
|
|
break;
|
|
}
|
|
printf ("Pipe %s has been created\n", optarg);
|
|
}
|
|
strcpy(dp -> fifo_name, optarg);
|
|
pthread_create(NULL, NULL, open_pipe, dp);
|
|
break;
|
|
case 'u':
|
|
if(NULL != optarg)
|
|
dp -> nDev = atoi(optarg);
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/* Description: this is a callback function which is called when resourse manager */
|
|
/* is shutting down */
|
|
/* Input : input_module_t * module - pointer to module descriptor */
|
|
/* int ms - program doesn't use this parameter */
|
|
/* Output : None */
|
|
/* Return : 0 if OK, otherwise -1 */
|
|
int kbd_shutdown(input_module_t *module, int delay)
|
|
{
|
|
struct data *dp = module->data;
|
|
if(NULL != dp)
|
|
{
|
|
if(0 < dp -> fId) /* if debug output file was created - close it */
|
|
close(dp -> fId);
|
|
if(0 < dp -> fifo) /* if debug output file was created - close it */
|
|
close(dp -> fifo);
|
|
if( NULL != dp -> hid_module_handle)
|
|
devi_unregister_hid_client(dp -> hid_module_handle);
|
|
}
|
|
return(0);
|
|
}
|