Stabilize ADB support for some non-Apple ADB peripherals. This is the

second (and final) part of the fix for PR 10086.  (There are no longer
any infinite-wait busy loops in the ADB driver!)
This commit is contained in:
scottr 2000-07-03 08:59:26 +00:00
parent 34c3137212
commit d08e3b12a4
6 changed files with 177 additions and 220 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: adb.c,v 1.36 2000/06/18 22:58:45 scottr Exp $ */
/* $NetBSD: adb.c,v 1.37 2000/07/03 08:59:26 scottr Exp $ */
/*
* Copyright (C) 1994 Bradley A. Grantham
@ -255,3 +255,64 @@ adbprint(args, name)
return (rv);
}
/*
* adb_op_sync
*
* This routine does exactly what the adb_op routine does, except that after
* the adb_op is called, it waits until the return value is present before
* returning.
*
* NOTE: The user specified compRout is ignored, since this routine specifies
* it's own to adb_op, which is why you really called this in the first place
* anyway.
*/
int
adb_op_sync(Ptr buffer, Ptr compRout, Ptr data, short command)
{
int tmout;
int result;
volatile int flag = 0;
result = ADBOp(buffer, (void *)adb_op_comprout,
(void *)&flag, command); /* send command */
if (result == 0) { /* send ok? */
/*
* Total time to wait is calculated as follows:
* - Tlt (stop to start time): 260 usec
* - start bit: 100 usec
* - up to 8 data bytes: 64 * 100 usec = 6400 usec
* - stop bit (with SRQ): 140 usec
* Total: 6900 usec
*/
tmout = 6900;
for (tmout = 6900; !flag && tmout >= 10; tmout -= 10)
delay(10);
if (!flag && tmout > 0)
delay(tmout);
if (!flag)
result = -2;
}
return result;
}
/*
* adb_op_comprout
*
* This function is used by the adb_op_sync routine so it knows when the
* function is done.
*/
void
adb_op_comprout(void)
{
#ifdef __NetBSD__
asm("movw #1,a2@ | update flag value");
#else /* for macos based testing */
asm {
move.w #1,(a2) } /* update flag value */
#endif
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: adb_direct.c,v 1.42 2000/03/23 06:39:55 thorpej Exp $ */
/* $NetBSD: adb_direct.c,v 1.43 2000/07/03 08:59:26 scottr Exp $ */
/* From: adb_direct.c 2.02 4/18/97 jpw */
@ -303,7 +303,6 @@ int get_adb_info __P((ADBDataBlock *, int));
int set_adb_info __P((ADBSetInfoBlock *, int));
void adb_setup_hw_type __P((void));
int adb_op __P((Ptr, Ptr, Ptr, short));
int adb_op_sync __P((Ptr, Ptr, Ptr, short));
void adb_read_II __P((u_char *));
void adb_hw_setup __P((void));
void adb_hw_setup_IIsi __P((u_char *));
@ -2120,8 +2119,10 @@ adb_reinit(void)
* Initialize the ADB table. For now, we'll always use the same table
* that is defined at the beginning of this file - no mallocs.
*/
for (i = 0; i < 16; i++)
for (i = 0; i < 16; i++) {
ADBDevTable[i].devType = 0;
ADBDevTable[i].origAddr = ADBDevTable[i].currentAddr = 0;
}
adb_setup_hw_type(); /* setup hardware type */
@ -2130,7 +2131,7 @@ adb_reinit(void)
delay(1000);
/* send an ADB reset first */
adb_op_sync((Ptr)0, (Ptr)0, (Ptr)0, (short)0x00);
(void)adb_op_sync((Ptr)0, (Ptr)0, (Ptr)0, (short)0x00);
delay(3000);
/*
@ -2156,16 +2157,7 @@ adb_reinit(void)
result = adb_op_sync((Ptr)send_string, (Ptr)0,
(Ptr)0, (short)command);
if (send_string[0] != 0) {
/* check for valid device handler */
switch (send_string[2]) {
case 0:
case 0xfd:
case 0xfe:
case 0xff:
continue; /* invalid, skip */
}
if (result == 0 && send_string[0] != 0) {
/* found a device */
++ADBNumDevices;
KASSERT(ADBNumDevices < 16);
@ -2195,7 +2187,7 @@ adb_reinit(void)
nonewtimes = 0; /* no loops w/o new devices */
while (saveptr > 0 && nonewtimes++ < 11) {
for (i = 1; i <= ADBNumDevices; i++) {
for (i = 1;saveptr > 0 && i <= ADBNumDevices; i++) {
device = ADBDevTable[i].currentAddr;
#ifdef ADB_DEBUG
if (adb_debug & 0x80)
@ -2205,7 +2197,7 @@ adb_reinit(void)
/* send TALK R3 to address */
command = ADBTALK(device, 3);
adb_op_sync((Ptr)send_string, (Ptr)0,
(void)adb_op_sync((Ptr)send_string, (Ptr)0,
(Ptr)0, (short)command);
/* move device to higher address */
@ -2213,38 +2205,43 @@ adb_reinit(void)
send_string[0] = 2;
send_string[1] = (u_char)(saveptr | 0x60);
send_string[2] = 0xfe;
adb_op_sync((Ptr)send_string, (Ptr)0,
(void)adb_op_sync((Ptr)send_string, (Ptr)0,
(Ptr)0, (short)command);
delay(500);
delay(1000);
/* send TALK R3 - anthing at new address? */
command = ADBTALK(saveptr, 3);
adb_op_sync((Ptr)send_string, (Ptr)0,
send_string[0] = 0;
result = adb_op_sync((Ptr)send_string, (Ptr)0,
(Ptr)0, (short)command);
delay(500);
delay(1000);
if (send_string[0] == 0) {
if (result != 0 || send_string[0] == 0) {
/*
* maybe there's a communication breakdown;
* just in case, move it back from whence it
* came, and we'll try again later
*/
command = ADBLISTEN(saveptr, 3);
send_string[0] = 2;
send_string[1] = (u_char)(device | 0x60);
send_string[2] = 0x00;
(void)adb_op_sync((Ptr)send_string, (Ptr)0,
(Ptr)0, (short)command);
#ifdef ADB_DEBUG
if (adb_debug & 0x80)
printf_intr("failed, continuing\n");
#endif
delay(1000);
continue;
}
/* send TALK R3 - anything at old address? */
command = ADBTALK(device, 3);
send_string[0] = 0;
result = adb_op_sync((Ptr)send_string, (Ptr)0,
(Ptr)0, (short)command);
if (send_string[0] != 0) {
/* check for valid device handler */
switch (send_string[2]) {
case 0:
case 0xfd:
case 0xfe:
case 0xff:
continue; /* invalid, skip */
}
if (result == 0 && send_string[0] != 0) {
/* new device found */
/* update data for previously moved device */
ADBDevTable[i].currentAddr = saveptr;
@ -2298,7 +2295,7 @@ adb_reinit(void)
send_string[0] = 2;
send_string[1] = (u_char)(device | 0x60);
send_string[2] = 0xfe;
adb_op_sync((Ptr)send_string, (Ptr)0,
(void)adb_op_sync((Ptr)send_string, (Ptr)0,
(Ptr)0, (short)command);
delay(1000);
}
@ -2463,50 +2460,6 @@ adb_cmd_extra(u_char *in)
}
/*
* adb_op_sync
*
* This routine does exactly what the adb_op routine does, except that after
* the adb_op is called, it waits until the return value is present before
* returning.
*
* NOTE: The user specified compRout is ignored, since this routine specifies
* it's own to adb_op, which is why you really called this in the first place
* anyway.
*/
int
adb_op_sync(Ptr buffer, Ptr compRout, Ptr data, short command)
{
int result;
volatile int flag = 0;
result = adb_op(buffer, (void *)adb_op_comprout,
(void *)&flag, command); /* send command */
if (result == 0) /* send ok? */
while (0 == flag)
/* wait for compl. routine */;
return result;
}
/*
* adb_op_comprout
*
* This function is used by the adb_op_sync routine so it knows when the
* function is done.
*/
void
adb_op_comprout(void)
{
#ifdef __NetBSD__
asm("movw #1,a2@ | update flag value");
#else /* for macos based testing */
asm {
move.w #1,(a2) } /* update flag value */
#endif
}
void
adb_setup_hw_type(void)
{
@ -2657,7 +2610,7 @@ count_adbs(void)
found = 0;
for (i = 1; i < 16; i++)
if (0 != ADBDevTable[i].devType)
if (0 != ADBDevTable[i].currentAddr)
found++;
return found;

View File

@ -1,4 +1,4 @@
/* $NetBSD: adbvar.h,v 1.18 2000/03/19 07:44:58 scottr Exp $ */
/* $NetBSD: adbvar.h,v 1.19 2000/07/03 08:59:27 scottr Exp $ */
/*
* Copyright (C) 1994 Bradley A. Grantham
@ -73,6 +73,9 @@ int adbwrite __P((dev_t dev, struct uio *uio, int flag));
int adbioctl __P((dev_t , int , caddr_t , int , struct proc *));
int adbpoll __P((dev_t dev, int events, struct proc *p));
int adb_op_sync __P((Ptr, Ptr, Ptr, short));
void adb_op_comprout __P((void));
/* adbsysasm.s */
void adb_kbd_asmcomplete __P((void));
void adb_ms_asmcomplete __P((void));

View File

@ -1,4 +1,4 @@
/* $NetBSD: akbd.c,v 1.9 2000/06/17 18:00:47 scottr Exp $ */
/* $NetBSD: akbd.c,v 1.10 2000/07/03 08:59:27 scottr Exp $ */
/*
* Copyright (C) 1998 Colin Wood
@ -78,7 +78,6 @@ static void blinkleds __P((struct akbd_softc *));
/*
* Local variables.
*/
static volatile int kbd_done; /* Did ADBOp() complete? */
/* Driver definition. */
struct cfattach akbd_ca = {
@ -87,7 +86,7 @@ struct cfattach akbd_ca = {
extern struct cfdriver akbd_cd;
int kbd_intr __P((adb_event_t *event));
int kbd_intr __P((adb_event_t *event, struct akbd_softc *));
int akbd_enable __P((void *, int));
void akbd_set_leds __P((void *, int));
int akbd_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
@ -136,7 +135,7 @@ akbdattach(parent, self, aux)
ADBSetInfoBlock adbinfo;
struct akbd_softc *sc = (struct akbd_softc *)self;
struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
int count, error;
int error, kbd_done;
short cmd;
u_char buffer[9];
#if NWSKBD > 0
@ -163,15 +162,9 @@ akbdattach(parent, self, aux)
printf("standard keyboard (ISO layout)\n");
break;
case ADB_EXTKBD:
kbd_done = 0;
cmd = ADBTALK(sc->adbaddr, 1);
ADBOp((Ptr)buffer, (Ptr)extdms_complete,
(Ptr)&kbd_done, cmd);
/* Wait until done, but no more than 2 secs */
count = 40000;
while (!kbd_done && count-- > 0)
delay(50);
kbd_done =
(adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd) == 0);
/* Ignore Logitech MouseMan/Trackman pseudo keyboard */
if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x20) {
@ -337,7 +330,7 @@ kbd_processevent(event, ksc)
#endif
#if NWSKBD > 0
if (ksc->sc_wskbddev != NULL) /* wskbd is attached? */
kbd_intr(&new_event);
kbd_intr(&new_event, ksc);
#else
/* do nothing */ ;
#endif
@ -350,7 +343,7 @@ kbd_processevent(event, ksc)
#endif
#if NWSKBD > 0
if (ksc->sc_wskbddev != NULL) /* wskbd is attached? */
kbd_intr(&new_event);
kbd_intr(&new_event, ksc);
#else
/* do nothing */ ;
#endif
@ -371,14 +364,10 @@ getleds(addr)
leds = 0x00; /* all off */
buffer[0] = 0;
kbd_done = 0;
cmd = ADBTALK(addr, 2);
ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&kbd_done, cmd);
while (!kbd_done)
/* busy-wait until done */ ;
if (buffer[0] > 0)
if (adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd) == 0 &&
buffer[0] > 0)
leds = ~(buffer[2]) & 0x07;
return (leds);
@ -404,14 +393,9 @@ setleds(ksc, leds)
addr = ksc->adbaddr;
buffer[0] = 0;
kbd_done = 0;
cmd = ADBTALK(addr, 2);
ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&kbd_done, cmd);
while (!kbd_done)
/* busy-wait until done */ ;
if (buffer[0] == 0)
if (adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd) || buffer[0] == 0)
return (EIO);
leds = ~leds & 0x07;
@ -419,17 +403,11 @@ setleds(ksc, leds)
buffer[2] |= leds;
cmd = ADBLISTEN(addr, 2);
ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&kbd_done, cmd);
while (!kbd_done)
/* busy-wait until done */ ;
adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd);
/* talk R2 */
cmd = ADBTALK(addr, 2);
ADBOp((Ptr)buffer, (Ptr)extdms_complete, (Ptr)&kbd_done, cmd);
while (!kbd_done)
/* busy-wait until done */ ;
if (buffer[0] == 0)
if (adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd) || buffer[0] == 0)
return (EIO);
ksc->sc_leds = ~((u_int8_t)buffer[2]) & 0x07;
@ -473,10 +451,8 @@ int
akbd_is_console()
{
extern struct mac68k_machine_S mac68k_machine;
static int akbd_console_initted = 0;
return ((mac68k_machine.serial_console & 0x03) == 0) &&
(++akbd_console_initted == 1);
return ((mac68k_machine.serial_console & 0x03) == 0);
}
int
@ -529,14 +505,13 @@ static int polledkey;
extern int adb_polling;
int
kbd_intr(event)
kbd_intr(event, sc)
adb_event_t *event;
struct akbd_softc *sc;
{
int key, press, val;
int type;
struct akbd_softc *sc = akbd_cd.cd_devs[0];
key = event->u.k.key;
press = ADBK_PRESS(key);
val = ADBK_KEYVAL(key);
@ -560,7 +535,9 @@ kbd_intr(event)
int
akbd_cnattach()
{
if (!akbd_is_console())
static int akbd_console_initted = 0;
if ((++akbd_console_initted > 1) || !akbd_is_console())
return -1;
wskbd_cnattach(&akbd_consops, NULL, &akbd_keymapdata);

View File

@ -1,4 +1,4 @@
/* $NetBSD: ams.c,v 1.8 2000/06/11 17:26:47 scottr Exp $ */
/* $NetBSD: ams.c,v 1.9 2000/07/03 08:59:27 scottr Exp $ */
/*
* Copyright (C) 1998 Colin Wood
@ -69,8 +69,6 @@ extern int kbd_polling; /* Are we polling (Debugger mode)? from kbd.c */
/*
* Local variables.
*/
static volatile int extdms_done; /* Did ADBOp() complete? */
/* Driver definition. */
struct cfattach ams_ca = {
@ -220,7 +218,7 @@ void
ems_init(sc)
struct ams_softc * sc;
{
int adbaddr, count;
int adbaddr;
short cmd;
u_char buffer[9];
@ -256,11 +254,7 @@ ems_init(sc)
buffer[4] = 0x07; /* Locking mask = 0000b,
* enable buttons = 0111b
*/
extdms_done = 0;
ADBOp((Ptr)buffer, (Ptr)extdms_complete,
(Ptr)&extdms_done, cmd);
while (!extdms_done)
/* busy wait until done */;
adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd);
sc->sc_buttons = 3;
sc->sc_res = 200;
@ -270,52 +264,41 @@ ems_init(sc)
(sc->handler_id == ADBMS_200DPI)) {
/* found a mouse */
cmd = ADBTALK(adbaddr, 3);
extdms_done = 0;
ADBOp((Ptr)buffer, (Ptr)extdms_complete,
(Ptr)&extdms_done, cmd);
/* Wait until done, but no more than 2 secs */
count = 40000;
while (!extdms_done && count-- > 0)
delay(50);
if (!extdms_done) {
if (adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd)) {
#ifdef ADB_DEBUG
if (adb_debug)
printf("adb: extdms_init timed out\n");
printf("adb: ems_init timed out\n");
#endif
return;
}
/* Attempt to initialize Extended Mouse Protocol */
buffer[2] = '\004'; /* make handler ID 4 */
extdms_done = 0;
buffer[2] = 4; /* make handler ID 4 */
cmd = ADBLISTEN(adbaddr, 3);
ADBOp((Ptr)buffer, (Ptr)extdms_complete,
(Ptr)&extdms_done, cmd);
while (!extdms_done)
/* busy wait until done */;
if (adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd)) {
#ifdef ADB_DEBUG
if (adb_debug)
printf("adb: ems_init timed out\n");
#endif
return;
}
/*
* Check to see if successful, if not
* try to initialize it as other types
*/
cmd = ADBTALK(adbaddr, 3);
extdms_done = 0;
ADBOp((Ptr)buffer, (Ptr)extdms_complete,
(Ptr)&extdms_done, cmd);
while (!extdms_done)
/* busy wait until done */;
adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd);
if (buffer[2] == ADBMS_EXTENDED) {
sc->handler_id = ADBMS_EXTENDED;
extdms_done = 0;
/* talk register 1 */
ADBOp((Ptr)buffer, (Ptr)extdms_complete,
(Ptr)&extdms_done, (adbaddr << 4) | 0xd);
while (!extdms_done)
/* busy-wait until done */;
if (buffer[0] == 8) {
cmd = ADBTALK(adbaddr, 1);
if (adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd)) {
#ifdef ADB_DEBUG
if (adb_debug)
printf("adb: ems_init timed out\n");
#endif
} else if (buffer[0] == 8) {
/* we have a true EMP device */
sc->sc_class = buffer[7];
sc->sc_buttons = buffer[8];
@ -328,42 +311,30 @@ ems_init(sc)
* button bits in 3rd byte instead of sending
* via pseudo keyboard device.
*/
extdms_done = 0;
/* listen register 1 */
cmd = ADBLISTEN(adbaddr, 1);
buffer[0]=2;
buffer[1]=0x00;
buffer[2]=0x81;
ADBOp((Ptr)buffer, (Ptr)extdms_complete,
(Ptr)&extdms_done, (adbaddr << 4) | 0x9);
while (!extdms_done)
/* busy-wait until done */;
extdms_done = 0;
/* listen register 1 */
adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd);
cmd = ADBLISTEN(adbaddr, 1);
buffer[0]=2;
buffer[1]=0x01;
buffer[2]=0x81;
ADBOp((Ptr)buffer, (Ptr)extdms_complete,
(Ptr)&extdms_done, (adbaddr << 4) | 0x9);
while (!extdms_done)
/* busy-wait until done */;
extdms_done = 0;
/* listen register 1 */
adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd);
cmd = ADBLISTEN(adbaddr, 1);
buffer[0]=2;
buffer[1]=0x02;
buffer[2]=0x81;
ADBOp((Ptr)buffer, (Ptr)extdms_complete,
(Ptr)&extdms_done, (adbaddr << 4) | 0x9);
while (!extdms_done)
/* busy-wait until done */;
extdms_done = 0;
/* listen register 1 */
adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd);
cmd = ADBLISTEN(adbaddr, 1);
buffer[0]=2;
buffer[1]=0x03;
buffer[2]=0x38;
ADBOp((Ptr)buffer, (Ptr)extdms_complete,
(Ptr)&extdms_done, (adbaddr << 4) | 0x9);
while (!extdms_done)
/* busy-wait until done */;
adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd);
sc->sc_buttons = 3;
sc->sc_res = 400;
if (buffer[2] == 0x21)
@ -375,23 +346,21 @@ ems_init(sc)
} else {
/* Attempt to initialize as an A3 mouse */
buffer[2] = 0x03; /* make handler ID 3 */
extdms_done = 0;
cmd = ADBLISTEN(adbaddr, 3);
ADBOp((Ptr)buffer, (Ptr)extdms_complete,
(Ptr)&extdms_done, cmd);
while (!extdms_done)
/* busy wait until done */;
if (adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd)) {
#ifdef ADB_DEBUG
if (adb_debug)
printf("adb: ems_init timed out\n");
#endif
return;
}
/*
* Check to see if successful, if not
* try to initialize it as other types
*/
cmd = ADBTALK(adbaddr, 3);
extdms_done = 0;
ADBOp((Ptr)buffer, (Ptr)extdms_complete,
(Ptr)&extdms_done, cmd);
while (!extdms_done)
/* busy wait until done */;
adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd);
if (buffer[2] == ADBMS_MSA3) {
sc->handler_id = ADBMS_MSA3;
@ -406,11 +375,7 @@ ems_init(sc)
* enable 3 button mode = 0111b,
* speed = normal
*/
extdms_done = 0;
ADBOp((Ptr)buffer, (Ptr)extdms_complete,
(Ptr)&extdms_done, cmd);
while (!extdms_done)
/* busy wait until done */;
adb_op_sync((Ptr)buffer, (Ptr)0, (Ptr)0, cmd);
sc->sc_buttons = 3;
sc->sc_res = 300;
} else {

View File

@ -1,4 +1,4 @@
/* $NetBSD: pm_direct.c,v 1.13 2000/04/05 07:29:18 scottr Exp $ */
/* $NetBSD: pm_direct.c,v 1.14 2000/07/03 08:59:27 scottr Exp $ */
/*
* Copyright (C) 1997 Takashi Hamada
@ -385,9 +385,9 @@ pm_receive_pm1(data)
* Send data to PM for the PB1XX series
*/
int
pm_send_pm1(data, delay)
pm_send_pm1(data, timo)
u_char data;
int delay;
int timo;
{
int rval;
@ -395,18 +395,20 @@ pm_send_pm1(data, delay)
via_reg(VIA2, 0x200) = data;
PM_SET_STATE_ACKOFF();
if (pm_wait_busy(0x400) != 0) {
#if 0
if (pm_wait_busy(0x400) == 0) {
#else
if (pm_wait_busy(timo) == 0) {
#endif
PM_SET_STATE_ACKON();
via_reg(VIA2, vDirA) = 0x00;
return 0xffffcd36;
if (pm_wait_free(0x40) != 0)
rval = 0x0;
else
rval = 0xffffcd35;
} else {
rval = 0xffffcd36;
}
rval = 0x0;
PM_SET_STATE_ACKON();
if (pm_wait_free(0x40) == 0)
rval = 0xffffcd35;
PM_SET_STATE_ACKON();
via_reg(VIA2, vDirA) = 0x00;
@ -668,20 +670,16 @@ pm_send_pm2(data)
PM_SR() = data;
PM_SET_STATE_ACKOFF();
rval = 0xffffcd36;
if (pm_wait_busy((int)ADBDelay*32) != 0) {
if (pm_wait_busy((int)ADBDelay*32) == 0) {
PM_SET_STATE_ACKON();
via_reg(VIA1, vACR) |= 0x1c;
return rval;
if (pm_wait_free((int)ADBDelay*32) != 0)
rval = 0;
else
rval = 0xffffcd35;
} else {
rval = 0xffffcd36;
}
PM_SET_STATE_ACKON();
rval = 0xffffcd35;
if (pm_wait_free((int)ADBDelay*32) != 0)
rval = 0;
PM_SET_STATE_ACKON();
via_reg(VIA1, vACR) |= 0x1c;