Changeset 72af8da in mainline for uspace/drv/uhci-rhd/port.c
- Timestamp:
- 2011-03-16T18:50:17Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 42a3a57
- Parents:
- 3e7b7cd (diff), fcf07e6 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/uhci-rhd/port.c
r3e7b7cd r72af8da 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb28 /** @addtogroup drvusbuhcirh 29 29 * @{ 30 30 */ 31 31 /** @file 32 * @brief UHCI driver 33 */ 32 * @brief UHCI root hub port routines 33 */ 34 #include <libarch/ddi.h> /* pio_read and pio_write */ 34 35 #include <errno.h> 35 36 #include <str_error.h> … … 37 38 38 39 #include <usb/usb.h> /* usb_address_t */ 39 #include <usb/usbdevice.h>40 40 #include <usb/hub.h> 41 #include <usb/request.h>42 41 #include <usb/debug.h> 43 #include <usb/recognise.h>44 42 45 43 #include "port.h" 46 #include "port_status.h" 47 48 static int uhci_port_new_device(uhci_port_t *port, uint16_t status); 44 45 static int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed); 49 46 static int uhci_port_remove_device(uhci_port_t *port); 50 47 static int uhci_port_set_enabled(uhci_port_t *port, bool enabled); 51 48 static int uhci_port_check(void *port); 52 static int new_device_enable_port(int portno, void *arg); 53 54 int uhci_port_init( 55 uhci_port_t *port, port_status_t *address, unsigned number, 56 unsigned usec, ddf_dev_t *rh) 57 { 58 assert(port); 49 static int uhci_port_reset_enable(int portno, void *arg); 50 static void uhci_port_print_status( 51 uhci_port_t *port, const port_status_t value); 52 53 /** Register reading helper function. 54 * 55 * @param[in] port Structure to use. 56 * @return Error code. (Always EOK) 57 */ 58 static inline port_status_t uhci_port_read_status(uhci_port_t *port) 59 { 60 assert(port); 61 return pio_read_16(port->address); 62 } 63 /*----------------------------------------------------------------------------*/ 64 /** Register writing helper function. 65 * 66 * @param[in] port Structure to use. 67 * @param[in] value New register value. 68 * @return Error code. (Always EOK) 69 */ 70 static inline void uhci_port_write_status( 71 uhci_port_t *port, port_status_t value) 72 { 73 assert(port); 74 pio_write_16(port->address, value); 75 } 76 77 /*----------------------------------------------------------------------------*/ 78 /** Initialize UHCI root hub port instance. 79 * 80 * @param[in] port Memory structure to use. 81 * @param[in] addr Address of I/O register. 82 * @param[in] number Port number. 83 * @param[in] usec Polling interval. 84 * @param[in] rh Pointer to ddf instance fo the root hub driver. 85 * @return Error code. 86 * 87 * Creates and starts the polling fibril. 88 */ 89 int uhci_port_init(uhci_port_t *port, 90 port_status_t *address, unsigned number, unsigned usec, ddf_dev_t *rh) 91 { 92 assert(port); 93 asprintf(&port->id_string, "Port (%p - %d)", port, number); 94 if (port->id_string == NULL) { 95 return ENOMEM; 96 } 97 59 98 port->address = address; 60 99 port->number = number; … … 62 101 port->attached_device = 0; 63 102 port->rh = rh; 103 64 104 int rc = usb_hc_connection_initialize_from_device( 65 105 &port->hc_connection, rh); … … 71 111 port->checker = fibril_create(uhci_port_check, port); 72 112 if (port->checker == 0) { 73 usb_log_error(" Port(%p - %d): failed to launch root hubfibril.",74 port-> address, port->number);113 usb_log_error("%s: failed to create polling fibril.", 114 port->id_string); 75 115 return ENOMEM; 76 116 } 117 77 118 fibril_add_ready(port->checker); 78 usb_log_debug("Port(%p - %d): Added fibril. %x\n", 79 port->address, port->number, port->checker); 80 return EOK; 81 } 82 /*----------------------------------------------------------------------------*/ 119 usb_log_debug("%s: Started polling fibril(%x).\n", 120 port->id_string, port->checker); 121 return EOK; 122 } 123 /*----------------------------------------------------------------------------*/ 124 /** Cleanup UHCI root hub port instance. 125 * 126 * @param[in] port Memory structure to use. 127 * 128 * Stops the polling fibril. 129 */ 83 130 void uhci_port_fini(uhci_port_t *port) 84 131 { 85 // TODO: destroy fibril 86 // TODO: hangup phone 87 // fibril_teardown(port->checker); 132 assert(port); 133 free(port->id_string); 134 /* TODO: Kill fibril here */ 88 135 return; 89 136 } 90 137 /*----------------------------------------------------------------------------*/ 138 /** Periodically checks port status and reports new devices. 139 * 140 * @param[in] port Port structure to use. 141 * @return Error code. 142 */ 91 143 int uhci_port_check(void *port) 92 144 { 93 uhci_port_t *port_instance = port; 94 assert(port_instance); 95 // port_status_write(port_instance->address, 0); 96 97 unsigned count = 0; 145 uhci_port_t *instance = port; 146 assert(instance); 98 147 99 148 while (1) { 100 async_usleep(port_instance->wait_period_usec); 101 102 /* read register value */ 103 port_status_t port_status = 104 port_status_read(port_instance->address); 105 106 /* debug print */ 107 static fibril_mutex_t dbg_mtx = FIBRIL_MUTEX_INITIALIZER(dbg_mtx); 108 fibril_mutex_lock(&dbg_mtx); 109 usb_log_debug2("Port(%p - %d): Status: %#04x. === %u\n", 110 port_instance->address, port_instance->number, port_status, count++); 111 // print_port_status(port_status); 112 fibril_mutex_unlock(&dbg_mtx); 113 114 if ((port_status & STATUS_CONNECTED_CHANGED) != 0) { 115 usb_log_debug("Port(%p - %d): Connected change detected: %x.\n", 116 port_instance->address, port_instance->number, port_status); 117 118 119 int rc = usb_hc_connection_open( 120 &port_instance->hc_connection); 121 if (rc != EOK) { 122 usb_log_error("Port(%p - %d): Failed to connect to HC.", 123 port_instance->address, port_instance->number); 124 continue; 125 } 126 127 /* remove any old device */ 128 if (port_instance->attached_device) { 129 usb_log_debug("Port(%p - %d): Removing device.\n", 130 port_instance->address, port_instance->number); 131 uhci_port_remove_device(port_instance); 132 } 133 134 if ((port_status & STATUS_CONNECTED) != 0) { 135 /* new device */ 136 uhci_port_new_device(port_instance, port_status); 137 } else { 138 /* ack changes by writing one to WC bits */ 139 port_status_write(port_instance->address, port_status); 140 usb_log_debug("Port(%p - %d): Change status ACK.\n", 141 port_instance->address, port_instance->number); 142 } 143 144 rc = usb_hc_connection_close( 145 &port_instance->hc_connection); 146 if (rc != EOK) { 147 usb_log_error("Port(%p - %d): Failed to disconnect from HC.", 148 port_instance->address, port_instance->number); 149 } 149 async_usleep(instance->wait_period_usec); 150 151 /* Read register value */ 152 port_status_t port_status = uhci_port_read_status(instance); 153 154 /* Print the value if it's interesting */ 155 if (port_status & ~STATUS_ALWAYS_ONE) 156 uhci_port_print_status(instance, port_status); 157 158 if ((port_status & STATUS_CONNECTED_CHANGED) == 0) 159 continue; 160 161 usb_log_debug("%s: Connected change detected: %x.\n", 162 instance->id_string, port_status); 163 164 int rc = 165 usb_hc_connection_open(&instance->hc_connection); 166 if (rc != EOK) { 167 usb_log_error("%s: Failed to connect to HC.", 168 instance->id_string); 169 continue; 150 170 } 151 } 152 return EOK; 153 } 154 171 172 /* Remove any old device */ 173 if (instance->attached_device) { 174 usb_log_debug2("%s: Removing device.\n", 175 instance->id_string); 176 uhci_port_remove_device(instance); 177 } 178 179 if ((port_status & STATUS_CONNECTED) != 0) { 180 /* New device */ 181 const usb_speed_t speed = 182 ((port_status & STATUS_LOW_SPEED) != 0) ? 183 USB_SPEED_LOW : USB_SPEED_FULL; 184 uhci_port_new_device(instance, speed); 185 } else { 186 /* Write one to WC bits, to ack changes */ 187 uhci_port_write_status(instance, port_status); 188 usb_log_debug("%s: status change ACK.\n", 189 instance->id_string); 190 } 191 192 rc = usb_hc_connection_close(&instance->hc_connection); 193 if (rc != EOK) { 194 usb_log_error("%s: Failed to disconnect.", 195 instance->id_string); 196 } 197 } 198 return EOK; 199 } 200 /*----------------------------------------------------------------------------*/ 155 201 /** Callback for enabling port during adding a new device. 156 202 * … … 158 204 * @param arg Pointer to uhci_port_t of port with the new device. 159 205 * @return Error code. 160 */ 161 static int new_device_enable_port(int portno, void *arg) 206 * 207 * Resets and enables the ub port. 208 */ 209 int uhci_port_reset_enable(int portno, void *arg) 162 210 { 163 211 uhci_port_t *port = (uhci_port_t *) arg; 164 212 165 usb_log_debug2("Port(%p - %d): new_device_enable_port.\n", 166 port->address, port->number); 213 usb_log_debug2("%s: new_device_enable_port.\n", port->id_string); 167 214 168 215 /* … … 172 219 async_usleep(100000); 173 220 174 175 /* The hub maintains the reset signal to that port for 10 ms 176 * (See Section 11.5.1.5) 221 /* 222 * Resets from root ports should be nominally 50ms 177 223 */ 178 224 { 179 usb_log_debug("Port(%p - %d): Reset Signal start.\n", 180 port->address, port->number); 181 port_status_t port_status = 182 port_status_read(port->address); 225 usb_log_debug("%s: Reset Signal start.\n", port->id_string); 226 port_status_t port_status = uhci_port_read_status(port); 183 227 port_status |= STATUS_IN_RESET; 184 port_status_write(port->address, port_status); 185 async_usleep(10000); 186 port_status = 187 port_status_read(port->address); 228 uhci_port_write_status(port, port_status); 229 async_usleep(50000); 230 port_status = uhci_port_read_status(port); 188 231 port_status &= ~STATUS_IN_RESET; 189 port_status_write(port->address, port_status); 190 usb_log_debug("Port(%p - %d): Reset Signal stop.\n", 191 port->address, port->number); 192 } 232 uhci_port_write_status(port, port_status); 233 usb_log_debug("%s: Reset Signal stop.\n", port->id_string); 234 } 235 236 /* the reset recovery time 10ms */ 237 async_usleep(10000); 193 238 194 239 /* Enable the port. */ … … 197 242 return EOK; 198 243 } 199 200 /*----------------------------------------------------------------------------*/ 201 static int uhci_port_new_device(uhci_port_t *port, uint16_t status) 244 /*----------------------------------------------------------------------------*/ 245 /** Initialize and report connected device. 246 * 247 * @param[in] port Port structure to use. 248 * @param[in] speed Detected speed. 249 * @return Error code. 250 * 251 * Uses libUSB function to do the actual work. 252 */ 253 int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed) 202 254 { 203 255 assert(port); 204 256 assert(usb_hc_connection_is_opened(&port->hc_connection)); 205 257 206 usb_log_info("Port(%p-%d): Detected new device.\n", 207 port->address, port->number); 258 usb_log_info("%s: Detected new device.\n", port->id_string); 208 259 209 260 usb_address_t dev_addr; 210 261 int rc = usb_hc_new_device_wrapper(port->rh, &port->hc_connection, 211 ((status & STATUS_LOW_SPEED) != 0) ? USB_SPEED_LOW : USB_SPEED_FULL, 212 new_device_enable_port, port->number, port, 262 speed, uhci_port_reset_enable, port->number, port, 213 263 &dev_addr, &port->attached_device, NULL, NULL, NULL); 214 264 215 265 if (rc != EOK) { 216 usb_log_error(" Port(%p-%d): Failed(%d) adding newdevice: %s.\n",217 port-> address, port->number, rc, str_error(rc));266 usb_log_error("%s: Failed(%d) to add device: %s.\n", 267 port->id_string, rc, str_error(rc)); 218 268 uhci_port_set_enabled(port, false); 219 269 return rc; 220 270 } 221 271 222 usb_log_info("Port(%p-%d): New device has address %d (handle %zu).\n", 223 port->address, port->number, dev_addr, port->attached_device); 224 225 return EOK; 226 } 227 228 /*----------------------------------------------------------------------------*/ 229 static int uhci_port_remove_device(uhci_port_t *port) 230 { 231 usb_log_error("Port(%p-%d): Don't know how to remove device %#x.\n", 232 port->address, port->number, (unsigned int)port->attached_device); 233 // uhci_port_set_enabled(port, false); 234 return EOK; 235 } 236 /*----------------------------------------------------------------------------*/ 237 static int uhci_port_set_enabled(uhci_port_t *port, bool enabled) 238 { 239 assert(port); 240 241 /* read register value */ 242 port_status_t port_status 243 = port_status_read(port->address); 244 245 /* enable port: register write */ 272 usb_log_info("%s: New device has address %d (handle %zu).\n", 273 port->id_string, dev_addr, port->attached_device); 274 275 return EOK; 276 } 277 /*----------------------------------------------------------------------------*/ 278 /** Remove device. 279 * 280 * @param[in] port Memory structure to use. 281 * @return Error code. 282 * 283 * Does not work, DDF does not support device removal. 284 * Does not even free used USB address (it would be dangerous if tis driver 285 * is still running). 286 */ 287 int uhci_port_remove_device(uhci_port_t *port) 288 { 289 usb_log_error("%s: Don't know how to remove device %d.\n", 290 port->id_string, (unsigned int)port->attached_device); 291 return EOK; 292 } 293 /*----------------------------------------------------------------------------*/ 294 /** Enable or disable root hub port. 295 * 296 * @param[in] port Port structure to use. 297 * @param[in] enabled Port status to set. 298 * @return Error code. (Always EOK) 299 */ 300 int uhci_port_set_enabled(uhci_port_t *port, bool enabled) 301 { 302 assert(port); 303 304 /* Read register value */ 305 port_status_t port_status = uhci_port_read_status(port); 306 307 /* Set enabled bit */ 246 308 if (enabled) { 247 309 port_status |= STATUS_ENABLED; … … 249 311 port_status &= ~STATUS_ENABLED; 250 312 } 251 port_status_write(port->address, port_status); 252 253 usb_log_info("Port(%p-%d): %sabled port.\n", 254 port->address, port->number, enabled ? "En" : "Dis"); 255 return EOK; 256 } 257 /*----------------------------------------------------------------------------*/ 313 314 /* Write new value. */ 315 uhci_port_write_status(port, port_status); 316 317 usb_log_info("%s: %sabled port.\n", 318 port->id_string, enabled ? "En" : "Dis"); 319 return EOK; 320 } 321 /*----------------------------------------------------------------------------*/ 322 /** Print the port status value in a human friendly way 323 * 324 * @param[in] port Port structure to use. 325 * @param[in] value Port register value to print. 326 * @return Error code. (Always EOK) 327 */ 328 void uhci_port_print_status(uhci_port_t *port, const port_status_t value) 329 { 330 assert(port); 331 usb_log_debug2("%s Port status(%#x):%s%s%s%s%s%s%s%s%s%s%s.\n", 332 port->id_string, value, 333 (value & STATUS_SUSPEND) ? " SUSPENDED," : "", 334 (value & STATUS_RESUME) ? " IN RESUME," : "", 335 (value & STATUS_IN_RESET) ? " IN RESET," : "", 336 (value & STATUS_LINE_D_MINUS) ? " VD-," : "", 337 (value & STATUS_LINE_D_PLUS) ? " VD+," : "", 338 (value & STATUS_LOW_SPEED) ? " LOWSPEED," : "", 339 (value & STATUS_ENABLED_CHANGED) ? " ENABLED-CHANGE," : "", 340 (value & STATUS_ENABLED) ? " ENABLED," : "", 341 (value & STATUS_CONNECTED_CHANGED) ? " CONNECTED-CHANGE," : "", 342 (value & STATUS_CONNECTED) ? " CONNECTED," : "", 343 (value & STATUS_ALWAYS_ONE) ? " ALWAYS ONE" : " ERROR: NO ALWAYS ONE" 344 ); 345 } 258 346 /** 259 347 * @}
Note:
See TracChangeset
for help on using the changeset viewer.