1// Copyright 2016 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#pragma once
6
7#include <ddk/phys-iter.h>
8#include <sys/types.h>
9#include <zircon/compiler.h>
10#include <zircon/types.h>
11#include <zircon/hw/usb.h>
12#include <zircon/hw/usb-hub.h>
13#include <zircon/listnode.h>
14
15__BEGIN_CDECLS;
16
17typedef struct usb_request usb_request_t;
18
19// cache maintenance ops
20#define USB_REQUEST_CACHE_INVALIDATE        ZX_VMO_OP_CACHE_INVALIDATE
21#define USB_REQUEST_CACHE_CLEAN             ZX_VMO_OP_CACHE_CLEAN
22#define USB_REQUEST_CACHE_CLEAN_INVALIDATE  ZX_VMO_OP_CACHE_CLEAN_INVALIDATE
23#define USB_REQUEST_CACHE_SYNC              ZX_VMO_OP_CACHE_SYNC
24
25typedef void (*usb_request_complete_cb)(usb_request_t* req, void* cookie);
26
27// Should be set by the requestor.
28typedef struct usb_header {
29    // frame number for scheduling isochronous transfers
30    uint64_t frame;
31    uint32_t device_id;
32    // bEndpointAddress from endpoint descriptor
33    uint8_t ep_address;
34    // number of bytes to transfer
35    zx_off_t length;
36    // send zero length packet if length is multiple of max packet size
37    bool send_zlp;
38} usb_header_t;
39
40// response data
41// (filled in by processor before usb_request_complete() is called)
42typedef struct usb_response {
43    // status of transaction
44    zx_status_t status;
45    // number of bytes actually transferred (on success)
46    zx_off_t actual;
47} usb_response_t;
48
49typedef struct usb_request {
50    usb_header_t header;
51
52    // for control transactions
53    usb_setup_t setup;
54
55    // vmo_handle for payload
56    zx_handle_t vmo_handle;
57    zx_handle_t bti_handle;
58    size_t size;
59    // offset of the start of data from first page address of the vmo.
60    zx_off_t offset;
61    // mapped address of the first page of the vmo.
62    // Add offset to get actual data.
63    void* virt;
64
65    zx_handle_t pmt;
66    // phys addresses of the payload.
67    zx_paddr_t* phys_list;
68    // Number of physical pages of the payload.
69    uint64_t phys_count;
70
71    // The complete_cb() callback is set by the requestor and is
72    // invoked by the 'complete' ops method when it is called by
73    // the processor upon completion of the usb request.
74    // The saved_complete_cb field can be used to temporarily save
75    // the original callback and overwrite it with the desired intermediate
76    // callback.
77    usb_request_complete_cb complete_cb;
78
79    // Set by the requestor for opting out of the complete_cb()
80    // callback for successfully completed requests. The callback
81    // will still be invoked if an error is encountered.
82    // This is useful for isochronous requests, where the requestor
83    // may not care about most callbacks. They will still have to request
84    // callbacks at a regular interval to queue more data, and free or
85    // reuse previously silently completed requests.
86    bool cb_on_error_only;
87
88    // Set by requestor for passing data to complete_cb callback
89    // The saved_cookie field can be used to temporarily save the
90    // original cookie.
91    void* cookie;
92
93    // The current 'owner' of the usb request may save the original
94    // complete callback and cookie, allowing them to insert an
95    // intermediate callback.
96    usb_request_complete_cb saved_complete_cb;
97    void* saved_cookie;
98
99    usb_response_t response;
100
101    // list node and context
102    // the current "owner" of the usb_request may use these however desired
103    // (eg, the requestor may use node to hold the usb_request on a free list
104    // and when it's queued the processor may use node to hold the usb_request
105    // in a transaction queue)
106    list_node_t node;
107
108    void *context;
109
110    // The release_cb() callback is set by the allocator and is
111    // invoked by the 'usb_request_release' method when it is called
112    // by the requestor.
113    void (*release_cb)(usb_request_t* req);
114} usb_request_t;
115
116
117typedef struct {
118    zx_status_t (*req_alloc)(void* ctx, usb_request_t** out, uint64_t data_size,
119                             uint8_t ep_address);
120    zx_status_t (*req_alloc_vmo)(void* ctx, usb_request_t** out, zx_handle_t vmo_handle,
121                                 uint64_t vmo_offset, uint64_t length, uint8_t ep_address);
122    zx_status_t (*req_init)(void* ctx, usb_request_t* req, zx_handle_t vmo_handle,
123                            uint64_t vmo_offset, uint64_t length, uint8_t ep_address);
124    ssize_t (*req_copy_from)(void* ctx, usb_request_t* req, void* data,
125                                 size_t length, size_t offset);
126    ssize_t (*req_copy_to)(void* ctx, usb_request_t* req, const void* data,
127                               size_t length, size_t offset);
128    zx_status_t (*req_mmap)(void* ctx, usb_request_t* req, void** data);
129    zx_status_t (*req_cacheop)(void* ctx, usb_request_t* req, uint32_t op,
130                                   size_t offset, size_t length);
131    zx_status_t (*req_cache_flush)(void* ctx, usb_request_t* req,
132                                   size_t offset, size_t length);
133    zx_status_t (*req_cache_flush_invalidate)(void* ctx, usb_request_t* req,
134                                              zx_off_t offset, size_t length);
135    zx_status_t (*req_physmap)(void* ctx, usb_request_t* req);
136    void (*req_release)(void* ctx, usb_request_t* req);
137    void (*req_complete)(void* ctx, usb_request_t* req, zx_status_t status, zx_off_t actual);
138    void (*req_phys_iter_init)(void* ctx, phys_iter_t* iter, usb_request_t* req,
139                                   size_t max_length);
140    zx_status_t (*control)(void* ctx, uint8_t request_type, uint8_t request, uint16_t value,
141                           uint16_t index, void* data, size_t length, zx_time_t timeout,
142                           size_t* out_length);
143    // queues a USB request
144    void (*request_queue)(void* ctx, usb_request_t* usb_request);
145    usb_speed_t (*get_speed)(void* ctx);
146    zx_status_t (*set_interface)(void* ctx, uint8_t interface_number, uint8_t alt_setting);
147    uint8_t (*get_configuration)(void* ctx);
148    zx_status_t (*set_configuration)(void* ctx, uint8_t configuration);
149    zx_status_t (*enable_endpoint)(void* ctx, usb_endpoint_descriptor_t* ep_desc,
150                                   usb_ss_ep_comp_descriptor_t* ss_comp_desc, bool enable);
151    zx_status_t (*reset_endpoint)(void* ctx, uint8_t ep_address);
152    size_t (*get_max_transfer_size)(void* ctx, uint8_t ep_address);
153    uint32_t (*get_device_id)(void* ctx);
154    void (*get_device_descriptor)(void* ctx, usb_device_descriptor_t* out_desc);
155    zx_status_t (*get_configuration_descriptor)(void* ctx, uint8_t configuration,
156                                                usb_configuration_descriptor_t** out,
157                                                size_t* out_length);
158    zx_status_t (*get_descriptor_list)(void* ctx, void** out_descriptors, size_t* out_length);
159    zx_status_t (*get_string_descriptor)(void* ctx, uint8_t desc_id, uint16_t* inout_lang_id,
160                                         uint8_t* buf, size_t* inout_buflen);
161    zx_status_t (*cancel_all)(void* ctx, uint8_t ep_address);
162    uint64_t (*get_current_frame)(void* ctx);
163} usb_protocol_ops_t;
164
165typedef struct usb_protocol {
166    usb_protocol_ops_t* ops;
167    void* ctx;
168} usb_protocol_t;
169
170static inline zx_status_t usb_req_alloc(const usb_protocol_t* usb, usb_request_t** out,
171                                        uint64_t data_size, uint8_t ep_address) {
172    return usb->ops->req_alloc(usb->ctx, out, data_size, ep_address);
173}
174
175static inline zx_status_t usb_req_alloc_vmo(const usb_protocol_t* usb, usb_request_t** out,
176                                             zx_handle_t vmo_handle, uint64_t vmo_offset,
177                                             uint64_t length, uint8_t ep_address) {
178    return usb->ops->req_alloc_vmo(usb->ctx, out, vmo_handle, vmo_offset, length, ep_address);
179}
180
181static inline zx_status_t usb_req_init(const usb_protocol_t* usb, usb_request_t* req,
182                                       zx_handle_t vmo_handle, uint64_t vmo_offset,
183                                       uint64_t length, uint8_t ep_address) {
184    return usb->ops->req_init(usb->ctx, req, vmo_handle, vmo_offset, length, ep_address);
185}
186
187static inline ssize_t usb_req_copy_from(const usb_protocol_t* usb, usb_request_t* req, void* data,
188                                        size_t length, size_t offset) {
189    return usb->ops->req_copy_from(usb->ctx, req, data, length, offset);
190}
191
192static inline ssize_t usb_req_copy_to(const usb_protocol_t* usb, usb_request_t* req,
193                                      const void* data, size_t length, size_t offset) {
194    return usb->ops->req_copy_to(usb->ctx, req, data, length, offset);
195}
196
197static inline zx_status_t usb_req_mmap(const usb_protocol_t* usb, usb_request_t* req,
198                                       void** data) {
199    return usb->ops->req_mmap(usb->ctx, req, data);
200}
201
202static inline zx_status_t usb_req_cacheop(const usb_protocol_t* usb, usb_request_t* req,
203                                          uint32_t op, size_t offset, size_t length) {
204    return usb->ops->req_cacheop(usb->ctx, req, op, offset, length);
205}
206
207static inline zx_status_t usb_req_cache_flush(const usb_protocol_t* usb, usb_request_t* req,
208                                              size_t offset, size_t length) {
209    return usb->ops->req_cache_flush(usb->ctx, req, offset, length);
210}
211
212static inline zx_status_t usb_req_cache_flush_invalidate(const usb_protocol_t* usb,
213                                                         usb_request_t* req, zx_off_t offset,
214                                                         size_t length) {
215    return usb->ops->req_cache_flush_invalidate(usb->ctx, req, offset, length);
216}
217
218static inline zx_status_t usb_req_physmap(const usb_protocol_t* usb, usb_request_t* req) {
219    return usb->ops->req_physmap(usb->ctx, req);
220}
221
222static inline void usb_req_release(const usb_protocol_t* usb, usb_request_t* req) {
223    usb->ops->req_release(usb->ctx, req);
224}
225
226static inline void usb_req_complete(const usb_protocol_t* usb, usb_request_t* req,
227                             zx_status_t status, zx_off_t actual) {
228    usb->ops->req_complete(usb->ctx, req, status, actual);
229}
230
231static inline void usb_req_phys_iter_init(const usb_protocol_t* usb, phys_iter_t* iter,
232                                          usb_request_t* req, size_t max_length) {
233    usb->ops->req_phys_iter_init(usb->ctx, iter, req, max_length);
234}
235
236// synchronously executes a control request on endpoint zero
237static inline zx_status_t usb_control(const usb_protocol_t* usb, uint8_t request_type,
238                                      uint8_t request, uint16_t value, uint16_t index, void* data,
239                                      size_t length, zx_time_t timeout, size_t* out_length) {
240    return usb->ops->control(usb->ctx, request_type, request, value, index, data, length, timeout,
241                             out_length);
242}
243
244static inline zx_status_t usb_get_descriptor(const usb_protocol_t* usb, uint8_t request_type,
245                                             uint16_t type, uint16_t index, void* data,
246                                             size_t length, zx_time_t timeout, size_t* out_length) {
247    return usb_control(usb, request_type | USB_DIR_IN, USB_REQ_GET_DESCRIPTOR,
248                       (uint16_t)(type << 8 | index), 0, data, length, timeout, out_length);
249}
250
251static inline zx_status_t usb_get_status(const usb_protocol_t* usb, uint8_t request_type,
252                                         uint16_t index, void* data, size_t length,
253                                         zx_time_t timeout, size_t* out_length) {
254    return usb_control(usb, request_type | USB_DIR_IN, USB_REQ_GET_STATUS, 0, index, data, length,
255                       timeout, out_length);
256}
257
258static inline zx_status_t usb_set_feature(const usb_protocol_t* usb, uint8_t request_type,
259                                          uint16_t feature, uint16_t index, zx_time_t timeout) {
260    return usb_control(usb, request_type, USB_REQ_SET_FEATURE, feature, index, NULL, 0, timeout,
261                       NULL);
262}
263
264static inline zx_status_t usb_clear_feature(const usb_protocol_t* usb, uint8_t request_type,
265                                            uint16_t feature, uint16_t index, zx_time_t timeout) {
266    return usb_control(usb, request_type, USB_REQ_CLEAR_FEATURE, feature, index, NULL, 0, timeout,
267                       NULL);
268}
269
270static inline void usb_request_queue(const usb_protocol_t* usb, usb_request_t* usb_request) {
271    return usb->ops->request_queue(usb->ctx, usb_request);
272}
273
274static inline usb_speed_t usb_get_speed(const usb_protocol_t* usb) {
275    return usb->ops->get_speed(usb->ctx);
276}
277
278static inline zx_status_t usb_set_interface(const usb_protocol_t* usb, uint8_t interface_number,
279                                            uint8_t alt_setting) {
280    return usb->ops->set_interface(usb->ctx, interface_number, alt_setting);
281}
282
283static inline uint8_t usb_get_configuration(const usb_protocol_t* usb) {
284    return usb->ops->get_configuration(usb->ctx);
285}
286
287static inline zx_status_t usb_set_configuration(const usb_protocol_t* usb, uint8_t configuration) {
288    return usb->ops->set_configuration(usb->ctx, configuration);
289}
290
291static inline zx_status_t usb_enable_endpoint(const usb_protocol_t* usb,
292                                              usb_endpoint_descriptor_t* ep_desc,
293                                              usb_ss_ep_comp_descriptor_t* ss_comp_desc,
294                                              bool enable) {
295    return usb->ops->enable_endpoint(usb->ctx, ep_desc, ss_comp_desc, enable);
296}
297
298// Resets an endpoint that is in a halted or error state.
299// Endpoints will be halted if the device returns a STALL in response to a USB transaction.
300// When that occurs, the transaction will fail with ERR_IO_REFUSED.
301// usb_reset_endpoint() the endpoint to normal running state.
302static inline zx_status_t usb_reset_endpoint(const usb_protocol_t* usb, uint8_t ep_address) {
303    return usb->ops->reset_endpoint(usb->ctx, ep_address);
304}
305
306// returns the maximum amount of data that can be transferred on an endpoint in a single transaction.
307static inline size_t usb_get_max_transfer_size(const usb_protocol_t* usb, uint8_t ep_address) {
308    return usb->ops->get_max_transfer_size(usb->ctx, ep_address);
309}
310
311// Returns the device ID for the device.
312// This ID is generated by and used internally by the USB HCI controller driver.
313static inline uint32_t usb_get_device_id(const usb_protocol_t* usb) {
314    return usb->ops->get_device_id(usb->ctx);
315}
316
317// Returns the device's device descriptor.
318static inline void usb_get_device_descriptor(const usb_protocol_t* usb,
319                                             usb_device_descriptor_t* out_desc) {
320    usb->ops->get_device_descriptor(usb->ctx, out_desc);
321}
322
323// Returns the configuration descriptor for the given configuration.
324static inline zx_status_t usb_get_configuration_descriptor(const usb_protocol_t* usb,
325                                                           uint8_t configuration,
326                                                           usb_configuration_descriptor_t** out,
327                                                           size_t* out_length) {
328    return usb->ops->get_configuration_descriptor(usb->ctx, configuration, out, out_length);
329}
330
331// returns the USB descriptors for the USB device or interface
332// the returned value is de-allocated with free()
333static inline zx_status_t usb_get_descriptor_list(const usb_protocol_t* usb, void** out_descriptors,
334                                                  size_t* out_length) {
335    return usb->ops->get_descriptor_list(usb->ctx, out_descriptors, out_length);
336}
337
338// Fetch the descriptor using the provided descriptor ID and language ID.  If
339// the language ID requested is not available, the first entry of the language
340// ID table will be used instead and be provided in the updated version of the
341// parameter.
342//
343// The string will be encoded using UTF-8, and will be truncated to fit the
344// space provided by the buflen parameter.  buflen will be updated to indicate
345// the amount of space needed to hold the actual UTF-8 encoded string lenth, and
346// may be larger than the original value passed.  Embedded nulls may be present
347// in the string, and the result may not be null terminated if the string
348// occupies the entire provided buffer.
349//
350static inline zx_status_t usb_get_string_descriptor(const usb_protocol_t* usb,
351                                                    uint8_t desc_id, uint16_t* inout_lang_id,
352                                                    uint8_t* buf, size_t* inout_buflen) {
353    return usb->ops->get_string_descriptor(usb->ctx, desc_id, inout_lang_id, buf, inout_buflen);
354}
355
356static inline zx_status_t usb_cancel_all(const usb_protocol_t* usb, uint8_t ep_address) {
357    return usb->ops->cancel_all(usb->ctx, ep_address);
358}
359
360// returns the current frame (in milliseconds), used for isochronous transfers
361static inline uint64_t usb_get_current_frame(const usb_protocol_t* usb) {
362    return usb->ops->get_current_frame(usb->ctx);
363}
364
365__END_CDECLS;
366