⛏️ index : haiku.git

/*
 * Copyright 2004-2011, Haiku Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Michael Lotz <mmlr@mlotz.ch>
 *		Niels S. Reedijk
 *		Salvatore Benedetto <salvatore.benedetto@gmail.com>
 */
#ifndef UHCI_H
#define UHCI_H

#include "usb_private.h"
#include "uhci_hardware.h"
#include <lock.h>

#define UHCI_INTERRUPT_QUEUE				0
#define UHCI_LOW_SPEED_CONTROL_QUEUE		1
#define UHCI_FULL_SPEED_CONTROL_QUEUE		2
#define UHCI_BULK_QUEUE						3
#define UHCI_BANDWIDTH_RECLAMATION_QUEUE	4
#define UHCI_DEBUG_QUEUE					4

struct pci_info;
struct pci_device_module_info;
struct pci_device;
class UHCIRootHub;


class Queue {
public:
									Queue(Stack *stack);
									~Queue();

		bool						Lock();
		void						Unlock();

		status_t					InitCheck();

		status_t					LinkTo(Queue *other);
		status_t					TerminateByStrayDescriptor();

		status_t					AppendTransfer(uhci_qh *transfer,
										bool lock = true);
		status_t					RemoveTransfer(uhci_qh *transfer,
										bool lock = true);

		uint32						PhysicalAddress();

		void						PrintToStream();

		usb_id						USBID() { return 0; };
		const char *				TypeName() { return "uhci"; };

private:
		status_t					fStatus;
		Stack *						fStack;
		uhci_qh *					fQueueHead;
		uhci_td *					fStrayDescriptor;
		uhci_qh *					fQueueTop;
		mutex						fLock;
};


typedef struct transfer_data {
	Transfer *		transfer;
	Queue *			queue;
	uhci_qh *		transfer_queue;
	uhci_td *		first_descriptor;
	uhci_td *		data_descriptor;
	bool			incoming;
	bool			canceled;
	uint16			free_after_frame;
	transfer_data *	link;
} transfer_data;


// This structure is used to create a list of
// descriptors per isochronous transfer
typedef struct isochronous_transfer_data {
	Transfer *					transfer;
	// The next field is used to keep track
	// of every isochronous descriptor as they are NOT
	// linked to each other in a queue like in every other
	// transfer type
	uhci_td **					descriptors;
	uint16						last_to_process;
	bool						incoming;
	bool						is_active;
	isochronous_transfer_data *	link;
} isochronous_transfer_data;


class UHCI : public BusManager {
public:
									UHCI(pci_info *info, pci_device_module_info* pci,
										pci_device* device, Stack *stack, device_node* node);
									~UHCI();

		status_t					Start();
virtual	status_t					SubmitTransfer(Transfer *transfer);

virtual	status_t					StartDebugTransfer(Transfer *transfer);
virtual	status_t					CheckDebugTransfer(Transfer *transfer);
virtual	void						CancelDebugTransfer(Transfer *transfer);

virtual	status_t					CancelQueuedTransfers(Pipe *pipe, bool force);
		status_t					CancelQueuedIsochronousTransfers(Pipe *pipe, bool force);
		status_t					SubmitRequest(Transfer *transfer);
		status_t					SubmitIsochronous(Transfer *transfer);

		// Port operations
		status_t					GetPortStatus(uint8 index, usb_port_status *status);
		status_t					SetPortFeature(uint8 index, uint16 feature);
		status_t					ClearPortFeature(uint8 index, uint16 feature);

		status_t					ResetPort(uint8 index);

virtual	const char *				TypeName() const { return "uhci"; };

private:
		// Controller resets
		void						GlobalReset();
		status_t					ControllerReset();

		// Interrupt functions
static	int32						InterruptHandler(void *data);
		int32						Interrupt();

		// Transfer functions
		status_t					AddPendingTransfer(Transfer *transfer,
										Queue *queue,
										uhci_qh *transferQueue,
										uhci_td *firstDescriptor,
										uhci_td *dataDescriptor,
										bool directionIn);
		status_t					AddPendingIsochronousTransfer(
										Transfer *transfer,
										uhci_td **isoRequest,
										bool directionIn);

static	int32						FinishThread(void *data);
		void						FinishTransfers();

		void						AddToFreeList(transfer_data *transfer);
static	int32						CleanupThread(void *data);
		void						Cleanup();

		status_t					CreateFilledTransfer(Transfer *transfer,
										uhci_td **_firstDescriptor,
										uhci_qh **_transferQueue);

		// Isochronous transfer functions
static int32						FinishIsochronousThread(void *data);
		void						FinishIsochronousTransfers();
		isochronous_transfer_data *	FindIsochronousTransfer(uhci_td *descriptor);

		status_t					LinkIsochronousDescriptor(
										uhci_td *descriptor,
										uint16 frame);
		uhci_td *					UnlinkIsochronousDescriptor(uint16 frame);

		// Transfer queue functions
		uhci_qh *					CreateTransferQueue(uhci_td *descriptor);
		void						FreeTransferQueue(uhci_qh *queueHead);

		bool						LockIsochronous();
		void						UnlockIsochronous();

		// Descriptor functions
		uhci_td *					CreateDescriptor(Pipe *pipe,
										uint8 direction,
										size_t bufferSizeToAllocate);
		status_t					CreateDescriptorChain(Pipe *pipe,
										uhci_td **firstDescriptor,
										uhci_td **lastDescriptor,
										uint8 direction,
										size_t bufferSizeToAllocate);

		void						FreeDescriptor(uhci_td *descriptor);
		void						FreeDescriptorChain(uhci_td *topDescriptor);

		void						LinkDescriptors(uhci_td *first,
										uhci_td *second);

		size_t						WriteDescriptorChain(uhci_td *topDescriptor,
										generic_io_vec *vector, size_t vectorCount, bool physical);
		size_t						ReadDescriptorChain(uhci_td *topDescriptor,
										generic_io_vec *vector, size_t vectorCount, bool physical,
										uint8 *lastDataToggle);
		size_t						ReadActualLength(uhci_td *topDescriptor,
										uint8 *lastDataToggle);
		void						WriteIsochronousDescriptorChain(
										uhci_td **isoRequest,
										uint32 packetCount,
										generic_io_vec *vector);
		void						ReadIsochronousDescriptorChain(
										isochronous_transfer_data *transfer,
										generic_io_vec *vector);

		// Register functions
inline	void						WriteReg8(uint32 reg, uint8 value);
inline	void						WriteReg16(uint32 reg, uint16 value);
inline	void						WriteReg32(uint32 reg, uint32 value);
inline	uint8						ReadReg8(uint32 reg);
inline	uint16						ReadReg16(uint32 reg);
inline	uint32						ReadReg32(uint32 reg);

		uint32						fRegisterBase;
		pci_info *					fPCIInfo;
		pci_device_module_info*		fPci;
		pci_device*					fDevice;
		Stack *						fStack;
		uint32						fEnabledInterrupts;

		// Frame list memory
		area_id						fFrameArea;
		uint32 *					fFrameList;

		// fFrameBandwidth[n] holds the available bandwidth
		// of the nth frame in microseconds
		uint16 *					fFrameBandwidth;

		// fFirstIsochronousTransfer[n] and fLastIsochronousDescriptor[n]
		// keeps track of the first and last isochronous transfer descriptor
		// in the nth frame
		uhci_td **					fFirstIsochronousDescriptor;
		uhci_td **					fLastIsochronousDescriptor;

		// Queues
		int32						fQueueCount;
		Queue **					fQueues;

		// Maintain a linked list of transfers
		transfer_data *				fFirstTransfer;
		transfer_data *				fLastTransfer;
		sem_id						fFinishTransfersSem;
		thread_id					fFinishThread;
		bool						fStopThreads;
		Pipe *						fProcessingPipe;

		transfer_data *				fFreeList;
		thread_id					fCleanupThread;
		sem_id						fCleanupSem;
		int32						fCleanupCount;

		// Maintain a linked list of isochronous transfers
		isochronous_transfer_data *	fFirstIsochronousTransfer;
		isochronous_transfer_data *	fLastIsochronousTransfer;
		sem_id						fFinishIsochronousTransfersSem;
		thread_id					fFinishIsochronousThread;
		mutex						fIsochronousLock;

		// Root hub
		UHCIRootHub *				fRootHub;
		uint8						fRootHubAddress;
		uint8						fPortResetChange;

		uint32						fIRQ;
		bool						fUseMSI;
};


class UHCIRootHub : public Hub {
public:
									UHCIRootHub(Object *rootObject,
										int8 deviceAddress);

static	status_t					ProcessTransfer(UHCI *uhci,
										Transfer *transfer);
};


#endif