adb_bus.c (184890) | adb_bus.c (185724) |
---|---|
1/*- 2 * Copyright (C) 2008 Nathan Whitehorn 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 8 unchanged lines hidden (view full) --- 17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * | 1/*- 2 * Copyright (C) 2008 Nathan Whitehorn 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 8 unchanged lines hidden (view full) --- 17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * |
25 * $FreeBSD: head/sys/dev/adb/adb_bus.c 184890 2008-11-12 17:33:36Z nwhitehorn $ | 25 * $FreeBSD: head/sys/dev/adb/adb_bus.c 185724 2008-12-06 23:26:02Z nwhitehorn $ |
26 */ 27 28#include <sys/cdefs.h> 29#include <sys/param.h> 30#include <sys/systm.h> 31#include <sys/module.h> 32#include <sys/bus.h> 33#include <sys/conf.h> --- 9 unchanged lines hidden (view full) --- 43 44static int adb_bus_probe(device_t dev); 45static int adb_bus_attach(device_t dev); 46static int adb_bus_detach(device_t dev); 47static void adb_bus_enumerate(void *xdev); 48static void adb_probe_nomatch(device_t dev, device_t child); 49static int adb_print_child(device_t dev, device_t child); 50 | 26 */ 27 28#include <sys/cdefs.h> 29#include <sys/param.h> 30#include <sys/systm.h> 31#include <sys/module.h> 32#include <sys/bus.h> 33#include <sys/conf.h> --- 9 unchanged lines hidden (view full) --- 43 44static int adb_bus_probe(device_t dev); 45static int adb_bus_attach(device_t dev); 46static int adb_bus_detach(device_t dev); 47static void adb_bus_enumerate(void *xdev); 48static void adb_probe_nomatch(device_t dev, device_t child); 49static int adb_print_child(device_t dev, device_t child); 50 |
51static int adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, uint8_t reg, int len, u_char *data); | 51static 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); |
52 53static char *adb_device_string[] = { 54 "HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc" 55}; 56 57static device_method_t adb_bus_methods[] = { 58 /* Device interface */ 59 DEVMETHOD(device_probe, adb_bus_probe), --- 53 unchanged lines hidden (view full) --- 113 uint8_t i, next_free; 114 uint16_t r3; 115 116 sc->sc_dev = dev; 117 sc->parent = device_get_parent(dev); 118 119 sc->packet_reply = 0; 120 sc->autopoll_mask = 0; | 52 53static char *adb_device_string[] = { 54 "HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc" 55}; 56 57static device_method_t adb_bus_methods[] = { 58 /* Device interface */ 59 DEVMETHOD(device_probe, adb_bus_probe), --- 53 unchanged lines hidden (view full) --- 113 uint8_t i, next_free; 114 uint16_t r3; 115 116 sc->sc_dev = dev; 117 sc->parent = device_get_parent(dev); 118 119 sc->packet_reply = 0; 120 sc->autopoll_mask = 0; |
121 sc->sync_packet = 0xffff; |
|
121 | 122 |
122 mtx_init(&sc->sc_sync_mtx,"adbsyn",NULL,MTX_DEF | MTX_RECURSE); 123 | |
124 /* Initialize devinfo */ 125 for (i = 0; i < 16; i++) { 126 sc->devinfo[i].address = i; 127 sc->devinfo[i].default_address = 0; 128 } 129 130 /* Reset ADB bus */ | 123 /* Initialize devinfo */ 124 for (i = 0; i < 16; i++) { 125 sc->devinfo[i].address = i; 126 sc->devinfo[i].default_address = 0; 127 } 128 129 /* Reset ADB bus */ |
131 adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL); | 130 adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL,NULL); |
132 DELAY(1500); 133 134 /* Enumerate bus */ 135 next_free = 8; 136 137 for (i = 1; i <= 7; i++) { 138 int8_t first_relocated = -1; 139 int reply = 0; 140 141 do { 142 reply = adb_send_raw_packet_sync(dev,i, | 131 DELAY(1500); 132 133 /* Enumerate bus */ 134 next_free = 8; 135 136 for (i = 1; i <= 7; i++) { 137 int8_t first_relocated = -1; 138 int reply = 0; 139 140 do { 141 reply = adb_send_raw_packet_sync(dev,i, |
143 ADB_COMMAND_TALK,3,0,NULL); | 142 ADB_COMMAND_TALK,3,0,NULL,NULL); |
144 145 if (reply) { 146 /* If we got a response, relocate to next_free */ 147 r3 = sc->devinfo[i].register3; 148 r3 &= 0xf000; 149 r3 |= ((uint16_t)(next_free) & 0x000f) << 8; 150 r3 |= 0x00fe; 151 152 adb_send_raw_packet_sync(dev,i, ADB_COMMAND_LISTEN,3, | 143 144 if (reply) { 145 /* If we got a response, relocate to next_free */ 146 r3 = sc->devinfo[i].register3; 147 r3 &= 0xf000; 148 r3 |= ((uint16_t)(next_free) & 0x000f) << 8; 149 r3 |= 0x00fe; 150 151 adb_send_raw_packet_sync(dev,i, ADB_COMMAND_LISTEN,3, |
153 sizeof(uint16_t),(u_char *)(&r3)); | 152 sizeof(uint16_t),(u_char *)(&r3),NULL); |
154 155 adb_send_raw_packet_sync(dev,next_free, | 153 154 adb_send_raw_packet_sync(dev,next_free, |
156 ADB_COMMAND_TALK,3,0,NULL); | 155 ADB_COMMAND_TALK,3,0,NULL,NULL); |
157 158 sc->devinfo[next_free].default_address = i; 159 if (first_relocated < 0) 160 first_relocated = next_free; 161 162 next_free++; 163 } else if (first_relocated > 0) { 164 /* Collisions removed, relocate first device back */ 165 166 r3 = sc->devinfo[i].register3; 167 r3 &= 0xf000; 168 r3 |= ((uint16_t)(i) & 0x000f) << 8; 169 170 adb_send_raw_packet_sync(dev,first_relocated, 171 ADB_COMMAND_LISTEN,3, | 156 157 sc->devinfo[next_free].default_address = i; 158 if (first_relocated < 0) 159 first_relocated = next_free; 160 161 next_free++; 162 } else if (first_relocated > 0) { 163 /* Collisions removed, relocate first device back */ 164 165 r3 = sc->devinfo[i].register3; 166 r3 &= 0xf000; 167 r3 |= ((uint16_t)(i) & 0x000f) << 8; 168 169 adb_send_raw_packet_sync(dev,first_relocated, 170 ADB_COMMAND_LISTEN,3, |
172 sizeof(uint16_t),(u_char *)(&r3)); | 171 sizeof(uint16_t),(u_char *)(&r3),NULL); |
173 adb_send_raw_packet_sync(dev,i, | 172 adb_send_raw_packet_sync(dev,i, |
174 ADB_COMMAND_TALK,3,0,NULL); | 173 ADB_COMMAND_TALK,3,0,NULL,NULL); |
175 176 sc->devinfo[i].default_address = i; 177 sc->devinfo[(int)(first_relocated)].default_address = 0; 178 break; 179 } 180 } while (reply); 181 } 182 --- 6 unchanged lines hidden (view full) --- 189 190 bus_generic_attach(dev); 191 192 config_intrhook_disestablish(&sc->enum_hook); 193} 194 195static int adb_bus_detach(device_t dev) 196{ | 174 175 sc->devinfo[i].default_address = i; 176 sc->devinfo[(int)(first_relocated)].default_address = 0; 177 break; 178 } 179 } while (reply); 180 } 181 --- 6 unchanged lines hidden (view full) --- 188 189 bus_generic_attach(dev); 190 191 config_intrhook_disestablish(&sc->enum_hook); 192} 193 194static int adb_bus_detach(device_t dev) 195{ |
197 struct adb_softc *sc = device_get_softc(dev); 198 199 mtx_destroy(&sc->sc_sync_mtx); 200 | |
201 return (bus_generic_detach(dev)); 202} 203 204 205static void 206adb_probe_nomatch(device_t dev, device_t child) 207{ 208 struct adb_devinfo *dinfo; --- 16 unchanged lines hidden (view full) --- 225 if (len > 0 && (command & 0x0f) == ((ADB_COMMAND_TALK << 2) | 3)) { 226 memcpy(&sc->devinfo[addr].register3,data,2); 227 sc->devinfo[addr].handler_id = data[1]; 228 } 229 230 if (sc->sync_packet == command) { 231 memcpy(sc->syncreg,data,(len > 8) ? 8 : len); 232 atomic_store_rel_int(&sc->packet_reply,len + 1); | 196 return (bus_generic_detach(dev)); 197} 198 199 200static void 201adb_probe_nomatch(device_t dev, device_t child) 202{ 203 struct adb_devinfo *dinfo; --- 16 unchanged lines hidden (view full) --- 220 if (len > 0 && (command & 0x0f) == ((ADB_COMMAND_TALK << 2) | 3)) { 221 memcpy(&sc->devinfo[addr].register3,data,2); 222 sc->devinfo[addr].handler_id = data[1]; 223 } 224 225 if (sc->sync_packet == command) { 226 memcpy(sc->syncreg,data,(len > 8) ? 8 : len); 227 atomic_store_rel_int(&sc->packet_reply,len + 1); |
228 wakeup(sc); |
|
233 } 234 235 if (sc->children[addr] != NULL) { 236 ADB_RECEIVE_PACKET(sc->children[addr],status, 237 (command & 0x0f) >> 2,command & 0x03,len,data); 238 } 239 240 return (0); --- 71 unchanged lines hidden (view full) --- 312 struct adb_devinfo *dinfo; 313 314 dinfo = device_get_ivars(dev); 315 return (dinfo->handler_id); 316} 317 318static int 319adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, | 229 } 230 231 if (sc->children[addr] != NULL) { 232 ADB_RECEIVE_PACKET(sc->children[addr],status, 233 (command & 0x0f) >> 2,command & 0x03,len,data); 234 } 235 236 return (0); --- 71 unchanged lines hidden (view full) --- 308 struct adb_devinfo *dinfo; 309 310 dinfo = device_get_ivars(dev); 311 return (dinfo->handler_id); 312} 313 314static int 315adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, |
320 uint8_t reg, int len, u_char *data) | 316 uint8_t reg, int len, u_char *data, u_char *reply) |
321{ 322 u_char command_byte = 0; 323 struct adb_softc *sc; 324 int result = -1; | 317{ 318 u_char command_byte = 0; 319 struct adb_softc *sc; 320 int result = -1; |
325 int i = 0; | 321 int i = 1; |
326 327 sc = device_get_softc(dev); 328 329 command_byte |= to << 4; 330 command_byte |= command << 2; 331 command_byte |= reg; 332 333 /* Wait if someone else has a synchronous request pending */ | 322 323 sc = device_get_softc(dev); 324 325 command_byte |= to << 4; 326 command_byte |= command << 2; 327 command_byte |= reg; 328 329 /* Wait if someone else has a synchronous request pending */ |
334 mtx_lock(&sc->sc_sync_mtx); | 330 while (!atomic_cmpset_int(&sc->sync_packet, 0xffff, command_byte)) 331 tsleep(sc, 0, "ADB sync", hz/10); |
335 336 sc->packet_reply = 0; 337 sc->sync_packet = command_byte; 338 339 ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1); 340 341 while (!atomic_fetchadd_int(&sc->packet_reply,0)) { 342 /* 343 * Maybe the command got lost? Try resending and polling the 344 * controller. 345 */ | 332 333 sc->packet_reply = 0; 334 sc->sync_packet = command_byte; 335 336 ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1); 337 338 while (!atomic_fetchadd_int(&sc->packet_reply,0)) { 339 /* 340 * Maybe the command got lost? Try resending and polling the 341 * controller. 342 */ |
346 if (i > 40) | 343 if (i % 40 == 0) |
347 ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, 348 len, data, 1); 349 | 344 ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, 345 len, data, 1); 346 |
350 DELAY(100); | 347 tsleep(sc, 0, "ADB sync", hz/10); |
351 i++; 352 } 353 354 result = sc->packet_reply - 1; 355 | 348 i++; 349 } 350 351 result = sc->packet_reply - 1; 352 |
353 if (reply != NULL && result > 0) 354 memcpy(reply,sc->syncreg,result); 355 |
|
356 /* Clear packet sync */ 357 sc->packet_reply = 0; | 356 /* Clear packet sync */ 357 sc->packet_reply = 0; |
358 sc->sync_packet = 0xffff; /* We can't match a 16 bit value */ | |
359 | 358 |
360 mtx_unlock(&sc->sc_sync_mtx); | 359 /* 360 * We can't match a value beyond 8 bits, so set sync_packet to 361 * 0xffff to avoid collisions. 362 */ 363 atomic_set_int(&sc->sync_packet, 0xffff); |
361 362 return (result); 363} 364 365uint8_t 366adb_set_device_handler(device_t dev, uint8_t newhandler) 367{ 368 struct adb_softc *sc; 369 struct adb_devinfo *dinfo; 370 uint16_t newr3; 371 372 dinfo = device_get_ivars(dev); 373 sc = device_get_softc(device_get_parent(dev)); 374 375 newr3 = dinfo->register3 & 0xff00; 376 newr3 |= (uint16_t)(newhandler); 377 | 364 365 return (result); 366} 367 368uint8_t 369adb_set_device_handler(device_t dev, uint8_t newhandler) 370{ 371 struct adb_softc *sc; 372 struct adb_devinfo *dinfo; 373 uint16_t newr3; 374 375 dinfo = device_get_ivars(dev); 376 sc = device_get_softc(device_get_parent(dev)); 377 378 newr3 = dinfo->register3 & 0xff00; 379 newr3 |= (uint16_t)(newhandler); 380 |
381 adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, ADB_COMMAND_LISTEN, 382 3, sizeof(uint16_t), (u_char *)(&newr3), NULL); |
|
378 adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, | 383 adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, |
379 ADB_COMMAND_LISTEN, 3, sizeof(uint16_t), (u_char *)(&newr3)); 380 adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 381 ADB_COMMAND_TALK, 3, 0, NULL); | 384 ADB_COMMAND_TALK, 3, 0, NULL, NULL); |
382 383 return (dinfo->handler_id); 384} 385 | 385 386 return (dinfo->handler_id); 387} 388 |
386uint8_t 387adb_read_register(device_t dev, u_char reg, 388 size_t *len, void *data) | 389size_t 390adb_read_register(device_t dev, u_char reg, void *data) |
389{ 390 struct adb_softc *sc; 391 struct adb_devinfo *dinfo; | 391{ 392 struct adb_softc *sc; 393 struct adb_devinfo *dinfo; |
392 size_t orig_len; | 394 size_t result; |
393 394 dinfo = device_get_ivars(dev); 395 sc = device_get_softc(device_get_parent(dev)); 396 | 395 396 dinfo = device_get_ivars(dev); 397 sc = device_get_softc(device_get_parent(dev)); 398 |
397 orig_len = *len; | 399 result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 400 ADB_COMMAND_TALK, reg, 0, NULL, data); |
398 | 401 |
399 mtx_lock(&sc->sc_sync_mtx); 400 401 *len = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 402 ADB_COMMAND_TALK, reg, 0, NULL); 403 404 if (*len > 0) 405 memcpy(data,sc->syncreg,*len); 406 407 mtx_unlock(&sc->sc_sync_mtx); 408 409 return ((*len > 0) ? 0 : -1); | 402 return (result); |
410} 411 | 403} 404 |