1 /*
2 * Copyright 2006, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Michael Lotz <mmlr@mlotz.ch>
7 */
8 #ifndef EHCI_H
9 #define EHCI_H
10
11 #include "usb_private.h"
12 #include "ehci_hardware.h"
13
14
15 struct pci_info;
16 struct pci_device_module_info;
17 struct pci_device;
18
19 class EHCIRootHub;
20
21
22 typedef struct transfer_data {
23 Transfer * transfer;
24 ehci_qh * queue_head;
25 ehci_qtd * data_descriptor;
26 bool incoming;
27 bool canceled;
28 transfer_data * link;
29 } transfer_data;
30
31
32 // This structure is used to create a list of
33 // descriptors per isochronous transfer
34 typedef struct isochronous_transfer_data {
35 Transfer * transfer;
36 // The next field is used to keep track
37 // of every isochronous descriptor as they are NOT
38 // linked to each other in a queue like in every other
39 // transfer type
40 ehci_itd ** descriptors;
41 uint16 last_to_process;
42 bool incoming;
43 bool is_active;
44 isochronous_transfer_data * link;
45
46 size_t buffer_size;
47 void * buffer_log;
48 addr_t buffer_phy;
49 } isochronous_transfer_data;
50
51
52 class EHCI : public BusManager {
53 public:
54 EHCI(pci_info *info, pci_device_module_info* pci,
55 pci_device* device, Stack *stack, device_node *node);
56 ~EHCI();
57
58 status_t Start();
59
60 virtual status_t StartDebugTransfer(Transfer *transfer);
61 virtual status_t CheckDebugTransfer(Transfer *transfer);
62 void LinkAsyncDebugQueueHead(ehci_qh *queueHead);
63 void LinkPeriodicDebugQueueHead(
64 ehci_qh *queueHead, Pipe *pipe);
65 virtual void CancelDebugTransfer(Transfer *transfer);
66 void CleanupDebugTransfer(Transfer *transfer);
67
68 virtual status_t SubmitTransfer(Transfer *transfer);
69 status_t SubmitIsochronous(Transfer *transfer);
70
71 virtual status_t CancelQueuedTransfers(Pipe *pipe, bool force);
72 status_t CancelQueuedIsochronousTransfers(Pipe *pipe, bool force);
73
74 virtual status_t NotifyPipeChange(Pipe *pipe,
75 usb_change change);
76
77 // Port operations for root hub
PortCount()78 uint8 PortCount() { return fPortCount; }
79 status_t GetPortStatus(uint8 index, usb_port_status *status);
80 status_t SetPortFeature(uint8 index, uint16 feature);
81 status_t ClearPortFeature(uint8 index, uint16 feature);
82
83 status_t ResetPort(uint8 index);
84 status_t SuspendPort(uint8 index);
85
TypeName()86 virtual const char * TypeName() const { return "ehci"; }
87
88 private:
89 // Controller resets
90 status_t ControllerReset();
91 status_t LightReset();
92
93 // Interrupt functions
94 static int32 InterruptHandler(void *data);
95 int32 Interrupt();
96 static int32 InterruptPollThread(void *data);
97
98 // Transfer management
99 status_t AddPendingTransfer(Transfer *transfer,
100 ehci_qh *queueHead,
101 ehci_qtd *dataDescriptor,
102 bool directionIn);
103 status_t AddPendingIsochronousTransfer(
104 Transfer *transfer,
105 ehci_itd **isoRequest, uint32 lastIndex,
106 bool directionIn, addr_t bufferPhy,
107 void *bufferLog, size_t bufferSize);
108 status_t CancelAllPendingTransfers();
109
110
111 static int32 FinishThread(void *data);
112 void FinishTransfers();
113 static int32 CleanupThread(void *data);
114 void Cleanup();
115
116 // Isochronous transfer functions
117 static int32 FinishIsochronousThread(void *data);
118 void FinishIsochronousTransfers();
119 isochronous_transfer_data * FindIsochronousTransfer(ehci_itd *itd);
120 void LinkITDescriptors(ehci_itd *itd,
121 ehci_itd **last);
122 void LinkSITDescriptors(ehci_sitd *sitd,
123 ehci_sitd **last);
124 void UnlinkITDescriptors(ehci_itd *itd,
125 ehci_itd **last);
126 void UnlinkSITDescriptors(ehci_sitd *sitd,
127 ehci_sitd **last);
128
129 // Queue Head functions
130 ehci_qh * CreateQueueHead();
131 status_t InitQueueHead(ehci_qh *queueHead,
132 Pipe *pipe);
133 void FreeQueueHead(ehci_qh *queueHead);
134
135 status_t LinkQueueHead(ehci_qh *queueHead);
136 status_t LinkInterruptQueueHead(ehci_qh *queueHead,
137 Pipe *pipe);
138 status_t UnlinkQueueHead(ehci_qh *queueHead,
139 ehci_qh **freeList);
140
141 // Queue functions
142 status_t FillQueueWithRequest(Transfer *transfer,
143 ehci_qh *queueHead,
144 ehci_qtd **dataDescriptor,
145 bool *directionIn,
146 bool prepareKernelAccess);
147 status_t FillQueueWithData(Transfer *transfer,
148 ehci_qh *queueHead,
149 ehci_qtd **dataDescriptor,
150 bool *directionIn,
151 bool prepareKernelAccess);
152
153 bool LockIsochronous();
154 void UnlockIsochronous();
155
156 // Descriptor functions
157 ehci_qtd * CreateDescriptor(
158 size_t bufferSizeToAllocate,
159 uint8 pid);
160 status_t CreateDescriptorChain(Pipe *pipe,
161 ehci_qtd **firstDescriptor,
162 ehci_qtd **lastDescriptor,
163 ehci_qtd *strayDescriptor,
164 size_t bufferSizeToAllocate,
165 uint8 pid);
166 ehci_itd* CreateItdDescriptor();
167 ehci_sitd* CreateSitdDescriptor();
168
169 void FreeDescriptor(ehci_qtd *descriptor);
170 void FreeDescriptorChain(ehci_qtd *topDescriptor);
171 void FreeDescriptor(ehci_itd *descriptor);
172 void FreeDescriptor(ehci_sitd *descriptor);
173 void FreeIsochronousData(
174 isochronous_transfer_data *data);
175
176 void LinkDescriptors(ehci_qtd *first,
177 ehci_qtd *last, ehci_qtd *alt);
178
179 size_t WriteDescriptorChain(
180 ehci_qtd *topDescriptor,
181 generic_io_vec *vector, size_t vectorCount,
182 bool physical);
183 size_t ReadDescriptorChain(ehci_qtd *topDescriptor,
184 generic_io_vec *vector, size_t vectorCount,
185 bool physical, bool *nextDataToggle);
186 size_t ReadActualLength(ehci_qtd *topDescriptor,
187 bool *nextDataToggle);
188 size_t WriteIsochronousDescriptorChain(
189 isochronous_transfer_data *transfer);
190 size_t ReadIsochronousDescriptorChain(
191 isochronous_transfer_data *transfer);
192
193 // Operational register functions
194 inline void WriteOpReg(uint32 reg, uint32 value);
195 inline uint32 ReadOpReg(uint32 reg);
196
197 // Capability register functions
198 inline uint8 ReadCapReg8(uint32 reg);
199 inline uint16 ReadCapReg16(uint32 reg);
200 inline uint32 ReadCapReg32(uint32 reg);
201
202 uint8 * fCapabilityRegisters;
203 uint8 * fOperationalRegisters;
204 area_id fRegisterArea;
205 pci_info * fPCIInfo;
206 pci_device_module_info* fPci;
207 pci_device* fDevice;
208 Stack * fStack;
209 uint32 fEnabledInterrupts;
210 uint32 fThreshold;
211
212 // Periodic transfer framelist and interrupt entries
213 area_id fPeriodicFrameListArea;
214 uint32 * fPeriodicFrameList;
215 interrupt_entry * fInterruptEntries;
216 ehci_itd ** fItdEntries;
217 ehci_sitd ** fSitdEntries;
218
219 // Async transfer queue management
220 ehci_qh * fAsyncQueueHead;
221 sem_id fAsyncAdvanceSem;
222
223 // Maintain a linked list of transfers
224 transfer_data * fFirstTransfer;
225 transfer_data * fLastTransfer;
226 sem_id fFinishTransfersSem;
227 thread_id fFinishThread;
228 Pipe * fProcessingPipe;
229
230 ehci_qh * fFreeListHead;
231 sem_id fCleanupSem;
232 thread_id fCleanupThread;
233 bool fStopThreads;
234 int32 fNextStartingFrame;
235
236 // fFrameBandwidth[n] holds the available bandwidth
237 // of the nth frame in microseconds
238 uint16 * fFrameBandwidth;
239
240 // Maintain a linked list of isochronous transfers
241 isochronous_transfer_data * fFirstIsochronousTransfer;
242 isochronous_transfer_data * fLastIsochronousTransfer;
243 sem_id fFinishIsochronousTransfersSem;
244 thread_id fFinishIsochronousThread;
245 mutex fIsochronousLock;
246
247 // Root Hub
248 EHCIRootHub * fRootHub;
249 uint8 fRootHubAddress;
250
251 // Port management
252 uint8 fPortCount;
253 uint16 fPortResetChange;
254 uint16 fPortSuspendChange;
255
256 // Interrupt polling
257 thread_id fInterruptPollThread;
258 uint32 fIRQ;
259 bool fUseMSI;
260 };
261
262
263 class EHCIRootHub : public Hub {
264 public:
265 EHCIRootHub(Object *rootObject,
266 int8 deviceAddress);
267
268 static status_t ProcessTransfer(EHCI *ehci,
269 Transfer *transfer);
270 };
271
272
273 #endif // !EHCI_H
274