Changes in uspace/lib/usbdev/src/pipes.c [7fc260ff:01086cfe] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usbdev/src/pipes.c
r7fc260ff r01086cfe 1 1 /* 2 2 * Copyright (c) 2011 Vojtech Horky 3 * Copyright (c) 2011 Jan Vesely 3 4 * All rights reserved. 4 5 * … … 26 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 */ 28 29 29 /** @addtogroup libusbdev 30 30 * @{ 31 31 */ 32 32 /** @file 33 * USB endpoint pipes miscellaneous functions. 34 */ 35 #include <usb/usb.h> 33 * USB endpoint pipes functions. 34 */ 36 35 #include <usb/dev/pipes.h> 37 #include <usb/debug.h> 38 #include <usb/hc.h> 39 #include <usbhc_iface.h> 40 #include <usb_iface.h> 41 #include <devman.h> 36 #include <usb/dev/request.h> 42 37 #include <errno.h> 43 38 #include <assert.h> 44 #include "pipepriv.h" 45 46 #define IPC_AGAIN_DELAY (1000 * 2) /* 2ms */ 47 48 /** Tell USB address assigned to given device. 49 * 50 * @param sess Session to parent device. 51 * @param dev Device in question. 52 * @return USB address or error code. 53 */ 54 static usb_address_t get_my_address(async_sess_t *sess, const ddf_dev_t *dev) 55 { 56 async_exch_t *exch = async_exchange_begin(sess); 57 58 sysarg_t address; 59 int rc = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE), 60 IPC_M_USB_GET_MY_ADDRESS, &address); 61 62 async_exchange_end(exch); 63 64 if (rc != EOK) 65 return rc; 66 67 return (usb_address_t) address; 68 } 69 70 /** Tell USB interface assigned to given device. 71 * 72 * @param device Device in question. 73 * @return Interface number (negative code means any). 74 */ 75 int usb_device_get_assigned_interface(const ddf_dev_t *device) 76 { 77 assert(device); 78 async_sess_t *parent_sess = 79 devman_parent_device_connect(EXCHANGE_ATOMIC, device->handle, 80 IPC_FLAG_BLOCKING); 81 if (!parent_sess) 82 return -1; 83 84 async_exch_t *exch = async_exchange_begin(parent_sess); 85 86 sysarg_t iface_no; 87 int rc = async_req_2_1(exch, DEV_IFACE_ID(USB_DEV_IFACE), 88 IPC_M_USB_GET_INTERFACE, device->handle, &iface_no); 89 90 async_exchange_end(exch); 91 async_hangup(parent_sess); 92 93 if (rc != EOK) 94 return -1; 95 96 return (int) iface_no; 97 } 98 99 /** Initialize connection to USB device. 100 * 101 * @param connection Connection structure to be initialized. 102 * @param dev Generic device backing the USB device. 103 * @return Error code. 104 */ 105 int usb_device_connection_initialize_from_device( 106 usb_device_connection_t *connection, const ddf_dev_t *dev) 107 { 39 40 /** Prepare pipe for a long transfer. 41 * 42 * Long transfer is transfer consisting of several requests to the HC. 43 * Calling this function is optional and it has positive effect of 44 * improved performance because IPC session is initiated only once. 45 * 46 * @param pipe Pipe over which the transfer will happen. 47 * @return Error code. 48 */ 49 int usb_pipe_start_long_transfer(usb_pipe_t *pipe) 50 { 51 assert(pipe); 52 assert(pipe->wire); 53 assert(pipe->wire->hc_connection); 54 return usb_hc_connection_open(pipe->wire->hc_connection); 55 } 56 /*----------------------------------------------------------------------------*/ 57 /** Terminate a long transfer on a pipe. 58 * @param pipe Pipe where to end the long transfer. 59 * @return Error code. 60 * @see usb_pipe_start_long_transfer 61 */ 62 int usb_pipe_end_long_transfer(usb_pipe_t *pipe) 63 { 64 assert(pipe); 65 assert(pipe->wire); 66 assert(pipe->wire->hc_connection); 67 return usb_hc_connection_close(pipe->wire->hc_connection); 68 } 69 /*----------------------------------------------------------------------------*/ 70 /** Try to clear endpoint halt of default control pipe. 71 * 72 * @param pipe Pipe for control endpoint zero. 73 */ 74 static void clear_self_endpoint_halt(usb_pipe_t *pipe) 75 { 76 assert(pipe != NULL); 77 78 if (!pipe->auto_reset_halt || (pipe->endpoint_no != 0)) { 79 return; 80 } 81 82 /* Prevent infinite recursion. */ 83 pipe->auto_reset_halt = false; 84 usb_request_clear_endpoint_halt(pipe, 0); 85 pipe->auto_reset_halt = true; 86 } 87 /*----------------------------------------------------------------------------*/ 88 /** Request a control read transfer on an endpoint pipe. 89 * 90 * This function encapsulates all three stages of a control transfer. 91 * 92 * @param[in] pipe Pipe used for the transfer. 93 * @param[in] setup_buffer Buffer with the setup packet. 94 * @param[in] setup_buffer_size Size of the setup packet (in bytes). 95 * @param[out] data_buffer Buffer for incoming data. 96 * @param[in] data_buffer_size Size of the buffer for incoming data (in bytes). 97 * @param[out] data_transfered_size Number of bytes that were actually 98 * transfered during the DATA stage. 99 * @return Error code. 100 */ 101 int usb_pipe_control_read(usb_pipe_t *pipe, 102 const void *setup_buffer, size_t setup_buffer_size, 103 void *buffer, size_t buffer_size, size_t *transfered_size) 104 { 105 assert(pipe); 106 107 if ((setup_buffer == NULL) || (setup_buffer_size != 8)) { 108 return EINVAL; 109 } 110 111 if ((buffer == NULL) || (buffer_size == 0)) { 112 return EINVAL; 113 } 114 115 if ((pipe->direction != USB_DIRECTION_BOTH) 116 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) { 117 return EBADF; 118 } 119 120 uint64_t setup_packet; 121 memcpy(&setup_packet, setup_buffer, 8); 122 123 size_t act_size = 0; 124 const int rc = usb_device_control_read(pipe->wire, 125 pipe->endpoint_no, setup_packet, buffer, buffer_size, &act_size); 126 127 if (rc == ESTALL) { 128 clear_self_endpoint_halt(pipe); 129 } 130 131 if (rc == EOK && transfered_size != NULL) { 132 *transfered_size = act_size; 133 } 134 135 return rc; 136 } 137 /*----------------------------------------------------------------------------*/ 138 /** Request a control write transfer on an endpoint pipe. 139 * 140 * This function encapsulates all three stages of a control transfer. 141 * 142 * @param[in] pipe Pipe used for the transfer. 143 * @param[in] setup_buffer Buffer with the setup packet. 144 * @param[in] setup_buffer_size Size of the setup packet (in bytes). 145 * @param[in] data_buffer Buffer with data to be sent. 146 * @param[in] data_buffer_size Size of the buffer with outgoing data (in bytes). 147 * @return Error code. 148 */ 149 int usb_pipe_control_write(usb_pipe_t *pipe, 150 const void *setup_buffer, size_t setup_buffer_size, 151 const void *buffer, size_t buffer_size) 152 { 153 assert(pipe); 154 155 if ((setup_buffer == NULL) || (setup_buffer_size != 8)) { 156 return EINVAL; 157 } 158 159 if ((buffer == NULL) && (buffer_size > 0)) { 160 return EINVAL; 161 } 162 163 if ((buffer != NULL) && (buffer_size == 0)) { 164 return EINVAL; 165 } 166 167 if ((pipe->direction != USB_DIRECTION_BOTH) 168 || (pipe->transfer_type != USB_TRANSFER_CONTROL)) { 169 return EBADF; 170 } 171 172 uint64_t setup_packet; 173 memcpy(&setup_packet, setup_buffer, 8); 174 175 const int rc = usb_device_control_write(pipe->wire, 176 pipe->endpoint_no, setup_packet, buffer, buffer_size); 177 178 if (rc == ESTALL) { 179 clear_self_endpoint_halt(pipe); 180 } 181 182 return rc; 183 } 184 /*----------------------------------------------------------------------------*/ 185 /** Request a read (in) transfer on an endpoint pipe. 186 * 187 * @param[in] pipe Pipe used for the transfer. 188 * @param[out] buffer Buffer where to store the data. 189 * @param[in] size Size of the buffer (in bytes). 190 * @param[out] size_transfered Number of bytes that were actually transfered. 191 * @return Error code. 192 */ 193 int usb_pipe_read(usb_pipe_t *pipe, 194 void *buffer, size_t size, size_t *size_transfered) 195 { 196 assert(pipe); 197 198 if (buffer == NULL) { 199 return EINVAL; 200 } 201 202 if (size == 0) { 203 return EINVAL; 204 } 205 206 if (pipe->direction != USB_DIRECTION_IN) { 207 return EBADF; 208 } 209 210 if (pipe->transfer_type == USB_TRANSFER_CONTROL) { 211 return EBADF; 212 } 213 214 /* Isochronous transfer are not supported (yet) */ 215 if (pipe->transfer_type != USB_TRANSFER_INTERRUPT && 216 pipe->transfer_type != USB_TRANSFER_BULK) 217 return ENOTSUP; 218 219 size_t act_size = 0; 220 const int rc = usb_device_read(pipe->wire, 221 pipe->endpoint_no, buffer, size, &act_size); 222 223 if (rc == EOK && size_transfered != NULL) { 224 *size_transfered = act_size; 225 } 226 227 return rc; 228 } 229 /*----------------------------------------------------------------------------*/ 230 /** Request a write (out) transfer on an endpoint pipe. 231 * 232 * @param[in] pipe Pipe used for the transfer. 233 * @param[in] buffer Buffer with data to transfer. 234 * @param[in] size Size of the buffer (in bytes). 235 * @return Error code. 236 */ 237 int usb_pipe_write(usb_pipe_t *pipe, const void *buffer, size_t size) 238 { 239 assert(pipe); 240 241 if (buffer == NULL || size == 0) { 242 return EINVAL; 243 } 244 245 if (pipe->direction != USB_DIRECTION_OUT) { 246 return EBADF; 247 } 248 249 if (pipe->transfer_type == USB_TRANSFER_CONTROL) { 250 return EBADF; 251 } 252 253 /* Isochronous transfer are not supported (yet) */ 254 if (pipe->transfer_type != USB_TRANSFER_INTERRUPT && 255 pipe->transfer_type != USB_TRANSFER_BULK) 256 return ENOTSUP; 257 258 return usb_device_write(pipe->wire, 259 pipe->endpoint_no, buffer, size); 260 } 261 /*----------------------------------------------------------------------------*/ 262 /** Initialize USB endpoint pipe. 263 * 264 * @param pipe Endpoint pipe to be initialized. 265 * @param connection Connection to the USB device backing this pipe (the wire). 266 * @param endpoint_no Endpoint number (in USB 1.1 in range 0 to 15). 267 * @param transfer_type Transfer type (e.g. interrupt or bulk). 268 * @param max_packet_size Maximum packet size in bytes. 269 * @param direction Endpoint direction (in/out). 270 * @return Error code. 271 */ 272 int usb_pipe_initialize(usb_pipe_t *pipe, 273 usb_device_connection_t *connection, usb_endpoint_t endpoint_no, 274 usb_transfer_type_t transfer_type, size_t max_packet_size, 275 usb_direction_t direction) 276 { 277 assert(pipe); 108 278 assert(connection); 109 assert(dev); 110 111 int rc; 112 devman_handle_t hc_handle; 113 usb_address_t my_address; 114 115 rc = usb_hc_find(dev->handle, &hc_handle); 116 if (rc != EOK) 117 return rc; 118 119 async_sess_t *parent_sess = 120 devman_parent_device_connect(EXCHANGE_ATOMIC, dev->handle, 121 IPC_FLAG_BLOCKING); 122 if (!parent_sess) 123 return ENOMEM; 124 125 /* 126 * Asking for "my" address may require several attempts. 127 * That is because following scenario may happen: 128 * - parent driver (i.e. driver of parent device) announces new device 129 * and devman launches current driver 130 * - parent driver is preempted and thus does not send address-handle 131 * binding to HC driver 132 * - this driver gets here and wants the binding 133 * - the HC does not know the binding yet and thus it answers ENOENT 134 * So, we need to wait for the HC to learn the binding. 135 */ 136 137 do { 138 my_address = get_my_address(parent_sess, dev); 139 140 if (my_address == ENOENT) { 141 /* Be nice, let other fibrils run and try again. */ 142 async_usleep(IPC_AGAIN_DELAY); 143 } else if (my_address < 0) { 144 /* Some other problem, no sense trying again. */ 145 rc = my_address; 146 goto leave; 147 } 148 149 } while (my_address < 0); 150 151 rc = usb_device_connection_initialize(connection, 152 hc_handle, my_address); 153 154 leave: 155 async_hangup(parent_sess); 279 280 pipe->wire = connection; 281 pipe->endpoint_no = endpoint_no; 282 pipe->transfer_type = transfer_type; 283 pipe->max_packet_size = max_packet_size; 284 pipe->direction = direction; 285 pipe->auto_reset_halt = false; 286 287 return EOK; 288 } 289 /*----------------------------------------------------------------------------*/ 290 /** Initialize USB endpoint pipe as the default zero control pipe. 291 * 292 * @param pipe Endpoint pipe to be initialized. 293 * @param connection Connection to the USB device backing this pipe (the wire). 294 * @return Error code. 295 */ 296 int usb_pipe_initialize_default_control(usb_pipe_t *pipe, 297 usb_device_connection_t *connection) 298 { 299 assert(pipe); 300 assert(connection); 301 302 int rc = usb_pipe_initialize(pipe, connection, 0, USB_TRANSFER_CONTROL, 303 CTRL_PIPE_MIN_PACKET_SIZE, USB_DIRECTION_BOTH); 304 305 pipe->auto_reset_halt = true; 306 156 307 return rc; 157 308 } 158 159 /** Initialize connection to USB device. 160 * 161 * @param connection Connection structure to be initialized. 162 * @param host_controller_handle Devman handle of host controller device is 163 * connected to. 164 * @param device_address Device USB address. 165 * @return Error code. 166 */ 167 int usb_device_connection_initialize(usb_device_connection_t *connection, 168 devman_handle_t host_controller_handle, usb_address_t device_address) 169 { 170 assert(connection); 171 172 if ((device_address < 0) || (device_address >= USB11_ADDRESS_MAX)) { 173 return EINVAL; 174 } 175 176 connection->hc_handle = host_controller_handle; 177 connection->address = device_address; 178 179 return EOK; 180 } 181 182 /** Initialize connection to USB device on default address. 183 * 184 * @param dev_connection Device connection structure to be initialized. 185 * @param hc_connection Initialized connection to host controller. 186 * @return Error code. 187 */ 188 int usb_device_connection_initialize_on_default_address( 189 usb_device_connection_t *dev_connection, 190 usb_hc_connection_t *hc_connection) 191 { 192 assert(dev_connection); 193 194 if (hc_connection == NULL) { 195 return EBADMEM; 196 } 197 198 return usb_device_connection_initialize(dev_connection, 199 hc_connection->hc_handle, (usb_address_t) 0); 200 } 201 202 /** Prepare pipe for a long transfer. 203 * 204 * By a long transfer is mean transfer consisting of several 205 * requests to the HC. 206 * Calling such function is optional and it has positive effect of 207 * improved performance because IPC session is initiated only once. 208 * 209 * @param pipe Pipe over which the transfer will happen. 210 * @return Error code. 211 */ 212 void usb_pipe_start_long_transfer(usb_pipe_t *pipe) 213 { 214 (void) pipe_add_ref(pipe, true); 215 } 216 217 /** Terminate a long transfer on a pipe. 218 * 219 * @see usb_pipe_start_long_transfer 220 * 221 * @param pipe Pipe where to end the long transfer. 222 */ 223 void usb_pipe_end_long_transfer(usb_pipe_t *pipe) 224 { 225 pipe_drop_ref(pipe); 309 /*----------------------------------------------------------------------------*/ 310 /** Register endpoint with the host controller. 311 * 312 * @param pipe Pipe to be registered. 313 * @param interval Polling interval. 314 * @return Error code. 315 */ 316 int usb_pipe_register(usb_pipe_t *pipe, unsigned interval) 317 { 318 assert(pipe); 319 assert(pipe->wire); 320 321 return usb_device_register_endpoint(pipe->wire, 322 pipe->endpoint_no, pipe->transfer_type, 323 pipe->direction, pipe->max_packet_size, interval); 324 } 325 /*----------------------------------------------------------------------------*/ 326 /** Revert endpoint registration with the host controller. 327 * 328 * @param pipe Pipe to be unregistered. 329 * @return Error code. 330 */ 331 int usb_pipe_unregister(usb_pipe_t *pipe) 332 { 333 assert(pipe); 334 assert(pipe->wire); 335 336 return usb_device_unregister_endpoint(pipe->wire, 337 pipe->endpoint_no, pipe->direction); 226 338 } 227 339
Note:
See TracChangeset
for help on using the changeset viewer.