Low-level drivers, like the Power Manager driver, can get us into a major

funk when they misbehave and give us unexpected results.  Specifically:

 - Don't assume that the first free slot is at the top of the table if
   we can't find one.
 - Don't increment ADBNumDevices when backfilling "holes" left by devices
   that didn't respond to a TALK R3 during the initial device scan.
 - Don't assume that an address reassignment worked; make sure something
   responds on the new address before plowing forward.
 - If after device reassignment there are no free slots, make sure to
   indicate this fact.
 - Failing all else, handle the situation where we run out of slots in
   the device table -- which now should "never" happen -- gracefully.

While the Power Manager driver still sometimes misbehaves, it shouldn't
cause the system to crash/hang due to us walking off the end of the
device table.
This commit is contained in:
scottr 2000-03-07 06:35:22 +00:00
parent d315d42657
commit 6755970bcf
1 changed files with 33 additions and 13 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: adb_direct.c,v 1.38 2000/02/21 02:04:48 scottr Exp $ */
/* $NetBSD: adb_direct.c,v 1.39 2000/03/07 06:35:22 scottr Exp $ */
/* From: adb_direct.c 2.02 4/18/97 jpw */
@ -2148,11 +2148,13 @@ adb_reinit(void)
/* initial scan through the devices */
for (i = 1; i < 16; i++) {
command = (int)(0x0f | ((int)(i & 0x000f) << 4)); /* talk R3 */
command = ((int)(i & 0xf) << 4) | 0xf; /* talk R3 */
result = adb_op_sync((Ptr)send_string, (Ptr)0,
(Ptr)0, (short)command);
if (0x00 != send_string[0]) { /* anything come back ?? */
ADBDevTable[++ADBNumDevices].devType =
++ADBNumDevices;
KASSERT(ADBNumDevices < 16);
ADBDevTable[ADBNumDevices].devType =
(int)(send_string[2]);
ADBDevTable[ADBNumDevices].origAddr = i;
ADBDevTable[ADBNumDevices].currentAddr = i;
@ -2169,9 +2171,6 @@ adb_reinit(void)
if (-1 == get_adb_info(&data, saveptr))
break;
if (saveptr == 0) /* no free addresses??? */
saveptr = 15;
#ifdef ADB_DEBUG
if (adb_debug & 0x80) {
printf_intr("first free is: 0x%02x\n", saveptr);
@ -2180,7 +2179,7 @@ adb_reinit(void)
#endif
nonewtimes = 0; /* no loops w/o new devices */
while (nonewtimes++ < 11) {
while (saveptr > 0 && nonewtimes++ < 11) {
for (i = 1; i <= ADBNumDevices; i++) {
device = ADBDevTable[i].currentAddr;
#ifdef ADB_DEBUG
@ -2190,12 +2189,12 @@ adb_reinit(void)
#endif
/* send TALK R3 to address */
command = (int)(0x0f | ((int)(device & 0x000f) << 4));
command = ((int)(device & 0xf) << 4) | 0xf;
adb_op_sync((Ptr)send_string, (Ptr)0,
(Ptr)0, (short)command);
/* move device to higher address */
command = (int)(0x0b | ((int)(device & 0x000f) << 4));
command = ((int)(device & 0xf) << 4) | 0xb;
send_string[0] = 2;
send_string[1] = (u_char)(saveptr | 0x60);
send_string[2] = 0xfe;
@ -2203,8 +2202,22 @@ adb_reinit(void)
(Ptr)0, (short)command);
delay(500);
/* send TALK R3 - anthing at new address? */
command = ((int)(saveptr & 0xf) << 4) | 0xf;
adb_op_sync((Ptr)send_string, (Ptr)0,
(Ptr)0, (short)command);
delay(500);
if (send_string[0] == 0) {
#ifdef ADB_DEBUG
if (adb_debug & 0x80)
printf_intr("failed, continuing\n");
#endif
continue;
}
/* send TALK R3 - anything at old address? */
command = (int)(0x0f | ((int)(device & 0x000f) << 4));
command = ((int)(device & 0xf) << 4) | 0xf;
result = adb_op_sync((Ptr)send_string, (Ptr)0,
(Ptr)0, (short)command);
if (send_string[0] != 0) {
@ -2220,7 +2233,11 @@ adb_reinit(void)
if (adb_debug & 0x80)
printf_intr("new device found\n");
#endif
ADBDevTable[++ADBNumDevices].devType =
if (saveptr > ADBNumDevices) {
++ADBNumDevices;
KASSERT(ADBNumDevices < 16);
}
ADBDevTable[ADBNumDevices].devType =
(int)(send_string[2]);
ADBDevTable[ADBNumDevices].origAddr = device;
ADBDevTable[ADBNumDevices].currentAddr = device;
@ -2231,11 +2248,14 @@ adb_reinit(void)
ADBDevTable[ADBNumDevices].ServiceRtPtr =
(void *)0;
/* find next unused address */
for (x = saveptr; x > 0; x--)
for (x = saveptr; x > 0; x--) {
if (-1 == get_adb_info(&data, x)) {
saveptr = x;
break;
}
}
if (x == 0)
saveptr = 0;
#ifdef ADB_DEBUG
if (adb_debug & 0x80)
printf_intr("new free is 0x%02x\n",
@ -2250,7 +2270,7 @@ adb_reinit(void)
printf_intr("moving back...\n");
#endif
/* move old device back */
command = (int)(0x0b | ((int)(saveptr & 0x000f) << 4));
command = ((int)(saveptr & 0xf) << 4) | 0xb;
send_string[0] = 2;
send_string[1] = (u_char)(device | 0x60);
send_string[2] = 0xfe;