1 // Copyright 2017 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 <stdint.h>
8 #include <sys/types.h>
9 #include <ddk/io-buffer.h>
10 #include <ddk/protocol/usb.h>
11 #include <ddk/protocol/usb/request.h>
12 #include <zircon/hw/usb.h>
13 #include <zircon/listnode.h>
14 
15 #include <threads.h>
16 
17 __BEGIN_CDECLS;
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 
25 typedef struct {
26     list_node_t free_reqs;
27     mtx_t lock;
28     //offset of the list_node_t* (used for queueing) in usb_request_t.
29     uint64_t node_offset;
30 } usb_request_pool_t;
31 
32 typedef struct {
33     list_node_t node;
34 } usb_req_internal_t;
35 
36 #define USB_REQ_TO_REQ_INTERNAL(req, size) \
37    ((usb_req_internal_t *)((uintptr_t)(req) + (size)))
38 #define REQ_INTERNAL_TO_USB_REQ(ctx, size) ((usb_request_t *)((uintptr_t)(ctx) - (size)))
39 
40 // usb_request_alloc() creates a new usb request with payload space of data_size.
41 zx_status_t usb_request_alloc(usb_request_t** out, uint64_t data_size,
42                               uint8_t ep_address, size_t req_size);
43 
44 // usb_request_alloc_vmo() creates a new usb request with the given VMO.
45 zx_status_t usb_request_alloc_vmo(usb_request_t** out, zx_handle_t vmo_handle, uint64_t vmo_offset,
46                                   uint64_t length, uint8_t ep_address, size_t req_size);
47 
48 // usb_request_init() initializes the statically allocated usb request with the given VMO.
49 // This will free any resources allocated by the usb request but not the usb request itself.
50 zx_status_t usb_request_init(usb_request_t* req, zx_handle_t vmo_handle,
51                              uint64_t vmo_offset, uint64_t length, uint8_t ep_address);
52 
53 // usb_request_set_sg_list() copies the scatter gather list to the request.
54 // Future transfers using this request will determine where in the VMO to store read / write data
55 // using the scatter gather list.
56 // This will free any existing scatter gather list stored in the request.
57 zx_status_t usb_request_set_sg_list(usb_request_t* req, phys_iter_sg_entry_t* sg_list,
58                                     size_t sg_count);
59 
60 // usb_request_copy_from() copies data from the usb_request's vm object.
61 // Out of range operations are ignored.
62 ssize_t usb_request_copy_from(usb_request_t* req, void* data, size_t length, size_t offset);
63 
64 // usb_request_copy_to() copies data into a usb_request's vm object.
65 // Out of range operations are ignored.
66 ssize_t usb_request_copy_to(usb_request_t* req, const void* data, size_t length, size_t offset);
67 
68 // usb_request_mmap() maps the usb request's vm object. The 'data' field is set with the
69 // mapped address if this function succeeds.
70 zx_status_t usb_request_mmap(usb_request_t* req, void** data);
71 
72 // usb_request_cacheop() performs a cache maintenance op against the request's internal
73 // buffer.
74 zx_status_t usb_request_cacheop(usb_request_t* req, uint32_t op, size_t offset, size_t length);
75 
76 // usb_request_cache_flush() performs a cache flush on a range of memory in the request's buffer
77 zx_status_t usb_request_cache_flush(usb_request_t* req, zx_off_t offset, size_t length);
78 
79 // usb_request_cache_flush_invalidate() performs a cache flush and invalidate on a range of memory
80 // in the request's buffer
81 zx_status_t usb_request_cache_flush_invalidate(usb_request_t* req, zx_off_t offset, size_t length);
82 
83 // Looks up the physical pages backing this request's vm object.
84 zx_status_t usb_request_physmap(usb_request_t* req, zx_handle_t bti_handle);
85 
86 // usb_request_release() frees the message data -- should be called only by the entity that allocated it
87 void usb_request_release(usb_request_t* req);
88 
89 // usb_request_complete() must be called by the processor when the request has
90 // completed or failed and the request and any virtual or physical memory obtained
91 // from it may not be touched again by the processor.
92 //
93 // The complete_cb() will be called as the last action of this method.
94 void usb_request_complete(usb_request_t* req, zx_status_t status, zx_off_t actual,
95                           const usb_request_complete_t* complete_cb);
96 
97 // initializes a phys_iter_t for a usb request
98 // max_length is the maximum length of a range returned by usb_request_phys_iter_next()
99 // max_length must be either a positive multiple of PAGE_SIZE, or zero for no limit.
100 void usb_request_phys_iter_init(phys_iter_t* iter, usb_request_t* req, size_t max_length);
101 
102 // returns the next physical address and length for the iterator up to size max_length.
103 // return value is length, or zero if iteration is done.
104 size_t usb_request_phys_iter_next(phys_iter_t* iter, zx_paddr_t* out_paddr);
105 
106 // usb_request_pool_init() initializes the given pool. A driver may use
107 // a pool for recycling their own usb requests.
108 void usb_request_pool_init(usb_request_pool_t* pool, uint64_t node_offset);
109 
110 // usb_request_pool_add() adds the request to the pool.
111 zx_status_t usb_request_pool_add(usb_request_pool_t* pool, usb_request_t* req);
112 
113 // returns a request from the pool that has a buffer of the given length,
114 // or null if no such request exists.
115 // The request is not re-initialized in any way and should be set accordingly by the user.
116 usb_request_t* usb_request_pool_get(usb_request_pool_t* pool, size_t length);
117 
118 // releases all usb requests stored in the pool.
119 void usb_request_pool_release(usb_request_pool_t* pool);
120 
121 // Assumes usb_req_internal_t struct is allocated at parent_req_size offset in a usb request.
122 // Adds a request to the head of the list using the list_node_t pointer from that struct.
123 zx_status_t usb_req_list_add_head(list_node_t* list, usb_request_t* req, size_t parent_req_size);
124 // Assumes usb_req_internal_t is allocated at parent_req_size offset in a usb request. Adds a
125 // request to the tail of the list using the list_node_t pointer from that internal struct.
126 zx_status_t usb_req_list_add_tail(list_node_t* list, usb_request_t* req, size_t parent_req_size);
127 // Assumes usb_req_internal_t is allocated at parent_req_size offset in a usb request. Removes a
128 // request from the head of the list and returns the usb_request_t.
129 usb_request_t* usb_req_list_remove_head(list_node_t* list, size_t parent_req_size);
130 
131 __END_CDECLS;
132