1/*
2 * Copyright 2004-2011, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Michael Lotz <mmlr@mlotz.ch>
7 *		Niels S. Reedijk
8 *		Salvatore Benedetto <salvatore.benedetto@gmail.com>
9 */
10#ifndef UHCI_H
11#define UHCI_H
12
13#include "usb_private.h"
14#include "uhci_hardware.h"
15#include <lock.h>
16
17#define UHCI_INTERRUPT_QUEUE				0
18#define UHCI_LOW_SPEED_CONTROL_QUEUE		1
19#define UHCI_FULL_SPEED_CONTROL_QUEUE		2
20#define UHCI_BULK_QUEUE						3
21#define UHCI_BANDWIDTH_RECLAMATION_QUEUE	4
22#define UHCI_DEBUG_QUEUE					4
23
24struct pci_info;
25struct pci_device_module_info;
26struct pci_device;
27class UHCIRootHub;
28
29
30class Queue {
31public:
32									Queue(Stack *stack);
33									~Queue();
34
35		bool						Lock();
36		void						Unlock();
37
38		status_t					InitCheck();
39
40		status_t					LinkTo(Queue *other);
41		status_t					TerminateByStrayDescriptor();
42
43		status_t					AppendTransfer(uhci_qh *transfer,
44										bool lock = true);
45		status_t					RemoveTransfer(uhci_qh *transfer,
46										bool lock = true);
47
48		uint32						PhysicalAddress();
49
50		void						PrintToStream();
51
52		usb_id						USBID() { return 0; };
53		const char *				TypeName() { return "uhci"; };
54
55private:
56		status_t					fStatus;
57		Stack *						fStack;
58		uhci_qh *					fQueueHead;
59		uhci_td *					fStrayDescriptor;
60		uhci_qh *					fQueueTop;
61		mutex						fLock;
62};
63
64
65typedef struct transfer_data {
66	Transfer *		transfer;
67	Queue *			queue;
68	uhci_qh *		transfer_queue;
69	uhci_td *		first_descriptor;
70	uhci_td *		data_descriptor;
71	bool			incoming;
72	bool			canceled;
73	uint16			free_after_frame;
74	transfer_data *	link;
75} transfer_data;
76
77
78// This structure is used to create a list of
79// descriptors per isochronous transfer
80typedef struct isochronous_transfer_data {
81	Transfer *					transfer;
82	// The next field is used to keep track
83	// of every isochronous descriptor as they are NOT
84	// linked to each other in a queue like in every other
85	// transfer type
86	uhci_td **					descriptors;
87	uint16						last_to_process;
88	bool						incoming;
89	bool						is_active;
90	isochronous_transfer_data *	link;
91} isochronous_transfer_data;
92
93
94class UHCI : public BusManager {
95public:
96									UHCI(pci_info *info, pci_device_module_info* pci,
97										pci_device* device, Stack *stack, device_node* node);
98									~UHCI();
99
100		status_t					Start();
101virtual	status_t					SubmitTransfer(Transfer *transfer);
102
103virtual	status_t					StartDebugTransfer(Transfer *transfer);
104virtual	status_t					CheckDebugTransfer(Transfer *transfer);
105virtual	void						CancelDebugTransfer(Transfer *transfer);
106
107virtual	status_t					CancelQueuedTransfers(Pipe *pipe, bool force);
108		status_t					CancelQueuedIsochronousTransfers(Pipe *pipe, bool force);
109		status_t					SubmitRequest(Transfer *transfer);
110		status_t					SubmitIsochronous(Transfer *transfer);
111
112		// Port operations
113		status_t					GetPortStatus(uint8 index, usb_port_status *status);
114		status_t					SetPortFeature(uint8 index, uint16 feature);
115		status_t					ClearPortFeature(uint8 index, uint16 feature);
116
117		status_t					ResetPort(uint8 index);
118
119virtual	const char *				TypeName() const { return "uhci"; };
120
121private:
122		// Controller resets
123		void						GlobalReset();
124		status_t					ControllerReset();
125
126		// Interrupt functions
127static	int32						InterruptHandler(void *data);
128		int32						Interrupt();
129
130		// Transfer functions
131		status_t					AddPendingTransfer(Transfer *transfer,
132										Queue *queue,
133										uhci_qh *transferQueue,
134										uhci_td *firstDescriptor,
135										uhci_td *dataDescriptor,
136										bool directionIn);
137		status_t					AddPendingIsochronousTransfer(
138										Transfer *transfer,
139										uhci_td **isoRequest,
140										bool directionIn);
141
142static	int32						FinishThread(void *data);
143		void						FinishTransfers();
144
145		void						AddToFreeList(transfer_data *transfer);
146static	int32						CleanupThread(void *data);
147		void						Cleanup();
148
149		status_t					CreateFilledTransfer(Transfer *transfer,
150										uhci_td **_firstDescriptor,
151										uhci_qh **_transferQueue);
152
153		// Isochronous transfer functions
154static int32						FinishIsochronousThread(void *data);
155		void						FinishIsochronousTransfers();
156		isochronous_transfer_data *	FindIsochronousTransfer(uhci_td *descriptor);
157
158		status_t					LinkIsochronousDescriptor(
159										uhci_td *descriptor,
160										uint16 frame);
161		uhci_td *					UnlinkIsochronousDescriptor(uint16 frame);
162
163		// Transfer queue functions
164		uhci_qh *					CreateTransferQueue(uhci_td *descriptor);
165		void						FreeTransferQueue(uhci_qh *queueHead);
166
167		bool						LockIsochronous();
168		void						UnlockIsochronous();
169
170		// Descriptor functions
171		uhci_td *					CreateDescriptor(Pipe *pipe,
172										uint8 direction,
173										size_t bufferSizeToAllocate);
174		status_t					CreateDescriptorChain(Pipe *pipe,
175										uhci_td **firstDescriptor,
176										uhci_td **lastDescriptor,
177										uint8 direction,
178										size_t bufferSizeToAllocate);
179
180		void						FreeDescriptor(uhci_td *descriptor);
181		void						FreeDescriptorChain(uhci_td *topDescriptor);
182
183		void						LinkDescriptors(uhci_td *first,
184										uhci_td *second);
185
186		size_t						WriteDescriptorChain(uhci_td *topDescriptor,
187										generic_io_vec *vector, size_t vectorCount, bool physical);
188		size_t						ReadDescriptorChain(uhci_td *topDescriptor,
189										generic_io_vec *vector, size_t vectorCount, bool physical,
190										uint8 *lastDataToggle);
191		size_t						ReadActualLength(uhci_td *topDescriptor,
192										uint8 *lastDataToggle);
193		void						WriteIsochronousDescriptorChain(
194										uhci_td **isoRequest,
195										uint32 packetCount,
196										generic_io_vec *vector);
197		void						ReadIsochronousDescriptorChain(
198										isochronous_transfer_data *transfer,
199										generic_io_vec *vector);
200
201		// Register functions
202inline	void						WriteReg8(uint32 reg, uint8 value);
203inline	void						WriteReg16(uint32 reg, uint16 value);
204inline	void						WriteReg32(uint32 reg, uint32 value);
205inline	uint8						ReadReg8(uint32 reg);
206inline	uint16						ReadReg16(uint32 reg);
207inline	uint32						ReadReg32(uint32 reg);
208
209		uint32						fRegisterBase;
210		pci_info *					fPCIInfo;
211		pci_device_module_info*		fPci;
212		pci_device*					fDevice;
213		Stack *						fStack;
214		uint32						fEnabledInterrupts;
215
216		// Frame list memory
217		area_id						fFrameArea;
218		uint32 *					fFrameList;
219
220		// fFrameBandwidth[n] holds the available bandwidth
221		// of the nth frame in microseconds
222		uint16 *					fFrameBandwidth;
223
224		// fFirstIsochronousTransfer[n] and fLastIsochronousDescriptor[n]
225		// keeps track of the first and last isochronous transfer descriptor
226		// in the nth frame
227		uhci_td **					fFirstIsochronousDescriptor;
228		uhci_td **					fLastIsochronousDescriptor;
229
230		// Queues
231		int32						fQueueCount;
232		Queue **					fQueues;
233
234		// Maintain a linked list of transfers
235		transfer_data *				fFirstTransfer;
236		transfer_data *				fLastTransfer;
237		sem_id						fFinishTransfersSem;
238		thread_id					fFinishThread;
239		bool						fStopThreads;
240		Pipe *						fProcessingPipe;
241
242		transfer_data *				fFreeList;
243		thread_id					fCleanupThread;
244		sem_id						fCleanupSem;
245		int32						fCleanupCount;
246
247		// Maintain a linked list of isochronous transfers
248		isochronous_transfer_data *	fFirstIsochronousTransfer;
249		isochronous_transfer_data *	fLastIsochronousTransfer;
250		sem_id						fFinishIsochronousTransfersSem;
251		thread_id					fFinishIsochronousThread;
252		mutex						fIsochronousLock;
253
254		// Root hub
255		UHCIRootHub *				fRootHub;
256		uint8						fRootHubAddress;
257		uint8						fPortResetChange;
258
259		uint32						fIRQ;
260		bool						fUseMSI;
261};
262
263
264class UHCIRootHub : public Hub {
265public:
266									UHCIRootHub(Object *rootObject,
267										int8 deviceAddress);
268
269static	status_t					ProcessTransfer(UHCI *uhci,
270										Transfer *transfer);
271};
272
273
274#endif
275