1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-15 10:17:20 +00:00

- Remove cdevsw entry points in individual keyboard drivers;

instead, use generic entry points for all drivers.
- Eliminate bogus makedev().
- Eliminate softc in the lower drivers, as it is no longer necessary.

Submitted (95%) by: phk
This commit is contained in:
Kazutaka YOKOTA 1999-08-22 09:52:33 +00:00
parent a676a98301
commit 800da3b22a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=50154
10 changed files with 172 additions and 633 deletions

View File

@ -23,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: atkbd.c,v 1.12 1999/07/18 06:16:25 yokota Exp $
* $Id: atkbd.c,v 1.13 1999/08/15 06:06:14 yokota Exp $
*/
#include "atkbd.h"
@ -49,45 +49,8 @@
#include <isa/isareg.h>
#define ATKBD_SOFTC(unit) \
((atkbd_softc_t *)devclass_get_softc(atkbd_devclass, unit))
extern devclass_t atkbd_devclass;
static timeout_t atkbd_timeout;
#ifdef KBD_INSTALL_CDEV
static d_open_t atkbdopen;
static d_close_t atkbdclose;
static d_read_t atkbdread;
static d_ioctl_t atkbdioctl;
static d_poll_t atkbdpoll;
static struct cdevsw atkbd_cdevsw = {
/* open */ atkbdopen,
/* close */ atkbdclose,
/* read */ atkbdread,
/* write */ nowrite,
/* ioctl */ atkbdioctl,
/* stop */ nostop,
/* reset */ noreset,
/* devtotty */ nodevtotty,
/* poll */ atkbdpoll,
/* mmap */ nommap,
/* strategy */ nostrategy,
/* name */ ATKBD_DRIVER_NAME,
/* parms */ noparms,
/* maj */ -1,
/* dump */ nodump,
/* psize */ nopsize,
/* flags */ 0,
/* maxio */ 0,
/* bmaj */ -1
};
#endif /* KBD_INSTALL_CDEV */
int
atkbd_probe_unit(int unit, int port, int irq, int flags)
{
@ -108,15 +71,12 @@ atkbd_probe_unit(int unit, int port, int irq, int flags)
}
int
atkbd_attach_unit(int unit, atkbd_softc_t *sc, int port, int irq, int flags)
atkbd_attach_unit(int unit, keyboard_t **kbd, int port, int irq, int flags)
{
keyboard_switch_t *sw;
int args[2];
int error;
if (sc->flags & ATKBD_ATTACHED)
return 0;
sw = kbd_get_switch(ATKBD_DRIVER_NAME);
if (sw == NULL)
return ENXIO;
@ -124,19 +84,18 @@ atkbd_attach_unit(int unit, atkbd_softc_t *sc, int port, int irq, int flags)
/* reset, initialize and enable the device */
args[0] = port;
args[1] = irq;
sc->kbd = NULL;
*kbd = NULL;
error = (*sw->probe)(unit, args, flags);
if (error)
return error;
error = (*sw->init)(unit, &sc->kbd, args, flags);
error = (*sw->init)(unit, kbd, args, flags);
if (error)
return error;
(*sw->enable)(sc->kbd);
(*sw->enable)(*kbd);
#ifdef KBD_INSTALL_CDEV
/* attach a virtual keyboard cdev */
error = kbd_attach(makedev(0, ATKBD_MKMINOR(unit)), sc->kbd,
&atkbd_cdevsw);
error = kbd_attach(*kbd);
if (error)
return error;
#endif
@ -145,12 +104,10 @@ atkbd_attach_unit(int unit, atkbd_softc_t *sc, int port, int irq, int flags)
* This is a kludge to compensate for lost keyboard interrupts.
* A similar code used to be in syscons. See below. XXX
*/
atkbd_timeout(sc->kbd);
atkbd_timeout(*kbd);
if (bootverbose)
(*sw->diag)(sc->kbd, bootverbose);
sc->flags |= ATKBD_ATTACHED;
(*sw->diag)(*kbd, bootverbose);
return 0;
}
@ -192,60 +149,6 @@ atkbd_timeout(void *arg)
/* cdev driver functions */
#ifdef KBD_INSTALL_CDEV
static int
atkbdopen(dev_t dev, int flag, int mode, struct proc *p)
{
atkbd_softc_t *sc;
sc = ATKBD_SOFTC(ATKBD_UNIT(dev));
if (sc == NULL)
return ENXIO;
if (mode & (FWRITE | O_CREAT | O_APPEND | O_TRUNC))
return ENODEV;
/* FIXME: set the initial input mode (K_XLATE?) and lock state? */
return genkbdopen(&sc->gensc, sc->kbd, flag, mode, p);
}
static int
atkbdclose(dev_t dev, int flag, int mode, struct proc *p)
{
atkbd_softc_t *sc;
sc = ATKBD_SOFTC(ATKBD_UNIT(dev));
return genkbdclose(&sc->gensc, sc->kbd, flag, mode, p);
}
static int
atkbdread(dev_t dev, struct uio *uio, int flag)
{
atkbd_softc_t *sc;
sc = ATKBD_SOFTC(ATKBD_UNIT(dev));
return genkbdread(&sc->gensc, sc->kbd, uio, flag);
}
static int
atkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
{
atkbd_softc_t *sc;
sc = ATKBD_SOFTC(ATKBD_UNIT(dev));
return genkbdioctl(&sc->gensc, sc->kbd, cmd, arg, flag, p);
}
static int
atkbdpoll(dev_t dev, int event, struct proc *p)
{
atkbd_softc_t *sc;
sc = ATKBD_SOFTC(ATKBD_UNIT(dev));
return genkbdpoll(&sc->gensc, sc->kbd, event, p);
}
#endif /* KBD_INSTALL_CDEV */
/* LOW-LEVEL */

View File

@ -23,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: atkbd_isa.c,v 1.3 1999/04/16 21:22:34 peter Exp $
* $Id: atkbd_isa.c,v 1.4 1999/05/08 21:59:28 dfr Exp $
*/
#include "atkbd.h"
@ -64,7 +64,7 @@ static device_method_t atkbd_methods[] = {
static driver_t atkbd_driver = {
ATKBD_DRIVER_NAME,
atkbd_methods,
sizeof(atkbd_softc_t),
1,
};
static int
@ -88,7 +88,7 @@ atkbdprobe(device_t dev)
static int
atkbdattach(device_t dev)
{
atkbd_softc_t *sc;
keyboard_t *kbd;
uintptr_t port;
uintptr_t irq;
uintptr_t flags;
@ -97,13 +97,11 @@ atkbdattach(device_t dev)
int zero = 0;
int error;
sc = (atkbd_softc_t *)device_get_softc(dev);
BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_PORT, &port);
BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_FLAGS, &flags);
error = atkbd_attach_unit(device_get_unit(dev), sc, port, irq, flags);
error = atkbd_attach_unit(device_get_unit(dev), &kbd, port, irq, flags);
if (error)
return error;
@ -111,7 +109,7 @@ atkbdattach(device_t dev)
res = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, irq, irq, 1,
RF_SHAREABLE | RF_ACTIVE);
BUS_SETUP_INTR(device_get_parent(dev), dev, res, INTR_TYPE_TTY,
atkbd_isa_intr, sc, &ih);
atkbd_isa_intr, kbd, &ih);
return 0;
}
@ -119,10 +117,10 @@ atkbdattach(device_t dev)
static void
atkbd_isa_intr(void *arg)
{
atkbd_softc_t *sc;
keyboard_t *kbd;
sc = (atkbd_softc_t *)arg;
(*kbdsw[sc->kbd->kb_index]->intr)(sc->kbd, NULL);
kbd = (keyboard_t *)arg;
(*kbdsw[kbd->kb_index]->intr)(kbd, NULL);
}
DRIVER_MODULE(atkbd, atkbdc, atkbd_driver, atkbd_devclass, 0, 0);

View File

@ -23,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: atkbd_isa.c,v 1.3 1999/04/16 21:22:34 peter Exp $
* $Id: atkbd_isa.c,v 1.4 1999/05/08 21:59:28 dfr Exp $
*/
#include "atkbd.h"
@ -64,7 +64,7 @@ static device_method_t atkbd_methods[] = {
static driver_t atkbd_driver = {
ATKBD_DRIVER_NAME,
atkbd_methods,
sizeof(atkbd_softc_t),
1,
};
static int
@ -88,7 +88,7 @@ atkbdprobe(device_t dev)
static int
atkbdattach(device_t dev)
{
atkbd_softc_t *sc;
keyboard_t *kbd;
uintptr_t port;
uintptr_t irq;
uintptr_t flags;
@ -97,13 +97,11 @@ atkbdattach(device_t dev)
int zero = 0;
int error;
sc = (atkbd_softc_t *)device_get_softc(dev);
BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_PORT, &port);
BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_FLAGS, &flags);
error = atkbd_attach_unit(device_get_unit(dev), sc, port, irq, flags);
error = atkbd_attach_unit(device_get_unit(dev), &kbd, port, irq, flags);
if (error)
return error;
@ -111,7 +109,7 @@ atkbdattach(device_t dev)
res = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, irq, irq, 1,
RF_SHAREABLE | RF_ACTIVE);
BUS_SETUP_INTR(device_get_parent(dev), dev, res, INTR_TYPE_TTY,
atkbd_isa_intr, sc, &ih);
atkbd_isa_intr, kbd, &ih);
return 0;
}
@ -119,10 +117,10 @@ atkbdattach(device_t dev)
static void
atkbd_isa_intr(void *arg)
{
atkbd_softc_t *sc;
keyboard_t *kbd;
sc = (atkbd_softc_t *)arg;
(*kbdsw[sc->kbd->kb_index]->intr)(sc->kbd, NULL);
kbd = (keyboard_t *)arg;
(*kbdsw[kbd->kb_index]->intr)(kbd, NULL);
}
DRIVER_MODULE(atkbd, atkbdc, atkbd_driver, atkbd_devclass, 0, 0);

View File

@ -23,15 +23,13 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: atkbdreg.h,v 1.1 1999/01/09 02:44:50 yokota Exp $
* $Id: atkbdreg.h,v 1.2 1999/03/10 10:36:52 yokota Exp $
*/
#ifndef _DEV_KBD_ATKBDREG_H_
#define _DEV_KBD_ATKBDREG_H_
#define ATKBD_DRIVER_NAME "atkbd"
#define ATKBD_UNIT(dev) minor(dev)
#define ATKBD_MKMINOR(unit) (unit)
/* device configuration flags (atkbdprobe, atkbdattach) */
#define KB_CONF_FAIL_IF_NO_KBD (1 << 0) /* don't install if no kbd is found */
@ -40,20 +38,8 @@
#ifdef KERNEL
typedef struct atkbd_softc {
short flags;
#define ATKBD_ATTACHED (1 << 0)
keyboard_t *kbd;
#ifdef KBD_INSTALL_CDEV
genkbd_softc_t gensc;
#endif
} atkbd_softc_t;
#ifdef __i386__
atkbd_softc_t *atkbd_get_softc(int unit);
#endif
int atkbd_probe_unit(int unit, int port, int irq, int flags);
int atkbd_attach_unit(int unit, atkbd_softc_t *sc,
int atkbd_attach_unit(int unit, keyboard_t **kbd,
int port, int irq, int flags);
#endif /* KERNEL */

View File

@ -23,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: atkbd.c,v 1.12 1999/07/18 06:16:25 yokota Exp $
* $Id: atkbd.c,v 1.13 1999/08/15 06:06:14 yokota Exp $
*/
#include "atkbd.h"
@ -49,45 +49,8 @@
#include <isa/isareg.h>
#define ATKBD_SOFTC(unit) \
((atkbd_softc_t *)devclass_get_softc(atkbd_devclass, unit))
extern devclass_t atkbd_devclass;
static timeout_t atkbd_timeout;
#ifdef KBD_INSTALL_CDEV
static d_open_t atkbdopen;
static d_close_t atkbdclose;
static d_read_t atkbdread;
static d_ioctl_t atkbdioctl;
static d_poll_t atkbdpoll;
static struct cdevsw atkbd_cdevsw = {
/* open */ atkbdopen,
/* close */ atkbdclose,
/* read */ atkbdread,
/* write */ nowrite,
/* ioctl */ atkbdioctl,
/* stop */ nostop,
/* reset */ noreset,
/* devtotty */ nodevtotty,
/* poll */ atkbdpoll,
/* mmap */ nommap,
/* strategy */ nostrategy,
/* name */ ATKBD_DRIVER_NAME,
/* parms */ noparms,
/* maj */ -1,
/* dump */ nodump,
/* psize */ nopsize,
/* flags */ 0,
/* maxio */ 0,
/* bmaj */ -1
};
#endif /* KBD_INSTALL_CDEV */
int
atkbd_probe_unit(int unit, int port, int irq, int flags)
{
@ -108,15 +71,12 @@ atkbd_probe_unit(int unit, int port, int irq, int flags)
}
int
atkbd_attach_unit(int unit, atkbd_softc_t *sc, int port, int irq, int flags)
atkbd_attach_unit(int unit, keyboard_t **kbd, int port, int irq, int flags)
{
keyboard_switch_t *sw;
int args[2];
int error;
if (sc->flags & ATKBD_ATTACHED)
return 0;
sw = kbd_get_switch(ATKBD_DRIVER_NAME);
if (sw == NULL)
return ENXIO;
@ -124,19 +84,18 @@ atkbd_attach_unit(int unit, atkbd_softc_t *sc, int port, int irq, int flags)
/* reset, initialize and enable the device */
args[0] = port;
args[1] = irq;
sc->kbd = NULL;
*kbd = NULL;
error = (*sw->probe)(unit, args, flags);
if (error)
return error;
error = (*sw->init)(unit, &sc->kbd, args, flags);
error = (*sw->init)(unit, kbd, args, flags);
if (error)
return error;
(*sw->enable)(sc->kbd);
(*sw->enable)(*kbd);
#ifdef KBD_INSTALL_CDEV
/* attach a virtual keyboard cdev */
error = kbd_attach(makedev(0, ATKBD_MKMINOR(unit)), sc->kbd,
&atkbd_cdevsw);
error = kbd_attach(*kbd);
if (error)
return error;
#endif
@ -145,12 +104,10 @@ atkbd_attach_unit(int unit, atkbd_softc_t *sc, int port, int irq, int flags)
* This is a kludge to compensate for lost keyboard interrupts.
* A similar code used to be in syscons. See below. XXX
*/
atkbd_timeout(sc->kbd);
atkbd_timeout(*kbd);
if (bootverbose)
(*sw->diag)(sc->kbd, bootverbose);
sc->flags |= ATKBD_ATTACHED;
(*sw->diag)(*kbd, bootverbose);
return 0;
}
@ -192,60 +149,6 @@ atkbd_timeout(void *arg)
/* cdev driver functions */
#ifdef KBD_INSTALL_CDEV
static int
atkbdopen(dev_t dev, int flag, int mode, struct proc *p)
{
atkbd_softc_t *sc;
sc = ATKBD_SOFTC(ATKBD_UNIT(dev));
if (sc == NULL)
return ENXIO;
if (mode & (FWRITE | O_CREAT | O_APPEND | O_TRUNC))
return ENODEV;
/* FIXME: set the initial input mode (K_XLATE?) and lock state? */
return genkbdopen(&sc->gensc, sc->kbd, flag, mode, p);
}
static int
atkbdclose(dev_t dev, int flag, int mode, struct proc *p)
{
atkbd_softc_t *sc;
sc = ATKBD_SOFTC(ATKBD_UNIT(dev));
return genkbdclose(&sc->gensc, sc->kbd, flag, mode, p);
}
static int
atkbdread(dev_t dev, struct uio *uio, int flag)
{
atkbd_softc_t *sc;
sc = ATKBD_SOFTC(ATKBD_UNIT(dev));
return genkbdread(&sc->gensc, sc->kbd, uio, flag);
}
static int
atkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
{
atkbd_softc_t *sc;
sc = ATKBD_SOFTC(ATKBD_UNIT(dev));
return genkbdioctl(&sc->gensc, sc->kbd, cmd, arg, flag, p);
}
static int
atkbdpoll(dev_t dev, int event, struct proc *p)
{
atkbd_softc_t *sc;
sc = ATKBD_SOFTC(ATKBD_UNIT(dev));
return genkbdpoll(&sc->gensc, sc->kbd, event, p);
}
#endif /* KBD_INSTALL_CDEV */
/* LOW-LEVEL */

View File

@ -23,15 +23,13 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: atkbdreg.h,v 1.1 1999/01/09 02:44:50 yokota Exp $
* $Id: atkbdreg.h,v 1.2 1999/03/10 10:36:52 yokota Exp $
*/
#ifndef _DEV_KBD_ATKBDREG_H_
#define _DEV_KBD_ATKBDREG_H_
#define ATKBD_DRIVER_NAME "atkbd"
#define ATKBD_UNIT(dev) minor(dev)
#define ATKBD_MKMINOR(unit) (unit)
/* device configuration flags (atkbdprobe, atkbdattach) */
#define KB_CONF_FAIL_IF_NO_KBD (1 << 0) /* don't install if no kbd is found */
@ -40,20 +38,8 @@
#ifdef KERNEL
typedef struct atkbd_softc {
short flags;
#define ATKBD_ATTACHED (1 << 0)
keyboard_t *kbd;
#ifdef KBD_INSTALL_CDEV
genkbd_softc_t gensc;
#endif
} atkbd_softc_t;
#ifdef __i386__
atkbd_softc_t *atkbd_get_softc(int unit);
#endif
int atkbd_probe_unit(int unit, int port, int irq, int flags);
int atkbd_attach_unit(int unit, atkbd_softc_t *sc,
int atkbd_attach_unit(int unit, keyboard_t **kbd,
int port, int irq, int flags);
#endif /* KERNEL */

View File

@ -23,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: kbd.c,v 1.8 1999/05/30 16:51:31 phk Exp $
* $Id: kbd.c,v 1.9 1999/05/31 11:24:48 phk Exp $
*/
#include "kbd.h"
@ -44,6 +44,15 @@
#include <dev/kbd/kbdreg.h>
#define KBD_INDEX(dev) minor(dev)
typedef struct genkbd_softc {
int gkb_flags; /* flag/status bits */
#define KB_ASLEEP (1 << 0)
struct clist gkb_q; /* input queue */
struct selinfo gkb_rsel;
} genkbd_softc_t;
/* local arrays */
/*
@ -58,11 +67,6 @@ static keyboard_t **keyboard = &kbd_ini;
static keyboard_switch_t *kbdsw_ini;
keyboard_switch_t **kbdsw = &kbdsw_ini;
#ifdef KBD_INSTALL_CDEV
static struct cdevsw *kbdcdevsw_ini;
static struct cdevsw **kbdcdevsw = &kbdcdevsw_ini;
#endif
#define ARRAY_DELTA 4
static int
@ -70,9 +74,6 @@ kbd_realloc_array(void)
{
keyboard_t **new_kbd;
keyboard_switch_t **new_kbdsw;
#ifdef KBD_INSTALL_CDEV
struct cdevsw **new_cdevsw;
#endif
int newsize;
int s;
@ -89,35 +90,16 @@ kbd_realloc_array(void)
splx(s);
return ENOMEM;
}
#ifdef KBD_INSTALL_CDEV
new_cdevsw = malloc(sizeof(*new_cdevsw)*newsize, M_DEVBUF, M_NOWAIT);
if (new_cdevsw == NULL) {
free(new_kbd, M_DEVBUF);
free(new_kbdsw, M_DEVBUF);
splx(s);
return ENOMEM;
}
#endif
bzero(new_kbd, sizeof(*new_kbd)*newsize);
bzero(new_kbdsw, sizeof(*new_kbdsw)*newsize);
bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards);
bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards);
#ifdef KBD_INSTALL_CDEV
bzero(new_cdevsw, sizeof(*new_cdevsw)*newsize);
bcopy(kbdcdevsw, new_cdevsw, sizeof(*kbdcdevsw)*keyboards);
#endif
if (keyboards > 1) {
free(keyboard, M_DEVBUF);
free(kbdsw, M_DEVBUF);
#ifdef KBD_INSTALL_CDEV
free(kbdcdevsw, M_DEVBUF);
#endif
}
keyboard = new_kbd;
kbdsw = new_kbdsw;
#ifdef KBD_INSTALL_CDEV
kbdcdevsw = new_cdevsw;
#endif
keyboards = newsize;
splx(s);
@ -358,6 +340,8 @@ keyboard_t
{
if ((index < 0) || (index >= keyboards))
return NULL;
if (keyboard[index] == NULL)
return NULL;
if (!KBD_IS_VALID(keyboard[index]))
return NULL;
return keyboard[index];
@ -394,28 +378,26 @@ kbd_configure(int flags)
#define KBD_UNIT(dev) minor(dev)
static d_open_t kbdopen;
static d_close_t kbdclose;
static d_read_t kbdread;
static d_write_t kbdwrite;
static d_ioctl_t kbdioctl;
static d_devtotty_t kbddevtotty;
static d_poll_t kbdpoll;
static d_mmap_t kbdmmap;
static d_open_t genkbdopen;
static d_close_t genkbdclose;
static d_read_t genkbdread;
static d_write_t genkbdwrite;
static d_ioctl_t genkbdioctl;
static d_poll_t genkbdpoll;
#define CDEV_MAJOR 112
static struct cdevsw kbd_cdevsw = {
/* open */ kbdopen,
/* close */ kbdclose,
/* read */ kbdread,
/* write */ kbdwrite,
/* ioctl */ kbdioctl,
/* open */ genkbdopen,
/* close */ genkbdclose,
/* read */ genkbdread,
/* write */ genkbdwrite,
/* ioctl */ genkbdioctl,
/* stop */ nostop,
/* reset */ noreset,
/* devtotty */ kbddevtotty,
/* poll */ kbdpoll,
/* mmap */ kbdmmap,
/* devtotty */ nodevtotty,
/* poll */ genkbdpoll,
/* mmap */ nommap,
/* strategy */ nostrategy,
/* name */ "kbd",
/* parms */ noparms,
@ -427,157 +409,39 @@ static struct cdevsw kbd_cdevsw = {
/* bmaj */ -1
};
static void
vkbdattach(void *arg)
{
static int kbd_devsw_installed = FALSE;
if (!kbd_devsw_installed) {
cdevsw_add(&kbd_cdevsw);
kbd_devsw_installed = TRUE;
}
}
PSEUDO_SET(vkbdattach, kbd);
int
kbd_attach(dev_t dev, keyboard_t *kbd, struct cdevsw *cdevsw)
kbd_attach(keyboard_t *kbd)
{
int s;
dev_t dev;
if (kbd->kb_index >= keyboards)
return EINVAL;
if (keyboard[kbd->kb_index] != kbd)
return EINVAL;
s = spltty();
kbd->kb_minor = minor(dev);
kbdcdevsw[kbd->kb_index] = cdevsw;
splx(s);
/* XXX: DEVFS? */
dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL, 0600,
"kbd%r", kbd->kb_index);
if (dev->si_drv1 == NULL)
dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF,
M_WAITOK);
bzero(dev->si_drv1, sizeof(genkbd_softc_t));
printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit);
return 0;
}
int
kbd_detach(dev_t dev, keyboard_t *kbd, struct cdevsw *cdevsw)
kbd_detach(keyboard_t *kbd)
{
int s;
if (kbd->kb_index >= keyboards)
return EINVAL;
if (keyboard[kbd->kb_index] != kbd)
return EINVAL;
if (kbdcdevsw[kbd->kb_index] != cdevsw)
return EINVAL;
s = spltty();
kbdcdevsw[kbd->kb_index] = NULL;
splx(s);
/* XXX: unmake_dev() ? */
return 0;
}
static int
kbdopen(dev_t dev, int flag, int mode, struct proc *p)
{
int unit;
unit = KBD_UNIT(dev);
if (unit >= keyboards)
return ENXIO;
if (kbdcdevsw[unit] == NULL)
return ENXIO;
if (KBD_IS_BUSY(keyboard[unit]))
return EBUSY;
return (*kbdcdevsw[unit]->d_open)(makedev(0, keyboard[unit]->kb_minor),
flag, mode, p);
}
static int
kbdclose(dev_t dev, int flag, int mode, struct proc *p)
{
int unit;
unit = KBD_UNIT(dev);
if (kbdcdevsw[unit] == NULL)
return ENXIO;
return (*kbdcdevsw[unit]->d_close)(makedev(0, keyboard[unit]->kb_minor),
flag, mode, p);
}
static int
kbdread(dev_t dev, struct uio *uio, int flag)
{
int unit;
unit = KBD_UNIT(dev);
if (kbdcdevsw[unit] == NULL)
return ENXIO;
return (*kbdcdevsw[unit]->d_read)(makedev(0, keyboard[unit]->kb_minor),
uio, flag);
}
static int
kbdwrite(dev_t dev, struct uio *uio, int flag)
{
int unit;
unit = KBD_UNIT(dev);
if (kbdcdevsw[unit] == NULL)
return ENXIO;
return (*kbdcdevsw[unit]->d_write)(makedev(0, keyboard[unit]->kb_minor),
uio, flag);
}
static int
kbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
{
int unit;
unit = KBD_UNIT(dev);
if (kbdcdevsw[unit] == NULL)
return ENXIO;
return (*kbdcdevsw[unit]->d_ioctl)(makedev(0, keyboard[unit]->kb_minor),
cmd, arg, flag, p);
}
static struct tty
*kbddevtotty(dev_t dev)
{
int unit;
unit = KBD_UNIT(dev);
if (kbdcdevsw[unit] == NULL)
return NULL;
return (*kbdcdevsw[unit]->d_devtotty)(makedev(0, keyboard[unit]->kb_minor));
}
static int
kbdpoll(dev_t dev, int event, struct proc *p)
{
int unit;
unit = KBD_UNIT(dev);
if (kbdcdevsw[unit] == NULL)
return ENXIO;
return (*kbdcdevsw[unit]->d_poll)(makedev(0, keyboard[unit]->kb_minor),
event, p);
}
static int
kbdmmap(dev_t dev, vm_offset_t offset, int nprot)
{
int unit;
unit = KBD_UNIT(dev);
if (kbdcdevsw[unit] == NULL)
return ENXIO;
return (*kbdcdevsw[unit]->d_mmap)(makedev(0, keyboard[unit]->kb_minor),
offset, nprot);
}
/*
* Generic keyboard cdev driver functions
* Keyboard subdrivers may call these functions to implement common
@ -589,15 +453,18 @@ kbdmmap(dev_t dev, vm_offset_t offset, int nprot)
static kbd_callback_func_t genkbd_event;
int
genkbdopen(genkbd_softc_t *sc, keyboard_t *kbd, int mode, int flag,
struct proc *p)
static int
genkbdopen(dev_t dev, int mode, int flag, struct proc *p)
{
keyboard_t *kbd;
genkbd_softc_t *sc;
int s;
int i;
s = spltty();
if (!KBD_IS_VALID(kbd)) {
sc = dev->si_drv1;
kbd = kbd_get_keyboard(KBD_INDEX(dev));
if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
splx(s);
return ENXIO;
}
@ -626,29 +493,37 @@ genkbdopen(genkbd_softc_t *sc, keyboard_t *kbd, int mode, int flag,
return 0;
}
int
genkbdclose(genkbd_softc_t *sc, keyboard_t *kbd, int mode, int flag,
struct proc *p)
static int
genkbdclose(dev_t dev, int mode, int flag, struct proc *p)
{
keyboard_t *kbd;
genkbd_softc_t *sc;
int s;
/*
* NOTE: the device may have already become invalid.
* !KBD_IS_VALID(kbd)
* kbd == NULL || !KBD_IS_VALID(kbd)
*/
s = spltty();
kbd_release(kbd, (void *)sc);
sc = dev->si_drv1;
kbd = kbd_get_keyboard(KBD_INDEX(dev));
if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
/* XXX: we shall be forgiving and don't report error... */
} else {
kbd_release(kbd, (void *)sc);
#if 0
clist_free_cblocks(&sc->gkb_q);
clist_free_cblocks(&sc->gkb_q);
#endif
}
splx(s);
return 0;
}
int
genkbdread(genkbd_softc_t *sc, keyboard_t *kbd, struct uio *uio, int flag)
static int
genkbdread(dev_t dev, struct uio *uio, int flag)
{
keyboard_t *kbd;
genkbd_softc_t *sc;
u_char buffer[KB_BUFSIZE];
int len;
int error;
@ -656,17 +531,24 @@ genkbdread(genkbd_softc_t *sc, keyboard_t *kbd, struct uio *uio, int flag)
/* wait for input */
s = spltty();
sc = dev->si_drv1;
kbd = kbd_get_keyboard(KBD_INDEX(dev));
if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
splx(s);
return ENXIO;
}
while (sc->gkb_q.c_cc == 0) {
if (!KBD_IS_VALID(kbd)) {
splx(s);
return EIO;
}
if (flag & IO_NDELAY) {
splx(s);
return EWOULDBLOCK;
}
sc->gkb_flags |= KB_ASLEEP;
error = tsleep((caddr_t)sc, PZERO | PCATCH, "kbdrea", 0);
kbd = kbd_get_keyboard(KBD_INDEX(dev));
if ((kbd == NULL) || !KBD_IS_VALID(kbd)) {
splx(s);
return ENXIO; /* our keyboard has gone... */
}
if (error) {
sc->gkb_flags &= ~KB_ASLEEP;
splx(s);
@ -690,23 +572,25 @@ genkbdread(genkbd_softc_t *sc, keyboard_t *kbd, struct uio *uio, int flag)
return error;
}
int
genkbdwrite(genkbd_softc_t *sc, keyboard_t *kbd, struct uio *uio, int flag)
static int
genkbdwrite(dev_t dev, struct uio *uio, int flag)
{
if (!KBD_IS_VALID(kbd))
keyboard_t *kbd;
kbd = kbd_get_keyboard(KBD_INDEX(dev));
if ((kbd == NULL) || !KBD_IS_VALID(kbd))
return ENXIO;
return ENODEV;
}
int
genkbdioctl(genkbd_softc_t *sc, keyboard_t *kbd, u_long cmd, caddr_t arg,
int flag, struct proc *p)
static int
genkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
{
keyboard_t *kbd;
int error;
if (kbd == NULL) /* XXX */
return ENXIO;
if (!KBD_IS_VALID(kbd))
kbd = kbd_get_keyboard(KBD_INDEX(dev));
if ((kbd == NULL) || !KBD_IS_VALID(kbd))
return ENXIO;
error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg);
if (error == ENOIOCTL)
@ -714,17 +598,23 @@ genkbdioctl(genkbd_softc_t *sc, keyboard_t *kbd, u_long cmd, caddr_t arg,
return error;
}
int
genkbdpoll(genkbd_softc_t *sc, keyboard_t *kbd, int events, struct proc *p)
static int
genkbdpoll(dev_t dev, int events, struct proc *p)
{
keyboard_t *kbd;
genkbd_softc_t *sc;
int revents;
int s;
revents = 0;
s = spltty();
if (events & (POLLIN | POLLRDNORM)) {
if ((sc->gkb_q.c_cc > 0) || !KBD_IS_VALID(kbd))
revents |= (POLLIN | POLLRDNORM);
sc = dev->si_drv1;
kbd = kbd_get_keyboard(KBD_INDEX(dev));
if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) {
revents = POLLHUP; /* the keyboard has gone */
} else if (events & (POLLIN | POLLRDNORM)) {
if (sc->gkb_q.c_cc > 0)
revents = events & (POLLIN | POLLRDNORM);
else
selrecord(p, &sc->gkb_rsel);
}
@ -750,6 +640,11 @@ genkbd_event(keyboard_t *kbd, int event, void *arg)
case KBDIO_UNLOADING:
/* the keyboard is going... */
kbd_release(kbd, (void *)sc);
if (sc->gkb_flags & KB_ASLEEP) {
sc->gkb_flags &= ~KB_ASLEEP;
wakeup((caddr_t)sc);
}
selwakeup(&sc->gkb_rsel);
return 0;
default:
return EINVAL;

View File

@ -23,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: kbdreg.h,v 1.2 1999/01/19 11:31:14 yokota Exp $
* $Id: kbdreg.h,v 1.3 1999/03/10 10:36:52 yokota Exp $
*/
#ifndef _DEV_KBD_KBDREG_H_
@ -34,6 +34,7 @@ typedef struct keyboard keyboard_t;
struct keymap;
struct accentmap;
struct fkeytab;
struct cdevsw;
/* call back funcion */
typedef int kbd_callback_func_t(keyboard_t *kbd, int event,
@ -199,33 +200,8 @@ int kbd_configure(int flags);
#ifdef KBD_INSTALL_CDEV
/* virtual keyboard cdev driver functions */
int kbd_attach(dev_t dev, keyboard_t *kbd,
struct cdevsw *sw);
int kbd_detach(dev_t dev, keyboard_t *kbd,
struct cdevsw *sw);
/* generic keyboard cdev driver functions */
typedef struct genkbd_softc {
int gkb_flags; /* flag/status bits */
#define KB_ASLEEP (1 << 0)
struct clist gkb_q; /* input queue */
struct selinfo gkb_rsel;
} genkbd_softc_t;
int genkbdopen(genkbd_softc_t *sc, keyboard_t *kbd, int flag, int mode,
struct proc *p);
int genkbdclose(genkbd_softc_t *sc, keyboard_t *kbd, int flag, int mode,
struct proc *p);
int genkbdread(genkbd_softc_t *sc, keyboard_t *kbd, struct uio *uio,
int flag);
int genkbdwrite(genkbd_softc_t *sc, keyboard_t *kbd, struct uio *uio,
int flag);
int genkbdioctl(genkbd_softc_t *sc, keyboard_t *kbd, u_long cmd,
caddr_t arg, int flag, struct proc *p);
int genkbdpoll(genkbd_softc_t *sc, keyboard_t *kbd, int event,
struct proc *p);
int kbd_attach(keyboard_t *kbd);
int kbd_detach(keyboard_t *kbd);
#endif /* KBD_INSTALL_CDEV */

View File

@ -107,17 +107,8 @@ struct ukbd_data {
typedef struct ukbd_softc {
bdevice sc_dev; /* base device */
usbd_interface_handle sc_iface; /* interface */
short sc_flags;
#define UKBD_ATTACHED (1 << 0)
keyboard_t *sc_kbd;
#ifdef KBD_INSTALL_CDEV
genkbd_softc_t sc_gensc;
#endif
} ukbd_softc_t;
#define UKBDUNIT(dev) (minor(dev))
#define UKBD_CHUNK 128 /* chunk size for read */
#define UKBD_BSIZE 1020 /* buffer size */
@ -126,39 +117,6 @@ typedef void usbd_disco_t(void *);
static usbd_intr_t ukbd_intr;
static usbd_disco_t ukbd_disconnect;
static int ukbd_remove_kbd(struct ukbd_softc *sc);
#ifdef KBD_INSTALL_CDEV
static d_open_t ukbdopen;
static d_close_t ukbdclose;
static d_read_t ukbdread;
static d_ioctl_t ukbdioctl;
static d_poll_t ukbdpoll;
static struct cdevsw ukbd_cdevsw = {
/* open */ ukbdopen,
/* close */ ukbdclose,
/* read */ ukbdread,
/* write */ nowrite,
/* ioctl */ ukbdioctl,
/* stop */ nostop,
/* reset */ noreset,
/* devtotty */ nodevtotty,
/* poll */ ukbdpoll,
/* mmap */ nommap,
/* strategy */ nostrategy,
/* name */ DRIVER_NAME,
/* parms */ noparms,
/* maj */ -1,
/* dump */ nodump,
/* psize */ nopsize,
/* flags */ 0,
/* maxio */ 0,
/* bmaj */ -1
};
#endif /* KBD_INSTALL_CDEV */
USB_DECLARE_DRIVER(ukbd);
@ -167,7 +125,7 @@ USB_MATCH(ukbd)
USB_MATCH_START(ukbd, uaa);
keyboard_switch_t *sw;
void *arg[4];
void *arg[3];
int unit = device_get_unit(self);
sw = kbd_get_switch(DRIVER_NAME);
@ -177,7 +135,6 @@ USB_MATCH(ukbd)
arg[0] = (void *)uaa;
arg[1] = (void *)ukbd_intr;
arg[2] = (void *)ukbd_disconnect;
arg[3] = (void *)self;
if ((*sw->probe)(unit, (void *)arg, 0))
return (UMATCH_NONE);
@ -192,14 +149,14 @@ USB_ATTACH(ukbd)
char devinfo[1024];
keyboard_switch_t *sw;
void *arg[4];
keyboard_t *kbd;
void *arg[3];
int unit = device_get_unit(self);
sw = kbd_get_switch(DRIVER_NAME);
if (sw == NULL)
USB_ATTACH_ERROR_RETURN;
sc->sc_iface = iface;
id = usbd_get_interface_descriptor(iface);
usbd_devinfo(uaa->device, 0, devinfo);
USB_ATTACH_SETUP;
@ -209,21 +166,19 @@ USB_ATTACH(ukbd)
arg[0] = (void *)uaa;
arg[1] = (void *)ukbd_intr;
arg[2] = (void *)ukbd_disconnect;
arg[3] = (void *)self;
sc->sc_kbd = NULL;
kbd = NULL;
if ((*sw->probe)(unit, (void *)arg, 0))
USB_ATTACH_ERROR_RETURN;
if ((*sw->init)(unit, &sc->sc_kbd, (void *)arg, 0))
if ((*sw->init)(unit, &kbd, (void *)arg, 0))
USB_ATTACH_ERROR_RETURN;
(*sw->enable)(sc->sc_kbd);
(*sw->enable)(kbd);
#ifdef KBD_INSTALL_CDEV
if (kbd_attach(makedev(0, unit), sc->sc_kbd, &ukbd_cdevsw))
if (kbd_attach(kbd))
USB_ATTACH_ERROR_RETURN;
#endif
if (bootverbose)
(*sw->diag)(sc->sc_kbd, bootverbose);
sc->sc_flags |= UKBD_ATTACHED;
(*sw->diag)(kbd, bootverbose);
USB_ATTACH_SUCCESS_RETURN;
}
@ -231,14 +186,23 @@ USB_ATTACH(ukbd)
int
ukbd_detach(device_t self)
{
struct ukbd_softc *sc = device_get_softc(self);
keyboard_t *kbd;
int error;
error = ukbd_remove_kbd(sc);
kbd = kbd_get_keyboard(kbd_find_keyboard(DRIVER_NAME,
device_get_unit(self)));
if (kbd == NULL) {
DPRINTF(("%s: keyboard not attached!?\n", USBDEVNAME(self)));
return ENXIO;
}
#ifdef KBD_INSTALL_CDEV
error = kbd_detach(kbd);
if (error)
return error;
#endif
error = (*kbdsw[kbd->kb_index]->term)(kbd);
if (error)
return error;
sc->sc_flags &= ~UKBD_ATTACHED;
DPRINTF(("%s: disconnected\n", USBDEVNAME(self)));
@ -250,79 +214,12 @@ ukbd_detach(device_t self)
static void
ukbd_disconnect(void *p)
{
device_t self = (device_t)p;
struct ukbd_softc *sc = device_get_softc(self);
keyboard_t *kbd = (keyboard_t *)p;
DPRINTF(("ukbd_disconnect: sc:%p\n", sc));
(*kbdsw[sc->sc_kbd->kb_index]->disable)(sc->sc_kbd);
DPRINTF(("ukbd_disconnect: kbd:%p\n", kbd));
(*kbdsw[kbd->kb_index]->disable)(kbd);
}
static int
ukbd_remove_kbd(struct ukbd_softc *sc)
{
int error;
#ifdef KBD_INSTALL_CDEV
error = kbd_detach(makedev(0, sc->sc_kbd->kb_unit), sc->sc_kbd,
&ukbd_cdevsw);
if (error)
return error;
#endif
error = (*kbdsw[sc->sc_kbd->kb_index]->term)(sc->sc_kbd);
if (error)
return error;
sc->sc_kbd = NULL;
return 0;
}
/* cdev driver functions */
#ifdef KBD_INSTALL_CDEV
static int
ukbdopen(dev_t dev, int flag, int mode, struct proc *p)
{
USB_GET_SC_OPEN(ukbd, UKBDUNIT(dev), sc);
/* FIXME: set the initial input mode (K_XLATE?) and lock state? */
return genkbdopen(&sc->sc_gensc, sc->sc_kbd, flag, mode, p);
}
static int
ukbdclose(dev_t dev, int flag, int mode, struct proc *p)
{
USB_GET_SC(ukbd, UKBDUNIT(dev),sc);
return genkbdclose(&sc->sc_gensc, sc->sc_kbd, flag, mode, p);
}
static int
ukbdread(dev_t dev, struct uio *uio, int flag)
{
USB_GET_SC(ukbd, UKBDUNIT(dev),sc);
return genkbdread(&sc->sc_gensc, sc->sc_kbd, uio, flag);
}
static int
ukbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
{
USB_GET_SC(ukbd, UKBDUNIT(dev),sc);
return genkbdioctl(&sc->sc_gensc, sc->sc_kbd, cmd, arg, flag, p);
}
static int
ukbdpoll(dev_t dev, int event, struct proc *p)
{
USB_GET_SC(ukbd, UKBDUNIT(dev),sc);
return genkbdpoll(&sc->sc_gensc, sc->sc_kbd, event, p);
}
#endif /* KBD_INSTALL_CDEV */
void
ukbd_intr(usbd_request_handle reqh, usbd_private_handle addr, usbd_status status)
{
@ -545,7 +442,7 @@ ukbd_configure(int flags)
keyboard_t *kbd;
device_t device;
struct usb_attach_arg *uaa;
void *arg[4];
void *arg[3];
device = devclass_get_device(ukbd_devclass, UKBD_DEFAULT);
if (device == NULL)
@ -558,7 +455,6 @@ ukbd_configure(int flags)
arg[0] = (void *)uaa;
arg[1] = (void *)ukbd_intr;
arg[2] = (void *)ukbd_disconnect;
arg[3] = (void *)device;
kbd = NULL;
if (ukbd_probe(UKBD_DEFAULT, arg, flags))
return 0;
@ -689,7 +585,7 @@ ukbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
return ENXIO;
if (ukbd_enable_intr(kbd, TRUE, (usbd_intr_t *)data[1]) == 0) {
usbd_set_disco(state->ks_intrpipe,
(usbd_disco_t *)data[2], data[3]);
(usbd_disco_t *)data[2], (void *)kbd);
ukbd_timeout((void *)kbd);
}
KBD_CONFIG_DONE(kbd);

View File

@ -23,7 +23,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: atkbd_isa.c,v 1.3 1999/04/16 21:22:34 peter Exp $
* $Id: atkbd_isa.c,v 1.4 1999/05/08 21:59:28 dfr Exp $
*/
#include "atkbd.h"
@ -64,7 +64,7 @@ static device_method_t atkbd_methods[] = {
static driver_t atkbd_driver = {
ATKBD_DRIVER_NAME,
atkbd_methods,
sizeof(atkbd_softc_t),
1,
};
static int
@ -88,7 +88,7 @@ atkbdprobe(device_t dev)
static int
atkbdattach(device_t dev)
{
atkbd_softc_t *sc;
keyboard_t *kbd;
uintptr_t port;
uintptr_t irq;
uintptr_t flags;
@ -97,13 +97,11 @@ atkbdattach(device_t dev)
int zero = 0;
int error;
sc = (atkbd_softc_t *)device_get_softc(dev);
BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_PORT, &port);
BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_IRQ, &irq);
BUS_READ_IVAR(device_get_parent(dev), dev, KBDC_IVAR_FLAGS, &flags);
error = atkbd_attach_unit(device_get_unit(dev), sc, port, irq, flags);
error = atkbd_attach_unit(device_get_unit(dev), &kbd, port, irq, flags);
if (error)
return error;
@ -111,7 +109,7 @@ atkbdattach(device_t dev)
res = bus_alloc_resource(dev, SYS_RES_IRQ, &zero, irq, irq, 1,
RF_SHAREABLE | RF_ACTIVE);
BUS_SETUP_INTR(device_get_parent(dev), dev, res, INTR_TYPE_TTY,
atkbd_isa_intr, sc, &ih);
atkbd_isa_intr, kbd, &ih);
return 0;
}
@ -119,10 +117,10 @@ atkbdattach(device_t dev)
static void
atkbd_isa_intr(void *arg)
{
atkbd_softc_t *sc;
keyboard_t *kbd;
sc = (atkbd_softc_t *)arg;
(*kbdsw[sc->kbd->kb_index]->intr)(sc->kbd, NULL);
kbd = (keyboard_t *)arg;
(*kbdsw[kbd->kb_index]->intr)(kbd, NULL);
}
DRIVER_MODULE(atkbd, atkbdc, atkbd_driver, atkbd_devclass, 0, 0);