[an error occurred while processing this directive]
ps2.c
(«Телесистемы»: Конференция «Программируемые логические схемы и их применение»)

миниатюрный аудио-видеорекордер mAVR

Отправлено /гоша/ 26 августа 2004 г. 15:24
В ответ на: Например, у Атмеля на сайте, в разделе АВР, есть аппликуха по подключению ПС2-клавиатуры к микроконтроллеру. отправлено Сидоргек 25 августа 2004 г. 11:46


/*
* Copyright 2000, QNX Software Systems Ltd. All Rights Reserved
*
* This source code has been published by QNX Software Systems Ltd.
* (QSSL). However, any use, reproduction, modification, distribution
* or transfer of this software, or any software which includes or is
* based upon any of this code, is only permitted under the terms of
* the QNX Open Community License version 1.0 (see licensing.qnx.com
* for details) or as otherwise expressly authorized by a written license
* agreement from QSSL. For more information, please email licensing@qnx.com.
*/


/*
* ps2.c
*
* The ps/2 mouse protocol module.
*
*/
#include "devi.h"
#include "itf_parser.h"


#define SKIP_MAX (5) /* threshold for 0xff sequence ignorance */


#define FLAG_INIT 0x0100
#define FLAG_RESET 0x0200
#define FLAG_WHEEL_ON 0x0800
#define FLAG_BUTTONS5 0x1000

/* Protocol module private data */
struct private_data {
int flags; /* see valid values before */
struct packet_rel mp[3]; /* data buffer */
int state; /* current state (see ps2_input & ps2i_input */
unsigned long msec; /* last time stamp - we use it to filter dvice errors */
};


/* forward declarations */
static int ps2_init(input_module_t *module);
static int ps2_devctrl(input_module_t *module, int event, void *ptr);
static int ps2_reset(input_module_t *module);
static int ps2i_input(input_module_t *module, int num, void *arg);
static int ps2_input(input_module_t *module, int num, void *arg);
static int ps2_parm(input_module_t *module, int opt, char *optarg);
static int ps2_shutdown(input_module_t *module, int delay);

/* Our protocol module is represented by the following input_module_t data structure */

input_module_t ps2 = {
NULL,
NULL,
NULL,
0,
DEVI_CLASS_REL|DEVI_MODULE_TYPE_PROTO,
"Ps2",
__DATE__,
"",
NULL,
ps2_init,
ps2_reset,
ps2_input,
NULL,
NULL,
ps2_parm,
ps2_devctrl,
ps2_shutdown
};

/* 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 ps2_init(input_module_t *module)
{
struct private_data *dp = module->data;

input_module_t *down = module->down;

if(down && down->init)
(down->init)(down);

if(!module->data) {
if(!(dp = module->data = scalloc(sizeof *dp))) {
return (-1);
}
}

dp -> flags |= FLAG_WHEEL_ON;

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 ps2_devctrl(input_module_t *module, int event, void *ptr)
{
struct private_data *dp = module->data;
unsigned wheel;
input_module_t *down = module->down;
int rc = 0;

switch(event) {

case DEVCTL_GETDEVFLAGS:
*(unsigned short *)ptr = (dp->flags & FLAGS_GLOBAL);
break;

case DEVCTL_GETPTRBTNS:
*(unsigned long *)ptr = 5L;
break;

case DEVCTL_GETPTRCOORD:
*(unsigned char *)ptr='\02';
break;

case DEVCTL_SETMOUSETYPE:
{
int newtype = *(int *)ptr;
struct devctl_mouse_types mt;
if(down && down -> devctrl)
{
if((down -> devctrl)(down, DEVCTL_GETMOUSETYPE, &mt))
{
rc = -1;
break;
}
if(mt.curtype == newtype)
break; /* Nothing to do */
if((down -> devctrl)(down, DEVCTL_SETMOUSETYPE, &newtype))
{
rc = -1;
break;
}
ps2_reset(module);
}
else
rc = -1;
}
break;
case DEVCTL_GETMOUSETYPE:
if(NULL != ptr && down && down -> devctrl)
{
struct devctl_mouse_types * pmt = (struct devctl_mouse_types *)ptr;
if((down -> devctrl)(down, DEVCTL_GETMOUSETYPE, pmt))
rc = -1;
}
else
rc = -1;
break;
case DEVCTL_GETWHEEL:
if(NULL != ptr)
{
struct devctl_mouse_types * pmt = (struct devctl_mouse_types *)ptr;
if((down -> devctrl)(down, DEVCTL_GETMOUSETYPE, pmt) ||
(0 == pmt -> type))
rc = -1;
else
{
if (dp->flags & FLAG_WHEEL_ON)
wheel = 3;
else
wheel = 2;
*(unsigned *)ptr= wheel;
}
}
break;
case DEVCTL_SETWHEEL:
if(NULL != ptr)
{
wheel = *(unsigned *)ptr;
if (((wheel & 1) && !(dp->flags & FLAG_WHEEL_ON)) || /* Set wheel on */
(!(wheel & 1) && (dp->flags & FLAG_WHEEL_ON))) /* Set wheel off */
{
if(down && down -> devctrl)
{
int newtype = ((wheel & 1) ? 0x03 : 0x00);
if((down -> devctrl)(down, DEVCTL_SETMOUSETYPE, &newtype))
{
rc = -1;
break;
}
/* next reset tries to save previous type (we set it two lines ago) */
ps2_reset(module);
}
else
rc = -1;
}
}
break;

default:
if(down && down->devctrl)
rc = (down->devctrl)(down, event, ptr);
else
rc = (-1);
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 ps2_reset(input_module_t *module)
{
struct private_data *dp = module->data;
input_module_t *down = module->down;
input_module_t *up = module->up;
struct devctl_mouse_types mt;

dp -> state = 0; /* initial state of the state machine (see input functions)*/
if(down )
{ /* reset low level */
if(down -> reset)
(down -> reset)(down);
if(down -> devctrl)
(down -> devctrl)(down, DEVCTL_GETMOUSETYPE, &mt);
else
{ /* default */
mt.type = 0;
mt.curtype = 0;
}
if(verbosity >= 3)
printf("Mouse: type = %i, current type = %i\n", (int)mt.type, (int)mt.curtype);
if(mt.curtype > 0) /* This is a wheel mouse */
{
dp->flags |= FLAG_WHEEL_ON;
ps2.input = ps2i_input;
if(NULL != up)
{ /* change state of the filter layer */
int nWheelCode = 3;
up -> devctrl(up, DEVCTL_SETWHEEL, (void *)&nWheelCode);
}
}
else /* simple 2 or 3-button mouse */
{
ps2.input = ps2_input;
dp->flags &= ~FLAG_WHEEL_ON;
}
if(0x04 == mt.curtype) /* more than 3 buttons */
dp->flags |= FLAG_BUTTONS5;
}
dp->flags |= FLAG_INIT;

return (0);
}

/* Description: main protocol processing function. It will be called by the */
/* device layer to pass it data to process. Its job is to interpret */
/* the data according to the MS wheel mouse protocol, create a */
/* data structure, fill it in and hand it off to the filter layer */
/* module above it. The protocol is processed using simple state */
/* machine. State info is kept in module's private data */
/* 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 */
/* Comment : driver uses one of two input modules depending on device data */
/* protocol */
int ps2i_input(input_module_t *module, int num, void *arg)
{
unsigned char *p = (char *) arg;
struct private_data *dp = module->data;
input_module_t *up = module->up;
struct timespec t;
unsigned msec;
int zmove;
int nSkip = 0;

/* NOTE: in current implementation num always equal to 1 */
/* in order to make possible for state machine to trap data */
/* flow interruption checking time intervals between bytes */
/* in each sample */

if(dp->flags & FLAG_INIT)
{
int i = 0;

/* delay between bytes in a sample cannot be more than 150 msec */
clk_get((struct timespec *)&t);
msec = MSEC(t);

if((dp->state != 0) && (msec - dp->msec > 150)) {
if(verbosity >= 3)
fprintf(stderr, "Data timeout; state = %i, dtime = %i; reset mouse\n",
(int)(dp->state), (int)(msec-dp->msec));
dp -> flags &= ~FLAG_INIT;
ps2_reset(module);
return 0;
}

if(verbosity >= 4) {
printf("%s:Received %d bytes from %s\n",
module->name, num, module->down->name);
}

/* PS2 mouse packet
*
* D7 D6 D5 D4 D3 D2 D1 D0
* -----------------------
* 0 0 Y7 X7 1 M R L
* X7 X6 X5 X4 X3 X2 X1 X0
* Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
*
* If the wheel mouse is enabled we will get a fourth byte.
*
* Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0
*
* (M will be the wheel button)
*
* D7 and D6 are actually overflow bits but since this rarely
* happens we can attempt to sync up a packet relying on
* them being zero. D3 is stated as reserved in the PS/2 doc
* but is typically 1. Unfortunately older MS PS/2 mice set
* it to 0. The new ones set it to 1 however.
*
*/

for(; num; p++, num--) {

switch(dp->state) {

case 0: /* Buttons */

/* All mice after re-plug-in send 0xaa-0x00 */
/* to host; however some mice before that send */
/* short sequence of 0xff-s; to effectively */
/* process re-plugin we try to ignore this code*/
/* in 0-state; so far it works good */
if((0xff == *p) && (nSkip++ < SKIP_MAX))
continue;
nSkip = 0;

if ((*p & 0xc8) != 8) {
/* According to specification D3 == 1
assume an overflow means just that
keep the state machine in sync, but don't send
an event up */
dp -> flags &= ~FLAG_INIT;
if(verbosity >= 3)
fprintf(stderr, "ps2i: wrong byte comes 0x%02X; reset mouse\n", (int)*p);
ps2_reset(module);
return 0;
}

dp->mp[i].buttons = ((*p & 0x01) ?
_POINTER_BUTTON_LEFT : 0) |
((*p & 0x02) ?
_POINTER_BUTTON_RIGHT : 0) |
((*p & 0x04) ? _POINTER_BUTTON_MIDDLE : 0);

dp->mp[i].dy = (*p & 0x20) ? -1 : 1;
dp->mp[i].dx = (*p & 0x10) ? -1 : 1;

dp->state++;
dp->msec = msec;
break;

case 1: /* x-move */
dp->mp[i].dx = (dp->mp[i].dx & ~0x00ff) |
(*p & 0x00ff);
dp->state++;
if(verbosity >= 5)
printf("X=%i ", (int)(dp->mp[i].dx));
break;

case 2: /* y-move */
dp->mp[i].dy = (dp->mp[i].dy & ~0x00ff) |
(*p & 0x00ff);

dp->state++;
if(verbosity >= 5)
printf("Y=%i\n", (int)(dp->mp[i].dy));
break;

case 3:
/* extract & convert z-move */
zmove = (*p & 0x0007);
if(verbosity >= 5)
printf("4-th byte: 0x%02X\n", (int)*p);
dp->mp[i].flags |= PTR_Z_DATA;

if (*p & 0x08)
zmove |= (-1 & ~7);

dp -> mp[i].dz = zmove;
/* If mouse has more than 3 buttons - take their states ! */
if(dp->flags & FLAG_BUTTONS5)
dp->mp[i].buttons |= ((*p & 0x10) ?
_POINTER_BUTTON_4 : 0) |
((*p & 0x20) ?
_POINTER_BUTTON_5 : 0);

clk_get(&dp->mp[i].timestamp);
/* pass data to filter module */
if(++i >= 3) /* Buffer is full, send now */
{
(up->input)(up, 3, dp->mp);
i = 0;
}
else
if(num < 4) /* There is not enough bytes to combine new sample; */
{ /* Not delay send, do it now */
(up->input)(up, i, dp->mp);
i = 0;
}
/* and reset satate machine */
dp->state = 0;
break;
}
}
}

return (0);
}


/* Description: main protocol processing function for mice without wheels; see */
/* description for ps2i-input function for more details. */
/* 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 */
/* Comment : driver uses one of two input modules depending on device data */
/* protocol */
int ps2_input(input_module_t *module, int num, void *arg)
{
unsigned char *p = (char *) arg;
struct private_data *dp = module->data;
input_module_t *up = module->up;
struct timespec t;
unsigned msec;
int nSkip = 0;

if(dp->flags & FLAG_INIT) {
int i = 0;
clk_get((struct timespec *)&t);
msec = MSEC(t);

if((dp->state != 0) && (msec - dp->msec > 350)) {
if(verbosity >= 3)
fprintf(stderr, "Data timeout; state = %i, dtime = %i; reset mouse\n",
(int)(dp->state), (int)(msec-dp->msec));
dp -> flags &= ~FLAG_INIT;
ps2_reset(module);
return 0;
}

if(verbosity >= 4) {
printf("%s:Received %d bytes from %s\n",
module->name, num, module->down->name);
}

/* PS2 mouse packet
*
* D7 D6 D5 D4 D3 D2 D1 D0
* -----------------------
* 0 0 Y7 X7 1 M R L
* X7 X6 X5 X4 X3 X2 X1 X0
* Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
*
* If the wheel mouse is enabled we will get a fourth byte.
*
* Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0
*
* (M will be the wheel button)
*
* D7 and D6 are actually overflow bits but since this rarely
* happens we can attempt to sync up a packet relying on
* them being zero. D3 is stated as reserved in the PS/2 doc
* but is typically 1. Unfortunately older MS PS/2 mice set
* it to 0. The new ones set it to 1 however.
*
*/

for(; num; p++, num--) {

switch(dp->state) {

case 0: /* Buttons */
/* All mice after re-plug-in send 0xaa-0x00 */
/* to host; however some mice before that send */
/* short sequence of 0xff-s; to effectively */
/* process re-plugin we try to ignore this code*/
/* in 0-state; so far it works good */
if((0xff == *p) && (nSkip++ < SKIP_MAX))
continue;
nSkip = 0;
if ((*p & 0xc8) != 8) {
/* According to specification D3 == 1
assume an overflow means just that
keep the state machine in sync, but don't send
an event up */

dp -> flags &= ~FLAG_INIT;
if(verbosity >= 3)
fprintf(stderr, "ps2: wrong byte comes 0x%02X; reset mouse\n", (int)*p);
ps2_reset(module);
return 0;

}
dp->mp[i].buttons = ((*p & 0x01) ?
_POINTER_BUTTON_LEFT : 0) |
((*p & 0x02) ?
_POINTER_BUTTON_RIGHT : 0) |
((*p & 0x04) ? _POINTER_BUTTON_MIDDLE : 0);

dp->mp[i].dy = (*p & 0x20) ? -1 : 1;
dp->mp[i].dx = (*p & 0x10) ? -1 : 1;
dp->state++;
dp->msec = msec;
break;

case 1: /* x-move*/
dp->mp[i].dx = (dp->mp[i].dx & ~0x00ff) |
(*p & 0x00ff);
if(verbosity >= 5)
printf("X=%i ", (int)(dp->mp[i].dx));
dp->state++;
break;

case 2: /* y-move*/
dp->mp[i].dy = (dp->mp[i].dy & ~0x00ff) |
(*p & 0x00ff);
if(verbosity >= 5)
printf("Y=%i ", (int)(dp->mp[i].dy));

dp->mp[i].dz = 0;
clk_get(&dp->mp[i].timestamp);
/* pass data to filter module */
if(++i >= 3) /* Buffer is full, send now */
{
(up->input)(up, 3, dp->mp);
i = 0;
}
else
if(num < 4) /* There is not enough bytes to combine new sample; */
{ /* Not delay send, do it now */
(up->input)(up, i, dp->mp);
i = 0;
}
/* and reset satate machine */
dp->state = 0;
break;
}
}
}

return (0);
}


/* Description: this is a callback function for command line parameter processing */
/* (all valid parameters for device module are listed in ps2.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 */
/* Comment : we don't accept any parameter for this module at the protocol level */
int ps2_parm(input_module_t *module, int opt, char *optarg)
{
/* Now empty */
switch (opt)
{
default:
break;
}

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 */
/* Comment : Does nothing for the protocol level */
int ps2_shutdown(input_module_t *module, int delay)
{
return (0);
}


Составить ответ  |||  Конференция  |||  Архив

Ответы


Отправка ответа

Имя (обязательно): 
Пароль: 
E-mail: 

Тема (обязательно):
Сообщение:

Ссылка на URL: 
Название ссылки: 

URL изображения: 


Перейти к списку ответов  |||  Конференция  |||  Архив  |||  Главная страница  |||  Содержание  |||  Без кадра

E-mail: info@telesys.ru