1 // Copyright 2018 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 <xdc-server-utils/packet.h>
8 #include <zircon/types.h>
9 
10 #include <map>
11 #include <set>
12 #include <vector>
13 
14 namespace xdc {
15 
16 class UsbHandler {
17     // This is required by the UsbHandler constructor, to stop clients calling it directly.
18     struct ConstructorTag {
19         explicit ConstructorTag() = default;
20     };
21 
22 public:
23     class Transfer {
24     public:
25         static constexpr const size_t BUFFER_SIZE = 16 * 1024;
26         static constexpr const size_t HEADER_SIZE = sizeof(xdc_packet_header_t);
27 
28         static constexpr const size_t MAX_WRITE_DATA_SIZE = BUFFER_SIZE - HEADER_SIZE;
29 
30         // Create should be called instead. This is public for make_shared.
Transfer(ConstructorTag tag)31         explicit Transfer(ConstructorTag tag) {}
32 
33         // Sets the header of the transfer.
34         // Returns ZX_OK on success, or ZX_ERR_INVALID_ARGS if data_len is larger than
35         // MAX_WRITE_DATA_SIZE.
36         zx_status_t FillHeader(uint32_t stream_id, size_t data_len);
37 
38         // Sets the contents of the transfer.
39         // Returns ZX_OK on success, or ZX_ERR_INVALID_ARGS if data_len is larger than
40         // MAX_WRITE_DATA_SIZE.
41         zx_status_t FillData(uint32_t stream_id, unsigned char* data, size_t data_len);
42 
43         bool SetOffset(int offset);
44 
45         // Returns the data buffer to be populated for a write transfer.
write_data_buffer()46         unsigned char* write_data_buffer() const { return data_ + HEADER_SIZE; }
data()47         unsigned char* data() const { return data_; }
48         // The number of bytes to be transferred.
request_length()49         int request_length() const { return request_length_; }
50         // The number of bytes successfully transferred.
actual_length()51         int actual_length() const { return actual_length_; }
52         // Returns where the client has read up to in the data.
53         // An offset equal to actual_length indicates the client has reached the end.
offset()54         int offset() const { return offset_; }
55 
56     private:
57         // Only UsbHandler should create transfers.
58         static std::unique_ptr<Transfer> Create();
59 
60         // TODO(jocelyndang): this should store a libusb_transfer instead.
61         unsigned char* data_;
62         int request_length_;
63         int actual_length_;
64 
65         int offset_;
66 
67         friend class UsbHandler;
68     };
69 
70     // Create should be called instead. This is public for make_unique.
UsbHandler(ConstructorTag tag)71     explicit UsbHandler(ConstructorTag tag) {}
72 
73     static std::unique_ptr<UsbHandler> Create();
74 
75     // Handles any pending events.
76     //
77     // Parameters:
78     // completed_reads  A vector which will be populated with the usb transfers containing data
79     //                  read from the xdc device. Once the client has finished processing a read,
80     //                  it should be returned back to the UsbHandler by calling RequeueRead.
81     //
82     // Returns whether the usb handler fds have changed.
83     // If true, the newly added or removed fds should be fetched via GetFdUpdates.
84     bool HandleEvents(std::vector<std::unique_ptr<Transfer>>& completed_reads);
85 
86     // Returns the read transfer back to the UsbHandler to be requeued.
87     void RequeueRead(std::unique_ptr<Transfer> transfer);
88 
89     // Populates added_fds and removed_fds with the fds that have been added
90     // and removed since GetFdUpdates was last called.
91     //
92     // Parameters:
93     // added_fds      A map that will be populated with fds to start monitoring and
94     //                the corresponding events to monitor for.
95     // removed_fds    A set that will be populated with fds to stop monitoring.
96     //                The fds will be disjoint from added_fds.
97     void GetFdUpdates(std::map<int, short>& added_fds, std::set<int>& removed_fds);
98 
99     // Returns a write transfer that can be used with QueueWriteTransfer to write
100     // data to the xdc device. May return a nullptr if no transfers are available.
101     std::unique_ptr<Transfer> GetWriteTransfer();
102     void ReturnWriteTransfer(std::unique_ptr<Transfer>);
103     // Returns a nullptr if the transfer was successfully queued,
104     // otherwise returns the transfer to the client.
105     std::unique_ptr<Transfer> QueueWriteTransfer(std::unique_ptr<Transfer>);
106 
107     // Returns whether the given file descriptor is currently valid for the usb handler.
IsValidFd(int fd)108     bool IsValidFd(int fd) const { return fds_.count(fd); }
109 
writable()110     bool writable() const { return writable_; }
111 
112 private:
113     // All the libusb fds.
114     std::set<int> fds_;
115 
116     bool writable_;
117 };
118 
119 } // namespace xdc
120