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
15struct pci_info;
16struct pci_device_module_info;
17struct pci_device;
18
19class EHCIRootHub;
20
21
22typedef 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
34typedef 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
52class EHCI : public BusManager {
53public:
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
60virtual	status_t					StartDebugTransfer(Transfer *transfer);
61virtual	status_t					CheckDebugTransfer(Transfer *transfer);
62		void						LinkAsyncDebugQueueHead(ehci_qh *queueHead);
63		void						LinkPeriodicDebugQueueHead(
64										ehci_qh *queueHead, Pipe *pipe);
65virtual	void						CancelDebugTransfer(Transfer *transfer);
66		void						CleanupDebugTransfer(Transfer *transfer);
67
68virtual	status_t					SubmitTransfer(Transfer *transfer);
69		status_t					SubmitIsochronous(Transfer *transfer);
70
71virtual	status_t					CancelQueuedTransfers(Pipe *pipe, bool force);
72		status_t					CancelQueuedIsochronousTransfers(Pipe *pipe, bool force);
73
74virtual	status_t					NotifyPipeChange(Pipe *pipe,
75										usb_change change);
76
77		// Port operations for root hub
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
86virtual	const char *				TypeName() const { return "ehci"; }
87
88private:
89		// Controller resets
90		status_t					ControllerReset();
91		status_t					LightReset();
92
93		// Interrupt functions
94static	int32						InterruptHandler(void *data);
95		int32						Interrupt();
96static	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
111static	int32						FinishThread(void *data);
112		void						FinishTransfers();
113static	int32						CleanupThread(void *data);
114		void						Cleanup();
115
116		// Isochronous transfer functions
117static 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
194inline	void						WriteOpReg(uint32 reg, uint32 value);
195inline	uint32						ReadOpReg(uint32 reg);
196
197		// Capability register functions
198inline	uint8						ReadCapReg8(uint32 reg);
199inline	uint16						ReadCapReg16(uint32 reg);
200inline	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
263class EHCIRootHub : public Hub {
264public:
265									EHCIRootHub(Object *rootObject,
266										int8 deviceAddress);
267
268static	status_t					ProcessTransfer(EHCI *ehci,
269										Transfer *transfer);
270};
271
272
273#endif // !EHCI_H
274