pnp.c revision b72771e8c6ba3b3d9ebdd7977730325131ae0f98
/*
* Copyright 1998 by Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Kazutaka YOKOTA not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Kazutaka YOKOTA makes no representations
* about the suitability of this software for any purpose. It is provided
* "as is" without express or implied warranty.
*
* KAZUTAKA YOKOTA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KAZUTAKA YOKOTA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define NEED_EVENTS
#include "inputstr.h"
#include "scrnintstr.h"
#include "xf86.h"
#include "xf86Priv.h"
#include "xf86Xinput.h"
#include "xf86_OSproc.h"
#include "xf86OSmouse.h"
#include "xf86_ansic.h"
#include "mouse.h"
#include "mousePriv.h"
#ifdef MOUSEINITDEBUG
# define DEBUG
# define EXTMOUSEDEBUG
#endif
/* serial PnP ID string */
typedef struct {
int revision; /* PnP revision, 100 for 1.00 */
char *eisaid; /* EISA ID including mfr ID and product ID */
char *serial; /* serial No, optional */
char *class; /* device class, optional */
char *compat; /* list of compatible drivers, optional */
char *description; /* product description, optional */
int neisaid; /* length of the above fields... */
int nserial;
int nclass;
int ncompat;
int ndescription;
} pnpid_t;
/* symbol table entry */
typedef struct {
char *name;
} symtab_t;
/*
* EzScroll returns PNP0F04 in the compatible device field; but it
* doesn't look compatible... XXX
*/
#ifdef notyet
#endif
#ifdef notyet
#endif
#ifdef notyet
#endif
#ifdef notyet
#endif
#ifdef notyet
#endif
{ NULL, PROT_UNKNOWN },
};
static const char *pnpSerial[] = {
"BaudRate", "1200",
"DataBits", "7",
"StopBits", "1",
"Parity", "None",
"FlowControl", "None",
"VTime", "0",
"VMin", "1",
};
static MouseProtocolID
{
symtab_t *t;
int len;
{
if (!prePNP) {
return (t->val);
}
} else
}
return PROT_UNKNOWN;
}
{
return val;
}
#if 1
if (last) {
|| (mPriv->disablePnPauto
#ifdef EXTMOUSEDEBUG
xf86ErrorF("Mouse: Disabling PnP\n");
#endif
return PROT_UNKNOWN;
}
}
#ifdef EXTMOUSEDEBUG
if (mPriv->disablePnPauto)
xf86ErrorF("Mouse: Enabling PnP\n");
#endif
return getPs2ProtocolPnP(pInfo);
else
return probePs2ProtocolPnP(pInfo);
#else
return PROT_UNKNOWN;
#endif
}
/*
* Try to elicit a PnP ID as described in
* Microsoft, Hayes: "Plug and Play External COM Device Specification,
* rev 1.00", 1995.
*
* The routine does not fully implement the COM Enumerator as per Section
* 2.1 of the document. In particular, we don't have idle state in which
* the driver software monitors the com port for dynamic connection or
* removal of a device at the port, because `moused' simply quits if no
* device is found.
*
* In addition, as PnP COM device enumeration procedure slightly has
* changed since its first publication, devices which follow earlier
* revisions of the above spec. may fail to respond if the rev 1.0
* procedure is used. XXX
*/
static int
{
int i;
char c;
#if 0
/*
* This is the procedure described in rev 1.0 of PnP COM device spec.
* Unfortunately, some devices which comform to earlier revisions of
* the spec gets confused and do not return the ID string...
*/
/* port initialization (2.1.2) */
return 0;
i |= XF86_M_DTR; /* DTR = 1 */
i &= ~XF86_M_RTS; /* RTS = 0 */
goto disconnect_idle;
usleep(200000);
(i & XF86_M_DSR) == 0)
goto disconnect_idle;
/* port setup, 1st phase (2.1.3) */
usleep(200000);
i = TIOCM_DTR; /* DTR = 1, RTS = 0 */
usleep(200000);
/* wait for response, 1st phase (2.1.4) */
i = TIOCM_RTS; /* DTR = 1, RTS = 1 */
/* try to read something */
/* port setup, 2nd phase (2.1.5) */
usleep(200000);
/* wait for respose, 2nd phase (2.1.6) */
/* try to read something */
goto connect_idle;
}
#else
/*
* This is a simplified procedure; it simply toggles RTS.
*/
return 0;
i |= XF86_M_DTR; /* DTR = 1 */
i &= ~XF86_M_RTS; /* RTS = 0 */
goto disconnect_idle;
usleep(200000);
/* wait for respose */
/* try to read something */
goto connect_idle;
#endif
/* collect PnP COM device ID (2.1.7) */
i = 0;
/* we may see "M", or "M3..." before `Begin ID' */
if (c == 'M')
if ((c == 0x08) || (c == 0x28)) { /* Begin ID */
buf[0] = c;
i = 1;
break;
}
if (*prePNP)
buf[i++] = c;
break;
}
if (i <= 0) {
/* we haven't seen `Begin ID' in time... */
goto connect_idle;
}
if (*prePNP)
return i;
++c; /* make it `End ID' */
for (;;) {
break;
if (buf[i++] == c) /* End ID */
break;
if (i >= 256)
break;
}
if (buf[i - 1] != c)
goto connect_idle;
return i;
/*
* According to PnP spec, we should set DTR = 1 and RTS = 0 while
* in idle state. But, `moused' shall set DTR = RTS = 1 and proceed,
* assuming there is something at the port even if it didn't
* respond to the PnP enumeration procedure.
*/
return 0;
}
static int
{
char s[3];
int offset;
int sum = 0;
int i, j;
id->ndescription = 0;
/* calculate checksum */
for (i = 0; i < len - 3; ++i) {
}
for (; i < len; ++i)
/* revision */
/* EISA vender and product ID */
/* option strings */
i = 10;
if (buf[i] == '\\') {
/* device serial # */
for (j = ++i; i < len; ++i) {
if (buf[i] == '\\')
break;
}
if (i >= len)
i -= 3;
if (i - j == 8) {
}
}
if (buf[i] == '\\') {
/* PnP class */
for (j = ++i; i < len; ++i) {
if (buf[i] == '\\')
break;
}
if (i >= len)
i -= 3;
if (i > j + 1) {
}
}
if (buf[i] == '\\') {
/* compatible driver */
for (j = ++i; i < len; ++i) {
if (buf[i] == '\\')
break;
}
/*
* PnP COM spec prior to v0.96 allowed '*' in this field,
* it's not allowed now; just ignore it.
*/
if (buf[j] == '*')
++j;
if (i >= len)
i -= 3;
if (i > j + 1) {
}
}
if (buf[i] == '\\') {
/* product description */
for (j = ++i; i < len; ++i) {
if (buf[i] == ';')
break;
}
if (i >= len)
i -= 3;
if (i > j + 1) {
id->ndescription = i - j;
}
}
/* checksum exists if there are any optional fields */
#if 0
/*
* Checksum error!!
* I found some mice do not comply with the PnP COM device
* spec regarding checksum... XXX
*/
return FALSE;
#endif
}
}
return TRUE;
}
/* We can only identify MS at the moment */
static MouseProtocolID
{
return PROT_MS;
return PROT_UNKNOWN;
}
static symtab_t *
{
symtab_t *t;
int i, j;
/* this is not a mouse! */
return NULL;
if (t->val != -1)
return t;
}
/*
* The 'Compatible drivers' field may contain more than one
* ID separated by ','.
*/
return NULL;
break;
if (i > j) {
if (t->val != -1)
return t;
}
}
return NULL;
}
static symtab_t *
char *s;
int len;
{
int i;
break;
}
return &tab[i];
}
/******************* PS/2 PnP probing ****************/
static int
{
return FALSE;
return TRUE;
}
static void
{
unsigned char reset_wrap_mode[] = { 0xEC };
}
{
unsigned char c;
int i,j;
#ifdef MOUSE_DEBUG
xf86ErrorF("Ps/2 data package:");
for (i = 0; i < len; i++)
xf86ErrorF("\n");
#endif
for (i = 0; i < len; i++) {
for (j = 0; j < 10; j++) {
usleep(10000);
#ifdef MOUSE_DEBUG
#endif
return FALSE;
}
#ifdef MOUSE_DEBUG
xf86ErrorF("Recieved: 0x%x\n",c);
#endif
if (c == 0xFA) /* ACK */
break;
if (c == 0xFE) /* resend */
continue;
if (c == 0xFC) /* error */
return FALSE;
/* Some mice accidently enter wrap mode during init */
if (c == *(bytes + i) /* wrap mode */
return FALSE;
}
if (j == 10)
return FALSE;
}
return TRUE;
}
static Bool
{
unsigned char packet[] = { 0xF5 };
}
{
unsigned char packet[] = { 0xF4 };
}
int
{
unsigned char u;
unsigned char packet[] = { 0xf2 };
usleep(30000);
return -1;
while (1) {
return -1;
if (u != 0xFA)
break;
}
#ifdef MOUSE_DEBUG
xf86ErrorF("Obtained Mouse Type: %x\n",u);
#endif
return (int) u;
}
{
unsigned char u;
unsigned char packet[] = { 0xff };
unsigned int i;
#ifdef MOUSE_DEBUG
xf86ErrorF("PS/2 Mouse reset\n");
#endif
return FALSE;
/* we need a little delay here */
for (i = 0; i < sizeof(reply) ; i++) {
goto EXIT;
}
if (u != reply[i])
goto EXIT;
}
return TRUE;
EXIT:
return FALSE;
}
static MouseProtocolID
{
unsigned char u;
/* Try to identify Intelli Mouse */
u = ps2GetDeviceID(pInfo);
if (u == 0x03) {
/* found IntelliMouse now try IntelliExplorer */
u = ps2GetDeviceID(pInfo);
if (u == 0x04)
ret = PROT_EXPPS2;
else
ret = PROT_IMPS2;
}
}
if (ret != PROT_UNKNOWN)
}
return ret;
}
static struct ps2protos {
int Id;
} ps2 [] = {
{ 0x0, PROT_PS2 },
{ 0x3, PROT_IMPS2 },
{ 0x4, PROT_EXPPS2 },
{ -1 , PROT_UNKNOWN }
};
static MouseProtocolID
{
int Id;
int i;
int count = 4;
while (--count)
if (ps2DisableDataReporting(pInfo))
break;
if (!count) {
goto EXIT;
}
goto EXIT;
}
goto EXIT;
}
goto EXIT;
}
}
EXIT:
return proto;
}