summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2008-12-06 23:26:02 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2008-12-06 23:26:02 +0000
commite6bc656165feaa55eb1bb3b7ba07f1e02c7e307b (patch)
treec72b76b735b5bc154e27235b50a32c00ae045050 /sys/dev
parenta689f483835ae8389214b38c9fce209311c1a019 (diff)
downloadFreeBSD-src-e6bc656165feaa55eb1bb3b7ba07f1e02c7e307b.zip
FreeBSD-src-e6bc656165feaa55eb1bb3b7ba07f1e02c7e307b.tar.gz
Fix some nasty race conditions in the VIA-CUDA driver that ended up preventing
my right mouse button and keyboard LEDs from working due to mangled configuration packets. Fixed several other races and associated problems in the main ADB stack that were exposed while fixing this.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/adb/adb.h2
-rw-r--r--sys/dev/adb/adb_bus.c71
-rw-r--r--sys/dev/adb/adb_kbd.c14
-rw-r--r--sys/dev/adb/adb_mouse.c2
-rw-r--r--sys/dev/adb/adbvar.h1
5 files changed, 39 insertions, 51 deletions
diff --git a/sys/dev/adb/adb.h b/sys/dev/adb/adb.h
index 8d68a87..10c3db2 100644
--- a/sys/dev/adb/adb.h
+++ b/sys/dev/adb/adb.h
@@ -68,7 +68,7 @@ uint8_t adb_get_device_type(device_t dev);
uint8_t adb_get_device_handler(device_t dev);
uint8_t adb_set_device_handler(device_t dev, uint8_t newhandler);
-uint8_t adb_read_register(device_t dev, u_char reg, size_t *len, void *data);
+size_t adb_read_register(device_t dev, u_char reg, void *data);
/* Bits for implementing ADB host bus adapters */
extern devclass_t adb_devclass;
diff --git a/sys/dev/adb/adb_bus.c b/sys/dev/adb/adb_bus.c
index 9c00144..faab048 100644
--- a/sys/dev/adb/adb_bus.c
+++ b/sys/dev/adb/adb_bus.c
@@ -48,7 +48,7 @@ static void adb_bus_enumerate(void *xdev);
static void adb_probe_nomatch(device_t dev, device_t child);
static int adb_print_child(device_t dev, device_t child);
-static int adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, uint8_t reg, int len, u_char *data);
+static int adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, uint8_t reg, int len, u_char *data, u_char *reply);
static char *adb_device_string[] = {
"HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc"
@@ -118,8 +118,7 @@ adb_bus_enumerate(void *xdev)
sc->packet_reply = 0;
sc->autopoll_mask = 0;
-
- mtx_init(&sc->sc_sync_mtx,"adbsyn",NULL,MTX_DEF | MTX_RECURSE);
+ sc->sync_packet = 0xffff;
/* Initialize devinfo */
for (i = 0; i < 16; i++) {
@@ -128,7 +127,7 @@ adb_bus_enumerate(void *xdev)
}
/* Reset ADB bus */
- adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL);
+ adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL,NULL);
DELAY(1500);
/* Enumerate bus */
@@ -140,7 +139,7 @@ adb_bus_enumerate(void *xdev)
do {
reply = adb_send_raw_packet_sync(dev,i,
- ADB_COMMAND_TALK,3,0,NULL);
+ ADB_COMMAND_TALK,3,0,NULL,NULL);
if (reply) {
/* If we got a response, relocate to next_free */
@@ -150,10 +149,10 @@ adb_bus_enumerate(void *xdev)
r3 |= 0x00fe;
adb_send_raw_packet_sync(dev,i, ADB_COMMAND_LISTEN,3,
- sizeof(uint16_t),(u_char *)(&r3));
+ sizeof(uint16_t),(u_char *)(&r3),NULL);
adb_send_raw_packet_sync(dev,next_free,
- ADB_COMMAND_TALK,3,0,NULL);
+ ADB_COMMAND_TALK,3,0,NULL,NULL);
sc->devinfo[next_free].default_address = i;
if (first_relocated < 0)
@@ -169,9 +168,9 @@ adb_bus_enumerate(void *xdev)
adb_send_raw_packet_sync(dev,first_relocated,
ADB_COMMAND_LISTEN,3,
- sizeof(uint16_t),(u_char *)(&r3));
+ sizeof(uint16_t),(u_char *)(&r3),NULL);
adb_send_raw_packet_sync(dev,i,
- ADB_COMMAND_TALK,3,0,NULL);
+ ADB_COMMAND_TALK,3,0,NULL,NULL);
sc->devinfo[i].default_address = i;
sc->devinfo[(int)(first_relocated)].default_address = 0;
@@ -194,10 +193,6 @@ adb_bus_enumerate(void *xdev)
static int adb_bus_detach(device_t dev)
{
- struct adb_softc *sc = device_get_softc(dev);
-
- mtx_destroy(&sc->sc_sync_mtx);
-
return (bus_generic_detach(dev));
}
@@ -230,6 +225,7 @@ adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len,
if (sc->sync_packet == command) {
memcpy(sc->syncreg,data,(len > 8) ? 8 : len);
atomic_store_rel_int(&sc->packet_reply,len + 1);
+ wakeup(sc);
}
if (sc->children[addr] != NULL) {
@@ -317,12 +313,12 @@ adb_get_device_handler(device_t dev)
static int
adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command,
- uint8_t reg, int len, u_char *data)
+ uint8_t reg, int len, u_char *data, u_char *reply)
{
u_char command_byte = 0;
struct adb_softc *sc;
int result = -1;
- int i = 0;
+ int i = 1;
sc = device_get_softc(dev);
@@ -331,7 +327,8 @@ adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command,
command_byte |= reg;
/* Wait if someone else has a synchronous request pending */
- mtx_lock(&sc->sc_sync_mtx);
+ while (!atomic_cmpset_int(&sc->sync_packet, 0xffff, command_byte))
+ tsleep(sc, 0, "ADB sync", hz/10);
sc->packet_reply = 0;
sc->sync_packet = command_byte;
@@ -343,21 +340,27 @@ adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command,
* Maybe the command got lost? Try resending and polling the
* controller.
*/
- if (i > 40)
+ if (i % 40 == 0)
ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte,
len, data, 1);
- DELAY(100);
+ tsleep(sc, 0, "ADB sync", hz/10);
i++;
}
result = sc->packet_reply - 1;
+ if (reply != NULL && result > 0)
+ memcpy(reply,sc->syncreg,result);
+
/* Clear packet sync */
sc->packet_reply = 0;
- sc->sync_packet = 0xffff; /* We can't match a 16 bit value */
- mtx_unlock(&sc->sc_sync_mtx);
+ /*
+ * We can't match a value beyond 8 bits, so set sync_packet to
+ * 0xffff to avoid collisions.
+ */
+ atomic_set_int(&sc->sync_packet, 0xffff);
return (result);
}
@@ -375,37 +378,27 @@ adb_set_device_handler(device_t dev, uint8_t newhandler)
newr3 = dinfo->register3 & 0xff00;
newr3 |= (uint16_t)(newhandler);
+ adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, ADB_COMMAND_LISTEN,
+ 3, sizeof(uint16_t), (u_char *)(&newr3), NULL);
adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
- ADB_COMMAND_LISTEN, 3, sizeof(uint16_t), (u_char *)(&newr3));
- adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
- ADB_COMMAND_TALK, 3, 0, NULL);
+ ADB_COMMAND_TALK, 3, 0, NULL, NULL);
return (dinfo->handler_id);
}
-uint8_t
-adb_read_register(device_t dev, u_char reg,
- size_t *len, void *data)
+size_t
+adb_read_register(device_t dev, u_char reg, void *data)
{
struct adb_softc *sc;
struct adb_devinfo *dinfo;
- size_t orig_len;
+ size_t result;
dinfo = device_get_ivars(dev);
sc = device_get_softc(device_get_parent(dev));
- orig_len = *len;
-
- mtx_lock(&sc->sc_sync_mtx);
-
- *len = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
- ADB_COMMAND_TALK, reg, 0, NULL);
+ result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
+ ADB_COMMAND_TALK, reg, 0, NULL, data);
- if (*len > 0)
- memcpy(data,sc->syncreg,*len);
-
- mtx_unlock(&sc->sc_sync_mtx);
-
- return ((*len > 0) ? 0 : -1);
+ return (result);
}
diff --git a/sys/dev/adb/adb_kbd.c b/sys/dev/adb/adb_kbd.c
index db95cfe..115b35d 100644
--- a/sys/dev/adb/adb_kbd.c
+++ b/sys/dev/adb/adb_kbd.c
@@ -271,11 +271,12 @@ adb_kbd_attach(device_t dev)
}
#endif
- adb_set_autopoll(dev,1);
-
- /* Check (asynchronously) if we can read out the LED state from
+ /* Check if we can read out the LED state from
this keyboard by reading the key state register */
- adb_send_packet(dev,ADB_COMMAND_TALK,2,0,NULL);
+ if (adb_read_register(dev, 2, NULL) == 2)
+ sc->have_led_control = 1;
+
+ adb_set_autopoll(dev,1);
return (0);
}
@@ -323,11 +324,6 @@ adb_kbd_receive_packet(device_t dev, u_char status,
if (command != ADB_COMMAND_TALK)
return 0;
- if (reg == 2 && len == 2) {
- sc->have_led_control = 1;
- return 0;
- }
-
if (reg != 0 || len != 2)
return (0);
diff --git a/sys/dev/adb/adb_mouse.c b/sys/dev/adb/adb_mouse.c
index 26edbc5..bba38c2 100644
--- a/sys/dev/adb/adb_mouse.c
+++ b/sys/dev/adb/adb_mouse.c
@@ -181,7 +181,7 @@ adb_mouse_attach(device_t dev)
sc->mode.resolution = 200;
break;
case 4:
- adb_read_register(dev,1,&r1_len,r1);
+ r1_len = adb_read_register(dev,1,r1);
if (r1_len < 8)
break;
diff --git a/sys/dev/adb/adbvar.h b/sys/dev/adb/adbvar.h
index e70aa75..47afb35 100644
--- a/sys/dev/adb/adbvar.h
+++ b/sys/dev/adb/adbvar.h
@@ -40,7 +40,6 @@ struct adb_softc {
device_t parent;
struct intr_config_hook enum_hook;
- struct mtx sc_sync_mtx;
volatile int sync_packet;
volatile int packet_reply;
OpenPOWER on IntegriCloud