1
1
input/devi/hid/kbd.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);
}