mouse8042.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
/* All Rights Reserved */
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* PS/2 type Mouse Module - Streams
*/
#ifdef DEBUG
#define MOUSE8042_DEBUG
#endif
/*
*
* Local Static Data
*
*/
/*
* We only support one instance. Yes, it's theoretically possible to
* plug in more than one, but it's not worth the implementation cost.
*
* The introduction of USB keyboards might make it worth reassessing
* this decision, as they might free up the keyboard port for a second
* PS/2 style mouse.
*/
static dev_info_t *mouse8042_dip;
struct mouse_state {
};
#if defined(MOUSE8042_DEBUG)
int mouse8042_debug = 0;
int mouse8042_debug_minimal = 0;
#endif
/*
* Streams module info.
*/
#define MODULE_NAME "mouse8042"
static struct module_info mouse8042_minfo = {
23, /* Module ID number */
0, INFPSZ, /* minimum & maximum packet sizes */
256, 128 /* hi and low water marks */
};
static struct qinit mouse8042_rinit = {
NULL, /* put */
NULL, /* service */
NULL, /* admin */
NULL /* statistics */
};
static struct qinit mouse8042_winit = {
mouse8042_wput, /* put */
NULL, /* service */
NULL, /* open */
NULL, /* close */
NULL, /* admin */
NULL /* statistics */
};
static struct streamtab mouse8042_strinfo = {
NULL, /* muxrinit */
NULL, /* muxwinit */
};
/*
* Local Function Declarations
*/
static struct cb_ops mouse8042_cb_ops = {
nodev, /* open */
nodev, /* close */
nodev, /* strategy */
nodev, /* print */
nodev, /* dump */
nodev, /* read */
nodev, /* write */
nodev, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* poll */
ddi_prop_op, /* cb_prop_op */
&mouse8042_strinfo, /* streamtab */
};
static struct dev_ops mouse8042_ops = {
DEVO_REV, /* devo_rev, */
0, /* refcnt */
mouse8042_getinfo, /* getinfo */
nulldev, /* identify */
nulldev, /* probe */
mouse8042_attach, /* attach */
mouse8042_detach, /* detach */
nodev, /* reset */
&mouse8042_cb_ops, /* driver operations */
(struct bus_ops *)0 /* bus operations */
};
/*
* This is the loadable module wrapper.
*/
extern struct mod_ops mod_driverops;
/*
* Module linkage information for the kernel.
*/
&mod_driverops, /* Type of module. This one is a driver */
"PS/2 Mouse %I%, %E%",
&mouse8042_ops, /* driver ops */
};
static struct modlinkage modlinkage = {
(void *)&modldrv,
};
/*
* This is the driver initialization routine.
*/
int
_init()
{
int rv;
return (rv);
}
int
_fini(void)
{
return (mod_remove(&modlinkage));
}
int
{
}
static int
{
struct mouse_state *state;
static ddi_device_acc_attr_t attr = {
};
int rc;
#ifdef MOUSE8042_DEBUG
if (mouse8042_debug) {
}
#endif
if (cmd != DDI_ATTACH)
return (DDI_FAILURE);
if (mouse8042_dip != NULL)
return (DDI_FAILURE);
/* allocate and initialize state structure */
/*
* between internal virtual open and external physical open.
*
* When the physical devices are opened by application, they will
* be unlinked from the virtual device and their data stream will
* not be sent to the virtual device. When the opened physical
* devices are closed, they will be relinked to the virtual devices.
*
* All these automatic switch between virtual and physical are
* transparent.
*
* So we change minor node numbering scheme to be:
* external node minor num == instance * 2
* internal node minor num == instance * 2 + 1
*/
DDI_NT_MOUSE, NULL);
if (rc != DDI_SUCCESS) {
#if defined(MOUSE8042_DEBUG)
MODULE_NAME "_attach: ddi_create_minor_node failed\n");
#endif
goto fail_1;
}
goto fail_2;
}
if (rc != DDI_SUCCESS) {
#if defined(MOUSE8042_DEBUG)
#endif
goto fail_2;
}
if (rc != DDI_SUCCESS) {
#if defined(MOUSE8042_DEBUG)
MODULE_NAME "_attach: Can't get iblock cookie");
#endif
goto fail_3;
}
if (rc != DDI_SUCCESS) {
#if defined(MOUSE8042_DEBUG)
#endif
goto fail_3;
}
mouse8042_dip = dip;
/* Now that we're attached, announce our presence to the world. */
#if defined(MOUSE8042_DEBUG)
#endif
return (DDI_SUCCESS);
return (rc);
}
/*ARGSUSED*/
static int
{
struct mouse_state *state;
switch (cmd) {
case DDI_DETACH:
return (DDI_SUCCESS);
default:
#ifdef MOUSE8042_DEBUG
if (mouse8042_debug) {
"mouse8042_detach: cmd = %d unknown\n", cmd);
}
#endif
return (DDI_FAILURE);
}
}
/* ARGSUSED */
static int
void *arg,
void **result)
{
#ifdef MOUSE8042_DEBUG
if (mouse8042_debug)
#endif
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
if (mouse8042_dip == NULL)
return (DDI_FAILURE);
*result = (void *)mouse8042_dip;
break;
case DDI_INFO_DEVT2INSTANCE:
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*ARGSUSED*/
static int
queue_t *q,
int flag,
int sflag,
{
struct mouse_state *state;
int rval;
if (mouse8042_dip == NULL)
return (ENXIO);
#ifdef MOUSE8042_DEBUG
if (mouse8042_debug)
#endif
/*
* Exit if the same minor node is already open
*/
return (0);
}
/*
* Check whether it is switch between physical and virtual
*
* Opening from virtual while the device is being physically
* opened by an application should not happen. So we ASSERT
* this in DEBUG version, and return error in the non-DEBUG
* case.
*/
if (MOUSE8042_INTERNAL_OPEN(minor)) {
return (EINVAL);
}
/*
* Opening the physical one while it is being underneath
* the virtual one.
*
* consconfig_unlink is called to unlink this device from
* the virtual one, thus the old stream serving for this
* device under the virtual one is closed, and then the
* lower driver's close routine (here is mouse8042_close)
* is also called to accomplish the whole stream close.
* Here we have to drop the lock because mouse8042_close
* also needs the lock.
*
* For mouse, the old stream is:
* consms->["pushmod"->]"mouse_vp driver"
*
* After the consconfig_unlink returns, the old stream is closed
* and we grab the lock again to reopen this device as normal.
*/
/*
* If unlink fails, fail the physical open.
*/
MOUSE8042_INTERNAL_MINOR(minor))) != 0) {
return (rval);
}
}
qprocson(q);
return (0);
}
/*ARGSUSED*/
static int
{
struct mouse_state *state;
#ifdef MOUSE8042_DEBUG
if (mouse8042_debug)
#endif
qprocsoff(q);
if (!MOUSE8042_INTERNAL_OPEN(minor)) {
/*
* Closing physical PS/2 mouse
*
* Link it back to virtual mouse, and
* mouse8042_open will be called as a result
* of the consconfig_link call.
*
* If linking back fails, this specific mouse
* will not be available underneath the virtual
* mouse, and can only be accessed via physical
* open.
*/
}
return (0);
}
static void
int error,
int rval)
{
}
static int
{
struct mouse_state *state;
#ifdef MOUSE8042_DEBUG
if (mouse8042_debug)
#endif
case M_FLUSH:
#ifdef MOUSE8042_DEBUG
if (mouse8042_debug)
#endif
break;
case M_IOCTL:
#ifdef MOUSE8042_DEBUG
if (mouse8042_debug)
#endif
break;
case M_IOCDATA:
#ifdef MOUSE8042_DEBUG
if (mouse8042_debug)
#endif
break;
case M_DATA:
do {
#if defined(MOUSE8042_DEBUG)
if (mouse8042_debug) {
"mouse8042: send %2x\n",
}
if (mouse8042_debug_minimal) {
}
#endif
}
break;
default:
break;
}
#ifdef MOUSE8042_DEBUG
if (mouse8042_debug)
#endif
return (0); /* ignored */
}
static uint_t
{
unsigned char mdata;
int rc;
#if defined(MOUSE8042_DEBUG)
if (mouse8042_debug)
#endif
for (;;) {
break;
}
#if defined(MOUSE8042_DEBUG)
if (mouse8042_debug)
#endif
}
}
#ifdef MOUSE8042_DEBUG
if (mouse8042_debug)
#endif
return (rc);
}