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