Factor out ADB spin-wait timeout loop, and use it for synchronous

operations to access the PRAM RTC, etc. in the IIsi and Cuda cases.
Thanks to Martin Husemann for pointing out the flaw.

This is a slightly more thorough workaround for the issue Martin found
in PR 37611, as it affected more than just adb_read_date_time().
This commit is contained in:
scottr 2008-04-03 05:03:23 +00:00
parent 012e0e0132
commit 776597a46f
3 changed files with 54 additions and 51 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: adb.c,v 1.51 2007/12/03 15:33:51 ad Exp $ */
/* $NetBSD: adb.c,v 1.52 2008/04/03 05:03:23 scottr Exp $ */
/*
* Copyright (C) 1994 Bradley A. Grantham
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: adb.c,v 1.51 2007/12/03 15:33:51 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: adb.c,v 1.52 2008/04/03 05:03:23 scottr Exp $");
#include "opt_adb.h"
@ -271,34 +271,13 @@ adbprint(void *args, const char *name)
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, __UNVOLATILE(&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
*
* This is the total time allowed by the specification. Any
* device that doesn't conform to this will fail to operate
* properly on some Apple systems. In spite of this we
* double the time to wait; some Cuda-based apparently
* queues some commands and allows the main CPU to continue
* processing (radical concept, eh?). To be safe, allow
* time for two complete ADB transactions to occur.
*/
for (tmout = 13800; !flag && tmout >= 10; tmout -= 10)
delay(10);
if (!flag && tmout > 0)
delay(tmout);
adb_spin(&flag);
if (!flag)
result = -2;
}
@ -306,6 +285,37 @@ adb_op_sync(Ptr buffer, Ptr compRout, Ptr data, short command)
return result;
}
/*
* adb_spin
*
* Implements a spin-wait with timeout to be used for synchronous
* operations on the ADB bus.
*
* 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
*
* This is the total time allowed by the specification. Any device that
* doesn't conform to this will fail to operate properly on some Apple
* systems. In spite of this we double the time to wait; Cuda-based
* systems apparently queue commands and allow the main CPU to continue
* processing (how radical!). To be safe, allow time for two complete
* ADB transactions to occur.
*/
void
adb_spin(volatile int *fp)
{
int tmout;
for (tmout = 13800; *fp == 0 && tmout >= 10; tmout -= 10)
delay(10);
if (*fp == 0 && tmout > 0)
delay(tmout);
}
/*
* adb_op_comprout

View File

@ -1,4 +1,4 @@
/* $NetBSD: adb_direct.c,v 1.61 2008/04/01 12:02:52 martin Exp $ */
/* $NetBSD: adb_direct.c,v 1.62 2008/04/03 05:03:23 scottr Exp $ */
/* From: adb_direct.c 2.02 4/18/97 jpw */
@ -62,7 +62,7 @@
#ifdef __NetBSD__
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: adb_direct.c,v 1.61 2008/04/01 12:02:52 martin Exp $");
__KERNEL_RCSID(0, "$NetBSD: adb_direct.c,v 1.62 2008/04/03 05:03:23 scottr Exp $");
#include "opt_adb.h"
@ -2737,15 +2737,9 @@ adb_read_date_time(unsigned long *curtime)
if (result != 0) /* exit if not sent */
return -1;
for (tmout = 13800; !flag && tmout >= 10; tmout -= 10)
delay(10);
if (!flag && tmout > 0)
delay(tmout);
if (!flag) {
printf("WARNING: ADB command did not complete\n");
adb_spin(&flag); /* wait for result */
if (flag == 0) /* exit it timeout */
return -1;
}
*curtime = (long)(*(long *)(output + 1));
return 0;
@ -2762,15 +2756,9 @@ adb_read_date_time(unsigned long *curtime)
if (result != 0) /* exit if not sent */
return -1;
for (tmout = 138000; !flag && tmout >= 10; tmout -= 10)
delay(10);
if (!flag && tmout > 0)
delay(tmout);
if (!flag) {
printf("WARNING: ADB command did not complete\n");
adb_spin(&flag); /* wait for result */
if (flag == 0) /* exit it timeout */
return -1;
}
*curtime = (long)(*(long *)(output + 1));
return 0;
@ -2810,8 +2798,9 @@ adb_set_date_time(unsigned long curtime)
if (result != 0) /* exit if not sent */
return -1;
while (0 == flag) /* wait for send to finish */
;
adb_spin(&flag); /* wait for result */
if (flag == 0) /* exit it timeout */
return -1;
return 0;
@ -2831,8 +2820,9 @@ adb_set_date_time(unsigned long curtime)
if (result != 0) /* exit if not sent */
return -1;
while (0 == flag) /* wait for send to finish */
;
adb_spin(&flag); /* wait for result */
if (flag == 0) /* exit it timeout */
return -1;
return 0;
@ -2910,8 +2900,9 @@ adb_prog_switch_enable(void)
if (result != 0) /* exit if not sent */
return -1;
while (0 == flag) /* wait for send to finish */
;
adb_spin(&flag); /* wait for result */
if (flag == 0) /* exit it timeout */
return -1;
return 0;
@ -2945,8 +2936,9 @@ adb_prog_switch_disable(void)
if (result != 0) /* exit if not sent */
return -1;
while (0 == flag) /* wait for send to finish */
;
adb_spin(&flag); /* wait for result */
if (flag == 0) /* exit it timeout */
return -1;
return 0;

View File

@ -1,4 +1,4 @@
/* $NetBSD: adbvar.h,v 1.24 2007/03/08 02:24:39 tsutsui Exp $ */
/* $NetBSD: adbvar.h,v 1.25 2008/04/03 05:03:23 scottr Exp $ */
/*
* Copyright (C) 1994 Bradley A. Grantham
@ -66,6 +66,7 @@ extern int adb_debug;
void adb_enqevent(adb_event_t *);
int adb_op_sync(Ptr, Ptr, Ptr, short);
void adb_spin(volatile int *);
void adb_op_comprout(void);
/* adbsysasm.s */