* Copyright (c) 1988 University of Utah.
* Copyright (c) 1990 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
* %sccs.include.redist.c%
* from: Utah $Hdr: hil.c 1.33 89/12/22$
* @(#)hil.c 7.3 (Berkeley) %G%
struct _hilbell default_bell
= { BELLDUR
, BELLFREQ
};
int hilqfork(), hilqvfork(), hilqexit();
struct mapmemops hilqops
= { hilqfork
, hilqvfork
, hilqexit
, hilqexit
};
#define HDB_KEYBOARD 0x10
#define HDB_IDMODULE 0x20
/* symbolic sleep message strings */
register struct hilloop
*hilp
= &hil0
; /* XXX */
* Initialize loop information
hilp
->hl_cmdending
= FALSE
;
hilp
->hl_actdev
= hilp
->hl_cmddev
= 0;
hilp
->hl_cmddone
= FALSE
;
hilp
->hl_cmdbp
= hilp
->hl_cmdbuf
;
hilp
->hl_pollbp
= hilp
->hl_pollbuf
;
hilp
->hl_kbdlang
= KBD_DEFAULT
;
* Clear all queues and device associations with queues
for (i
= 0; i
< NHILQ
; i
++) {
hilp
->hl_queue
[i
].hq_eventqueue
= NULL
;
hilp
->hl_queue
[i
].hq_procp
= NULL
;
hilp
->hl_queue
[i
].hq_devmask
= 0;
for (i
= 0; i
< NHILD
; i
++)
hilp
->hl_device
[i
].hd_qmask
= 0;
hilp
->hl_device
[HILLOOPDEV
].hd_flags
= (HIL_ALIVE
|HIL_PSEUDO
);
* Reset the loop hardware, and collect keyboard/id info
struct proc
*p
= u
.u_procp
; /* XXX */
register struct hilloop
*hilp
= &hil0
; /* XXX */
register struct hilloopdev
*dptr
;
u_char device
= HILUNIT(dev
);
if (hildebug
& HDB_FOLLOW
)
printf("hilopen(%d): device %x\n", p
->p_pid
, device
);
if ((hilp
->hl_device
[HILLOOPDEV
].hd_flags
& HIL_ALIVE
) == 0)
dptr
= &hilp
->hl_device
[device
];
if ((dptr
->hd_flags
& HIL_ALIVE
) == 0)
* Pseudo-devices cannot be read, nothing more to do.
if (dptr
->hd_flags
& HIL_PSEUDO
)
* 1. Open devices have only one of HIL_READIN/HIL_QUEUEIN.
* 2. HPUX processes always get read syscall interface and
* must have exclusive use of the device.
* 3. BSD processes default to shared queue interface.
* Multiple processes can open the device.
if (dptr
->hd_flags
& (HIL_READIN
|HIL_QUEUEIN
))
dptr
->hd_flags
|= HIL_READIN
;
if (dptr
->hd_flags
& HIL_READIN
)
dptr
->hd_flags
|= HIL_QUEUEIN
;
dptr
->hd_flags
|= HIL_NOBLOCK
;
* It is safe to flush the read buffer as we are guarenteed
* that no one else is using it.
ndflush(&dptr
->hd_queue
, dptr
->hd_queue
.c_cc
);
send_hil_cmd(hilp
->hl_addr
, HIL_INTON
, NULL
, 0, NULL
);
* Opened the keyboard, put in raw mode.
if (device
== hilp
->hl_kbddev
) {
send_hil_cmd(hilp
->hl_addr
, HIL_WRITEKBDSADR
, &mask
, 1, NULL
);
hilp
->hl_kbdflags
|= KBD_RAW
;
if (hildebug
& HDB_KEYBOARD
)
printf("hilopen: keyboard %d raw\n", hilp
->hl_kbddev
);
struct proc
*p
= u
.u_procp
; /* XXX */
register struct hilloop
*hilp
= &hil0
; /* XXX */
register struct hilloopdev
*dptr
;
u_char device
= HILUNIT(dev
);
if (hildebug
& HDB_FOLLOW
)
printf("hilclose(%d): device %x\n", p
->p_pid
, device
);
dptr
= &hilp
->hl_device
[device
];
if (device
&& (dptr
->hd_flags
& HIL_PSEUDO
))
if ((p
->p_flag
& SHPUX
) == 0) {
* If this is the loop device,
* free up all queues belonging to this process.
for (i
= 0; i
< NHILQ
; i
++)
if (hilp
->hl_queue
[i
].hq_procp
== p
)
mask
= ~hildevmask(device
);
for (i
= 0; i
< NHILQ
; i
++)
if (hilp
->hl_queue
[i
].hq_procp
== p
) {
dptr
->hd_qmask
&= ~hilqmask(i
);
hilp
->hl_queue
[i
].hq_devmask
&= mask
;
* Always flush the read buffer
dptr
->hd_flags
&= ~(HIL_QUEUEIN
|HIL_READIN
|HIL_NOBLOCK
);
ndflush(&dptr
->hd_queue
, dptr
->hd_queue
.c_cc
);
* Set keyboard back to cooked mode when closed.
if (device
&& device
== hilp
->hl_kbddev
) {
mask
= 1 << (hilp
->hl_kbddev
- 1);
send_hil_cmd(hilp
->hl_addr
, HIL_WRITEKBDSADR
, &mask
, 1, NULL
);
hilp
->hl_kbdflags
&= ~(KBD_RAW
|KBD_AR1
|KBD_AR2
);
* XXX: We have had trouble with keyboards remaining raw
* after close due to the LPC_KBDCOOK bit getting cleared
* somewhere along the line. Hence we check and reset
send_hil_cmd(hilp
->hl_addr
, HIL_READLPCTRL
, NULL
, 0, &lpctrl
);
if ((lpctrl
& LPC_KBDCOOK
) == 0) {
printf("hilclose: bad LPCTRL %x, reset to %x\n",
lpctrl
, lpctrl
|LPC_KBDCOOK
);
send_hil_cmd(hilp
->hl_addr
, HIL_WRITELPCTRL
,
if (hildebug
& HDB_KEYBOARD
)
printf("hilclose: keyboard %d cooked\n",
* Read interface to HIL device.
register struct uio
*uio
;
struct hilloop
*hilp
= &hil0
; /* XXX */
register struct hilloopdev
*dptr
;
u_char device
= HILUNIT(dev
);
* XXX: Don't do this since HP-UX doesn't.
* This check is necessary since loop can reconfigure.
if (device
> hilp
->hl_maxdev
)
dptr
= &hilp
->hl_device
[device
];
if ((dptr
->hd_flags
& HIL_READIN
) == 0)
while (dptr
->hd_queue
.c_cc
== 0) {
if (dptr
->hd_flags
& HIL_NOBLOCK
) {
dptr
->hd_flags
|= HIL_ASLEEP
;
if (error
= tsleep((caddr_t
)dptr
, TTIPRI
| PCATCH
, hilin
, 0)) {
while (uio
->uio_resid
> 0 && error
== 0) {
cc
= hilq_to_b(&dptr
->hd_queue
, buf
,
MIN(uio
->uio_resid
, HILBUFSIZE
));
error
= uiomove(buf
, cc
, uio
);
hilioctl(dev
, cmd
, data
, flag
)
struct proc
*p
= u
.u_procp
; /* XXX */
register struct hilloop
*hilp
= &hil0
; /* XXX */
char device
= HILUNIT(dev
);
if (hildebug
& HDB_FOLLOW
)
printf("hilioctl(%d): dev %x cmd %x\n",
dptr
= &hilp
->hl_device
[device
];
if ((dptr
->hd_flags
& HIL_ALIVE
) == 0)
* Don't allow hardware ioctls on virtual devices.
* Note that though these are the BSD names, they have the same
* values as the HP-UX equivalents so we catch them as well.
if (dptr
->hd_flags
& HIL_PSEUDO
) {
* XXX: should also return ENODEV but HP-UX compat
* breaks if we do. They work ok right now because
* we only recognize one keyboard on the loop. This
* will have to change if we remove that restriction.
return(hpuxhilioctl(dev
, cmd
, data
, flag
));
hilp
->hl_cmdbp
= hilp
->hl_cmdbuf
;
bzero((caddr_t
)hilp
->hl_cmdbuf
, HILBUFSIZE
);
hilp
->hl_cmddev
= device
;
/* Send four data bytes to the tone gererator. */
send_hil_cmd(hilp
->hl_addr
, HIL_STARTCMD
, data
, 4, NULL
);
/* Send the trigger beeper command to the 8042. */
send_hil_cmd(hilp
->hl_addr
, (cmd
& 0xFF), NULL
, 0, NULL
);
/* Transfer the real time to the 8042 data buffer */
send_hil_cmd(hilp
->hl_addr
, (cmd
& 0xFF), NULL
, 0, NULL
);
/* Read each byte of the real time */
for (i
= 0; i
< 5; i
++) {
send_hil_cmd(hilp
->hl_addr
, HIL_READTIME
+ i
, NULL
,
for (i
= 0; i
< 4; i
++) {
send_hil_cmd(hilp
->hl_addr
, (cmd
& 0xFF) + i
,
send_hildev_cmd(hilp
, device
, (cmd
& 0xFF));
bcopy(hilp
->hl_cmdbuf
, data
, hilp
->hl_cmdbp
-hilp
->hl_cmdbuf
);
hilp
->hl_cmddev
= hilp
->hl_kbddev
;
send_hildev_cmd(hilp
, hilp
->hl_kbddev
, (cmd
& 0xFF));
hilp
->hl_kbdflags
&= ~(KBD_AR1
|KBD_AR2
);
hilp
->hl_kbdflags
|= KBD_AR1
;
else if (cmd
== HILIOCAR2
)
hilp
->hl_kbdflags
|= KBD_AR2
;
hilbeep(hilp
, (struct _hilbell
*)data
);
dptr
= &hilp
->hl_device
[device
];
dptr
->hd_flags
|= HIL_NOBLOCK
;
dptr
->hd_flags
&= ~HIL_NOBLOCK
;
* FIOASYNC must be present for FIONBIO above to work!
* (See fcntl in kern_descrip.c).
error
= hilqalloc((struct hilqinfo
*)data
);
error
= hilqfree(((struct hilqinfo
*)data
)->qid
);
error
= hilqmap(*(int *)data
, device
);
error
= hilqunmap(*(int *)data
, device
);
dptr
= &hilp
->hl_device
[device
];
dptr
->hd_flags
|= HIL_READIN
;
dptr
->hd_flags
&= ~HIL_QUEUEIN
;
hildebug
= *(int *) data
;
hpuxhilioctl(dev
, cmd
, data
, flag
)
register struct hilloop
*hilp
= &hil0
; /* XXX */
char device
= HILUNIT(dev
);
hilp
->hl_cmdbp
= hilp
->hl_cmdbuf
;
bzero((caddr_t
)hilp
->hl_cmdbuf
, HILBUFSIZE
);
hilp
->hl_cmddev
= device
;
send_hildev_cmd(hilp
, device
, (cmd
& 0xFF));
bcopy(hilp
->hl_cmdbuf
, data
, hilp
->hl_cmdbp
-hilp
->hl_cmdbuf
);
hilp
->hl_cmddev
= hilp
->hl_kbddev
;
send_hildev_cmd(hilp
, hilp
->hl_kbddev
, (cmd
& 0xFF));
hilp
->hl_kbdflags
&= ~(KBD_AR1
|KBD_AR2
);
hilp
->hl_kbdflags
|= KBD_AR1
;
else if (cmd
== HILIOCAR2
)
hilp
->hl_kbdflags
|= KBD_AR2
;
/* Send four data bytes to the tone gererator. */
send_hil_cmd(hilp
->hl_addr
, HIL_STARTCMD
, data
, 4, NULL
);
/* Send the trigger beeper command to the 8042. */
send_hil_cmd(hilp
->hl_addr
, (cmd
& 0xFF), NULL
, 0, NULL
);
/* Transfer the real time to the 8042 data buffer */
send_hil_cmd(hilp
->hl_addr
, (cmd
& 0xFF), NULL
, 0, NULL
);
/* Read each byte of the real time */
for (i
= 0; i
< 5; i
++) {
send_hil_cmd(hilp
->hl_addr
, HIL_READTIME
+ i
, NULL
,
for (i
= 0; i
< 4; i
++) {
send_hil_cmd(hilp
->hl_addr
, (cmd
& 0xFF) + i
,
send_hil_cmd(hilp
->hl_addr
, (cmd
& 0xFF), NULL
, 0, &hold
);
send_hil_cmd(hilp
->hl_addr
, (cmd
& 0xFF), data
, 1, NULL
);
hilbeep(hilp
, (struct _hilbell
*)data
);
dptr
= &hilp
->hl_device
[device
];
dptr
->hd_flags
|= HIL_NOBLOCK
;
dptr
->hd_flags
&= ~HIL_NOBLOCK
;
* XXX: the mmap inteface for HIL devices should be rethought.
* We used it only briefly in conjuntion with shared queues
* (instead of HILIOCMAPQ ioctl). Perhaps mmap()ing a device
* should give a single queue per process.
struct proc
*p
= u
.u_procp
; /* XXX */
register struct hilloop
*hilp
= &hil0
; /* XXX */
register struct hiliqueue
*qp
;
* Only allow mmap() on loop device
if (HILUNIT(dev
) != 0 || off
>= NHILQ
*sizeof(HILQ
))
* Determine which queue we want based on the offset.
* Queue must belong to calling process.
qp
= &hilp
->hl_queue
[off
/ sizeof(HILQ
)];
return(kvtop((u_int
)qp
->hq_eventqueue
+ off
) >> PGSHIFT
);
struct proc
*p
= u
.u_procp
; /* XXX */
register struct hilloop
*hilp
= &hil0
; /* XXX */
register struct hilloopdev
*dptr
;
register struct hiliqueue
*qp
;
* Return 1 if there is something in the queue, 0 ow.
dptr
= &hilp
->hl_device
[device
];
if (dptr
->hd_flags
& HIL_READIN
) {
if (dptr
->hd_queue
.c_cc
) {
dptr
->hd_selr
->p_wchan
== (caddr_t
)&selwait
)
dptr
->hd_flags
|= HIL_SELCOLL
;
* Make sure device is alive and real (or the loop device).
* Note that we do not do this for the read interface.
* This is primarily to be consistant with HP-UX.
if (device
&& (dptr
->hd_flags
& (HIL_ALIVE
|HIL_PSEUDO
)) != HIL_ALIVE
)
* Select on loop device is special.
* Check to see if there are any data for any loop device
* provided it is associated with a queue belonging to this user.
mask
= hildevmask(device
);
* Must check everybody with interrupts blocked to prevent races.
for (qp
= hilp
->hl_queue
; qp
< &hilp
->hl_queue
[NHILQ
]; qp
++)
if (qp
->hq_procp
== p
&& (mask
& qp
->hq_devmask
) &&
qp
->hq_eventqueue
->hil_evqueue
.head
!=
qp
->hq_eventqueue
->hil_evqueue
.tail
) {
if (dptr
->hd_selr
&& dptr
->hd_selr
->p_wchan
== (caddr_t
)&selwait
)
dptr
->hd_flags
|= HIL_SELCOLL
;
struct hilloop
*hilp
= &hil0
; /* XXX */
register struct hil_dev
*hildevice
= hilp
->hl_addr
;
stat
= hildevice
->hil_stat
;
c
= hildevice
->hil_data
; /* clears interrupt */
hil_process_int(stat
, c
);
register struct hilloop
*hilp
;
if (hildebug
& HDB_EVENTS
)
printf("hilint: %x %x\n", stat
, c
);
/* the shift enables the compiler to generate a jump table */
switch ((stat
>>HIL_SSHIFT
) & HIL_SMASK
) {
case HIL_STATUS
: /* The status info. */
if (c
& HIL_POLLDATA
) /* End of data */
else /* End of command */
hilp
->hl_cmdending
= TRUE
;
if (c
& HIL_POLLDATA
) { /* Start of polled data */
if (hilp
->hl_actdev
!= 0)
hilp
->hl_actdev
= (c
& HIL_DEVMASK
);
hilp
->hl_pollbp
= hilp
->hl_pollbuf
;
} else { /* Start of command */
if (hilp
->hl_cmddev
== (c
& HIL_DEVMASK
)) {
hilp
->hl_cmdbp
= hilp
->hl_cmdbuf
;
if (hilp
->hl_actdev
!= 0) /* Collecting poll data */
else if (hilp
->hl_cmddev
!= 0) /* Collecting cmd data */
if (hilp
->hl_cmdending
) {
hilp
->hl_cmdending
= FALSE
;
case 0: /* force full jump table */
#if defined(DEBUG) && !defined(PANICBUTTON)
* Optimized macro to compute:
* eq->head == (eq->tail + 1) % eq->size
* i.e. has tail caught up with head. We do this because 32 bit long
* remaidering is expensive (a function call with our compiler).
#define HQFULL(eq) (((eq)->head?(eq)->head:(eq)->size) == (eq)->tail+1)
((eq)->size == HEVQSIZE && (eq)->tail >= 0 && (eq)->tail < HEVQSIZE)
register struct hilloopdev
*dptr
= &hilp
->hl_device
[hilp
->hl_actdev
];
register int len
, mask
, qnum
;
register u_char
*cp
, *pp
;
if (panicbutton
&& (*cp
& HIL_KBDDATA
)) {
else if (first
&& *cp
== 0x46 && !panicstr
)
panic("are we having fun yet?");
if (hildebug
& HDB_EVENTS
) {
printf("hilevent: dev %d pollbuf: ", hilp
->hl_actdev
);
* Note that HIL_READIN effectively "shuts off" any queues
* that may have been in use at the time of an HILIOCHPUX call.
if (dptr
->hd_flags
& HIL_READIN
) {
hpuxhilevent(hilp
, dptr
);
* If this device isn't on any queue or there are no data
* in the packet (can this happen?) do nothing.
if (dptr
->hd_qmask
== 0 ||
(len0
= hilp
->hl_pollbp
- hilp
->hl_pollbuf
) <= 0)
* Everybody gets the same time stamp
tenths
= (ourtime
.tv_sec
* 100) + (ourtime
.tv_usec
/ 10000);
for (qnum
= 0; mask
; qnum
++) {
if ((mask
& hilqmask(qnum
)) == 0)
hq
= hilp
->hl_queue
[qnum
].hq_eventqueue
;
* Ensure that queue fields that we rely on are valid
* and that there is space in the queue. If either
* test fails, we just skip this queue.
if (!HQVALID(&hq
->hil_evqueue
) || HQFULL(&hq
->hil_evqueue
))
* If this is the first queue we construct the packet
* with length, timestamp and poll buffer data.
* For second and sucessive packets we just duplicate
pp
= (u_char
*) &hq
->hil_event
[hq
->hil_evqueue
.tail
];
proto
= (hil_packet
*)pp
;
do *pp
++ = *cp
++; while (--len
);
*(hil_packet
*)pp
= *proto
;
if (++hq
->hil_evqueue
.tail
== hq
->hil_evqueue
.size
)
hq
->hil_evqueue
.tail
= 0;
* Wake up anyone selecting on this device or the loop itself
selwakeup(dptr
->hd_selr
, dptr
->hd_flags
& HIL_SELCOLL
);
dptr
->hd_flags
&= ~HIL_SELCOLL
;
dptr
= &hilp
->hl_device
[HILLOOPDEV
];
selwakeup(dptr
->hd_selr
, dptr
->hd_flags
& HIL_SELCOLL
);
dptr
->hd_flags
&= ~HIL_SELCOLL
;
register struct hilloop
*hilp
;
register struct hilloopdev
*dptr
;
* Everybody gets the same time stamp
tstamp
= (ourtime
.tv_sec
* 100) + (ourtime
.tv_usec
/ 10000);
* Each packet that goes into the buffer must be preceded by the
* number of bytes in the packet, and the timestamp of the packet.
* This adds 5 bytes to the packet size. Make sure there is enough
* room in the buffer for it, and if not, toss the packet.
len
= hilp
->hl_pollbp
- hilp
->hl_pollbuf
;
if (dptr
->hd_queue
.c_cc
<= (HILMAXCLIST
- (len
+5))) {
putc(len
+5, &dptr
->hd_queue
);
(void) b_to_q((char *)&tstamp
, sizeof tstamp
, &dptr
->hd_queue
);
(void) b_to_q((char *)hilp
->hl_pollbuf
, len
, &dptr
->hd_queue
);
* Wake up any one blocked on a read or select
if (dptr
->hd_flags
& HIL_ASLEEP
) {
dptr
->hd_flags
&= ~HIL_ASLEEP
;
selwakeup(dptr
->hd_selr
, dptr
->hd_flags
& HIL_SELCOLL
);
dptr
->hd_flags
&= ~HIL_SELCOLL
;
* Shared queue manipulation routines
struct proc
*p
= u
.u_procp
; /* XXX */
register struct hilloop
*hilp
= &hil0
; /* XXX */
if (hildebug
& HDB_FOLLOW
)
printf("hilqalloc(%d): addr %x\n",
for (qnum
= 0; qnum
< NHILQ
; qnum
++)
if (hilp
->hl_queue
[qnum
].hq_procp
== NULL
)
* Allocate and clear memory for the queue
if (hilp
->hl_queue
[qnum
].hq_eventqueue
)
hq
= (HILQ
*) cialloc(sizeof(HILQ
));
bzero((caddr_t
)hq
, sizeof(HILQ
));
hilp
->hl_queue
[qnum
].hq_eventqueue
= hq
;
hq
->hil_evqueue
.size
= HEVQSIZE
;
* Map queue into user address space as instructed
if (u
.u_error
= mmalloc(p
, qnum
, &qip
->addr
, sizeof(HILQ
), MM_RW
|MM_CI
, &hilqops
, &mp
)) {
cifree((caddr_t
)hq
, sizeof(HILQ
));
hilp
->hl_queue
[qnum
].hq_eventqueue
= NULL
;
if (!mmmapin(p
, mp
, hilqmapin
)) {
cifree((caddr_t
)hq
, sizeof(HILQ
));
hilp
->hl_queue
[qnum
].hq_eventqueue
= NULL
;
hilp
->hl_queue
[qnum
].hq_procp
= p
;
hilp
->hl_queue
[qnum
].hq_devmask
= 0;
struct proc
*p
= u
.u_procp
; /* XXX */
register struct hilloop
*hilp
= &hil0
; /* XXX */
register struct mapmem
*mp
;
if (hildebug
& HDB_FOLLOW
)
printf("hilqfree(%d): qnum %d\n",
if (qnum
>= NHILQ
|| hilp
->hl_queue
[qnum
].hq_procp
!= p
)
for (mp
= u
.u_mmap
; mp
; mp
= mp
->mm_next
)
if (qnum
== mp
->mm_id
&& mp
->mm_ops
== &hilqops
) {
register int qnum
, device
;
struct proc
*p
= u
.u_procp
; /* XXX */
register struct hilloop
*hilp
= &hil0
; /* XXX */
register struct hilloopdev
*dptr
= &hilp
->hl_device
[device
];
if (hildebug
& HDB_FOLLOW
)
printf("hilqmap(%d): qnum %d device %x\n",
if (qnum
>= NHILQ
|| hilp
->hl_queue
[qnum
].hq_procp
!= p
)
if ((dptr
->hd_flags
& HIL_QUEUEIN
) == 0)
if (dptr
->hd_qmask
&& u
.u_uid
&& u
.u_uid
!= dptr
->hd_uid
)
hilp
->hl_queue
[qnum
].hq_devmask
|= hildevmask(device
);
dptr
->hd_qmask
|= hilqmask(qnum
);
printf("hilqmap(%d): devmask %x qmask %x\n",
p
->p_pid
, hilp
->hl_queue
[qnum
].hq_devmask
,
register int qnum
, device
;
struct proc
*p
= u
.u_procp
; /* XXX */
register struct hilloop
*hilp
= &hil0
; /* XXX */
if (hildebug
& HDB_FOLLOW
)
printf("hilqunmap(%d): qnum %d device %x\n",
if (qnum
>= NHILQ
|| hilp
->hl_queue
[qnum
].hq_procp
!= p
)
hilp
->hl_queue
[qnum
].hq_devmask
&= ~hildevmask(device
);
hilp
->hl_device
[device
].hd_qmask
&= ~hilqmask(qnum
);
printf("hilqunmap(%d): devmask %x qmask %x\n",
p
->p_pid
, hilp
->hl_queue
[qnum
].hq_devmask
,
hilp
->hl_device
[device
].hd_qmask
);
struct hilloop
*hilp
= &hil0
; /* XXX */
register HILQ
*hq
= hilp
->hl_queue
[mp
->mm_id
].hq_eventqueue
;
if (hq
== NULL
|| off
>= sizeof(HILQ
))
return(kvtop((u_int
)hq
+ off
) >> PGSHIFT
);
* Unmap queue from child's address space
struct proc
*p
= u
.u_procp
; /* XXX */
printf("hilqfork(%d): %s qnum %d\n", p
->p_pid
,
ischild
? "child" : "parent", mp
->mm_id
);
* Associate queue with child when VM resources are passed.
struct hilloop
*hilp
= &hil0
; /* XXX */
register struct hiliqueue
*qp
= &hilp
->hl_queue
[mp
->mm_id
];
printf("hilqvfork(%d): from %x to %x qnum %d, qprocp %x\n",
u
.u_procp
->p_pid
, fup
->u_procp
, tup
->u_procp
,
mp
->mm_id
, qp
->hq_procp
);
if (qp
->hq_procp
== fup
->u_procp
)
qp
->hq_procp
= tup
->u_procp
;
* Unmap all devices and free all queues.
struct proc
*p
= u
.u_procp
; /* XXX */
register struct hilloop
*hilp
= &hil0
; /* XXX */
printf("hilqexit(%d): qnum %d\n", p
->p_pid
, mp
->mm_id
);
* Atomically take all devices off the queue
mask
= ~hilqmask(mp
->mm_id
);
for (i
= 0; i
< NHILD
; i
++)
hilp
->hl_device
[i
].hd_qmask
&= mask
;
* Now unmap from user address space and free queue
cifree((caddr_t
)hilp
->hl_queue
[i
].hq_eventqueue
, sizeof(HILQ
));
hilp
->hl_queue
[i
].hq_eventqueue
= NULL
;
hilp
->hl_queue
[i
].hq_procp
= NULL
;
* This is just a copy of the virgin q_to_b routine with minor
* optimizations for HIL use. It is used for two reasons:
* 1. If we have PAGE mode defined, the normal q_to_b processes
* chars one at a time and breaks on newlines.
* 2. We don't have to raise the priority to spltty() for most
* of the clist manipulations.
register struct clist
*q
;
register struct cblock
*bp
;
q
->c_cf
= q
->c_cl
= NULL
;
nc
= sizeof (struct cblock
) - ((int)q
->c_cf
& CROUND
);
(void) bcopy(q
->c_cf
, cp
, (unsigned)nc
);
bp
= (struct cblock
*)(q
->c_cf
- 1);
bp
= (struct cblock
*)((int)bp
& ~CROUND
);
q
->c_cf
= q
->c_cl
= NULL
;
if (((int)q
->c_cf
& CROUND
) == 0) {
bp
= (struct cblock
*)(q
->c_cf
);
q
->c_cf
= bp
->c_next
->c_info
;
* Cooked keyboard functions for ite driver.
* There is only one "cooked" ITE keyboard (the first keyboard found)
* per loop. There may be other keyboards, but they will always be "raw".
struct hilloop
*hilp
= &hil0
; /* XXX */
hilbeep(hilp
, &default_bell
);
struct hilloop
*hilp
= &hil0
; /* XXX */
register struct hil_dev
*hildevice
= hilp
->hl_addr
;
/* Set the autorepeat rate register */
send_hil_cmd(hildevice
, HIL_SETARR
, &db
, 1, NULL
);
/* Set the autorepeat delay register */
send_hil_cmd(hildevice
, HIL_SETARD
, &db
, 1, NULL
);
send_hil_cmd(hildevice
, HIL_INTON
, NULL
, 0, NULL
);
* XXX: read keyboard directly and return code.
* Used by console getchar routine. Could really screw up anybody
* reading from the keyboard in the normal, interrupt driven fashion.
struct hilloop
*hilp
= &hil0
; /* XXX */
register struct hil_dev
*hildevice
= hilp
->hl_addr
;
while (((stat
= hildevice
->hil_stat
) & HIL_DATA_RDY
) == 0)
* Recoginize and clear keyboard generated NMIs.
* Returns 1 if it was ours, 0 otherwise. Note that we cannot use
* send_hil_cmd() to issue the clear NMI command as that would actually
* lower the priority to splimp() and it doesn't wait for the completion
* of the command. Either of these conditions could result in the
* interrupt reoccuring. Note that we issue the CNMT command twice.
* This seems to be needed, once is not always enough!?!
register struct hilloop
*hilp
= &hil0
; /* XXX */
if ((*KBDNMISTAT
& KBDNMI
) == 0)
hilp
->hl_addr
->hil_cmd
= HIL_CNMT
;
hilp
->hl_addr
->hil_cmd
= HIL_CNMT
;
* Called at boot time to print out info about interesting devices
register struct hilloop
*hilp
;
register struct kbdmap
*km
;
printf("hil%d: ", hilp
->hl_kbddev
);
for (km
= kbd_map
; km
->kbd_code
; km
++)
if (km
->kbd_code
== hilp
->hl_kbdlang
) {
printf("%s ", km
->kbd_desc
);
* Attempt to locate the first ID module and print out its
* security code. Is this a good idea??
hilp
->hl_cmdbp
= hilp
->hl_cmdbuf
;
send_hildev_cmd(hilp
, id
, HILSECURITY
);
len
= hilp
->hl_cmdbp
- hilp
->hl_cmdbuf
;
hilp
->hl_cmdbp
= hilp
->hl_cmdbuf
;
printf("hil%d: security code", id
);
for (id
= 0; id
< len
; id
++)
printf(" %x", hilp
->hl_cmdbuf
[id
]);
* Called after the loop has reconfigured. Here we need to:
* - determine how many devices are on the loop
* (some may have been added or removed)
* - locate the ITE keyboard (if any) and ensure
* that it is in the proper state (raw or cooked)
* and is set to use the proper language mapping table
* - ensure all other keyboards are raw
* Note that our device state is now potentially invalid as
* devices may no longer be where they were. What we should
* do here is either track where the devices went and move
* state around accordingly or, more simply, just mark all
* devices as HIL_DERROR and don't allow any further use until
* they are closed. This is a little too brutal for my tastes,
* we prefer to just assume people won't move things around.
register struct hilloop
*hilp
;
if (hildebug
& HDB_CONFIG
) {
printf("hilconfig: reconfigured: ");
send_hil_cmd(hilp
->hl_addr
, HIL_READLPSTAT
, NULL
, 0, &db
);
printf("LPSTAT %x, ", db
);
send_hil_cmd(hilp
->hl_addr
, HIL_READLPCTRL
, NULL
, 0, &db
);
printf("LPCTRL %x, ", db
);
send_hil_cmd(hilp
->hl_addr
, HIL_READKBDSADR
, NULL
, 0, &db
);
printf("KBDSADR %x\n", db
);
* Determine how many devices are on the loop.
* Mark those as alive and real, all others as dead.
send_hil_cmd(hilp
->hl_addr
, HIL_READLPSTAT
, NULL
, 0, &db
);
hilp
->hl_maxdev
= db
& LPS_DEVMASK
;
for (db
= 1; db
< NHILD
; db
++) {
if (db
<= hilp
->hl_maxdev
)
hilp
->hl_device
[db
].hd_flags
|= HIL_ALIVE
;
hilp
->hl_device
[db
].hd_flags
&= ~HIL_ALIVE
;
hilp
->hl_device
[db
].hd_flags
&= ~HIL_PSEUDO
;
if (hildebug
& (HDB_CONFIG
|HDB_KEYBOARD
))
printf("hilconfig: max device %d\n", hilp
->hl_maxdev
);
if (hilp
->hl_maxdev
== 0) {
* Find out where the keyboards are and record the ITE keyboard
* (first one found). If no keyboards found, we are all done.
send_hil_cmd(hilp
->hl_addr
, HIL_READKBDSADR
, NULL
, 0, &db
);
if (hildebug
& HDB_KEYBOARD
)
printf("hilconfig: keyboard: KBDSADR %x, old %d, new %d\n",
db
, hilp
->hl_kbddev
, ffs((int)db
));
hilp
->hl_kbddev
= ffs((int)db
);
if (hilp
->hl_kbddev
== 0) {
* Determine if the keyboard should be cooked or raw and configure it.
db
= (hilp
->hl_kbdflags
& KBD_RAW
) ? 0 : 1 << (hilp
->hl_kbddev
- 1);
send_hil_cmd(hilp
->hl_addr
, HIL_WRITEKBDSADR
, &db
, 1, NULL
);
* Re-enable autorepeat in raw mode, cooked mode AR is not affected.
if (hilp
->hl_kbdflags
& (KBD_AR1
|KBD_AR2
)) {
db
= (hilp
->hl_kbdflags
& KBD_AR1
) ? HILAR1
: HILAR2
;
hilp
->hl_cmddev
= hilp
->hl_kbddev
;
send_hildev_cmd(hilp
, hilp
->hl_kbddev
, db
);
* Determine the keyboard language configuration, but don't
* override a user-specified setting.
send_hil_cmd(hilp
->hl_addr
, HIL_READKBDLANG
, NULL
, 0, &db
);
if (hildebug
& HDB_KEYBOARD
)
printf("hilconfig: language: old %x new %x\n",
if (hilp
->hl_kbdlang
!= KBD_SPECIAL
) {
for (km
= kbd_map
; km
->kbd_code
; km
++)
if (km
->kbd_code
== db
) {
kbd_keymap
= km
->kbd_keymap
;
kbd_shiftmap
= km
->kbd_shiftmap
;
kbd_ctrlmap
= km
->kbd_ctrlmap
;
kbd_ctrlshiftmap
= km
->kbd_ctrlshiftmap
;
kbd_stringmap
= km
->kbd_stringmap
;
register struct hil_dev
*hildevice
= hilp
->hl_addr
;
* Initialize the loop: reconfigure, don't report errors,
* cook keyboards, and enable autopolling.
db
= LPC_RECONF
| LPC_KBDCOOK
| LPC_NOERROR
| LPC_AUTOPOLL
;
send_hil_cmd(hildevice
, HIL_WRITELPCTRL
, &db
, 1, NULL
);
* Delay one second for reconfiguration and then read the the
* data register to clear the interrupt (if the loop reconfigured).
if (hildevice
->hil_stat
& HIL_DATA_RDY
)
db
= hildevice
->hil_data
;
* The HIL loop may have reconfigured. If so we proceed on,
* if not we loop until a successful reconfiguration is reported
* back to us. The HIL loop will continue to attempt forever.
* Probably not very smart.
send_hil_cmd(hildevice
, HIL_READLPSTAT
, NULL
, 0, &db
);
} while ((db
& (LPS_CONFFAIL
|LPS_CONFGOOD
)) == 0);
* At this point, the loop should have reconfigured.
* The reconfiguration interrupt has already called hilconfig()
* so the keyboard has been determined. All that is left is
send_hil_cmd(hildevice
, HIL_INTON
, NULL
, 0, NULL
);
register struct _hilbell
*bp
;
buf
[0] = ~((bp
->duration
- 10) / 10);
send_hil_cmd(hilp
->hl_addr
, HIL_SETTONE
, buf
, 2, NULL
);
* Locate and return the address of the first ID module, 0 if none present.
register struct hilloop
*hilp
;
if (hildebug
& HDB_IDMODULE
)
printf("hiliddev(%x): looking for idmodule...", hilp
);
for (i
= 1; i
<= hilp
->hl_maxdev
; i
++) {
hilp
->hl_cmdbp
= hilp
->hl_cmdbuf
;
send_hildev_cmd(hilp
, i
, HILIDENTIFY
);
* XXX: the final condition checks to ensure that the
* device ID byte is in the range of the ID module (0x30-0x3F)
len
= hilp
->hl_cmdbp
- hilp
->hl_cmdbuf
;
if (len
> 1 && (hilp
->hl_cmdbuf
[1] & HILSCBIT
) &&
(hilp
->hl_cmdbuf
[0] & 0xF0) == 0x30) {
hilp
->hl_cmdbp
= hilp
->hl_cmdbuf
;
send_hildev_cmd(hilp
, i
, HILSECURITY
);
hilp
->hl_cmdbp
= hilp
->hl_cmdbuf
;
if (hildebug
& HDB_IDMODULE
)
if (i
<= hilp
->hl_maxdev
)
printf("found at %d\n", i
);
return(i
<= hilp
->hl_maxdev
? i
: 0);
* Low level routines which actually talk to the 8042 chip.
* Send a command to the 8042 with zero or more bytes of data.
* If rdata is non-null, wait for and return a byte of data.
* We run at splimp() to make the transaction as atomic as
* possible without blocking the clock (is this necessary?)
send_hil_cmd(hildevice
, cmd
, data
, dlen
, rdata
)
register struct hil_dev
*hildevice
;
hildevice
->hil_cmd
= cmd
;
hildevice
->hil_data
= *data
++;
status
= hildevice
->hil_stat
;
*rdata
= hildevice
->hil_data
;
} while (((status
>> HIL_SSHIFT
) & HIL_SMASK
) != HIL_68K
);
* Send a command to a device on the loop.
* Since only one command can be active on the loop at any time,
* we must ensure that we are not interrupted during this process.
* Hence we mask interrupts to prevent potential access from most
* interrupt routines and turn off auto-polling to disable the
* internally generated poll commands.
* splhigh is extremely conservative but insures atomic operation,
* splimp (clock only interrupts) seems to be good enough in practice.
send_hildev_cmd(hilp
, device
, cmd
)
register struct hilloop
*hilp
;
register struct hil_dev
*hildevice
= hilp
->hl_addr
;
* Transfer the command and device info to the chip
hildevice
->hil_cmd
= HIL_STARTCMD
;
hildevice
->hil_data
= 8 + device
;
hildevice
->hil_data
= cmd
;
hildevice
->hil_data
= HIL_TIMEOUT
;
* Trigger the command and wait for completion
hildevice
->hil_cmd
= HIL_TRIGGER
;
hilp
->hl_cmddone
= FALSE
;
status
= hildevice
->hil_stat
;
hil_process_int(status
, c
);
} while (!hilp
->hl_cmddone
);
* Turn auto-polling off and on.
* Also disables and enable auto-repeat. Why?
register struct hil_dev
*hildevice
;
hildevice
->hil_cmd
= HIL_SETARR
;
hildevice
->hil_cmd
= HIL_READLPCTRL
;
db
= hildevice
->hil_data
;
hildevice
->hil_cmd
= HIL_WRITELPCTRL
;
hildevice
->hil_data
= db
;
* Must wait til polling is really stopped
hildevice
->hil_cmd
= HIL_READBUSY
;
db
= hildevice
->hil_data
;
} while (db
& BSY_LOOPBUSY
);
register struct hil_dev
*hildevice
;
hildevice
->hil_cmd
= HIL_READLPCTRL
;
db
= hildevice
->hil_data
;
hildevice
->hil_cmd
= HIL_WRITELPCTRL
;
hildevice
->hil_data
= db
;
hildevice
->hil_cmd
= HIL_SETARR
;
hildevice
->hil_data
= ar_format(KBD_ARR
);
register struct hilloop
*hilp
;
len
= hilp
->hl_pollbp
- cp
;
for (i
= 0; i
< len
; i
++)
printf("%x ", hilp
->hl_pollbuf
[i
]);
register struct hilloop
*hilp
;
len
= hilp
->hl_cmdbp
- cp
;
for (i
= 0; i
< len
; i
++)
printf("%x ", hilp
->hl_cmdbuf
[i
]);
register struct hilloop
*hilp
;
for (i
= 1; i
<= hilp
->hl_maxdev
; i
++) {
hilp
->hl_cmdbp
= hilp
->hl_cmdbuf
;
send_hildev_cmd(hilp
, i
, HILIDENTIFY
);
printf("hil%d: id: ", i
);
len
= hilp
->hl_cmdbp
- hilp
->hl_cmdbuf
;
if (len
> 1 && (hilp
->hl_cmdbuf
[1] & HILSCBIT
)) {
hilp
->hl_cmdbp
= hilp
->hl_cmdbuf
;
send_hildev_cmd(hilp
, i
, HILSECURITY
);
printf("hil%d: sc: ", i
);
hilp
->hl_cmdbp
= hilp
->hl_cmdbuf
;