summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/includes/xbox_usb.h
blob: 35f0d7782e731b725510bb48db6957ab17f5dd36 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
// license:BSD-3-Clause
// copyright-holders:Samuele Zannoli
#ifndef MAME_INCLUDES_XBOX_USB_H
#define MAME_INCLUDES_XBOX_USB_H

#pragma once

#include <forward_list>

struct OHCIEndpointDescriptor {
	int mps; // MaximumPacketSize
	int f; // Format
	int k; // sKip
	int s; // Speed
	int d; // Direction
	int en; // EndpointNumber
	int fa; // FunctionAddress
	uint32_t tailp; // TDQueueTailPointer
	uint32_t headp; // TDQueueHeadPointer
	uint32_t nexted; // NextED
	int c; // toggleCarry
	int h; // Halted
	uint32_t word0;
};

struct OHCITransferDescriptor {
	int cc; // ConditionCode
	int ec; // ErrorCount
	int t; // DataToggle
	int di; // DelayInterrupt
	int dp; // Direction/PID
	int r; // bufferRounding
	uint32_t cbp; // CurrentBufferPointer
	uint32_t nexttd; // NextTD
	uint32_t be; // BufferEnd
	uint32_t word0;
};

struct OHCIIsochronousTransferDescriptor {
	int cc; // ConditionCode
	int fc; // FrameCount
	int di; // DelayInterrupt
	int sf; // StartingFrame
	uint32_t bp0; // BufferPage0
	uint32_t nexttd; // NextTD
	uint32_t be; // BufferEnd
	uint32_t offset[8]; // Offset/PacketStatusWord
	uint32_t word0;
	uint32_t word1;
};

enum OHCIRegisters {
	HcRevision=0,
	HcControl,
	HcCommandStatus,
	HcInterruptStatus,
	HcInterruptEnable,
	HcInterruptDisable,
	HcHCCA,
	HcPeriodCurrentED,
	HcControlHeadED,
	HcControlCurrentED,
	HcBulkHeadED,
	HcBulkCurrentED,
	HcDoneHead,
	HcFmInterval,
	HcFmRemaining,
	HcFmNumber,
	HcPeriodicStart,
	HcLSThreshold,
	HcRhDescriptorA,
	HcRhDescriptorB,
	HcRhStatus,
	HcRhPortStatus1
};

enum HcControlBits
{
	CBSR = 3 << 0, // ControlBulkServiceRatio
	PLE = 1 << 2, // PeriodicListEnable
	IE = 1 << 3, // IsochronousEnable
	CLE = 1 << 4, // ControlListEnable
	BLE = 1 << 5, // BulkListEnable
	HCFS = 3 << 6, // HostControllerFunctionalState
	IR = 1 << 8, // InterruptRouting
	RWC = 1 << 9, // RemoteWakeupConnected
	RWE = 1 << 10 // RemoteWakeupEnable
};

enum HcCommandStatusBits
{
	HCR = 1 << 0, // HostControllerReset
	CLF = 1 << 1, // ControlListFilled
	BLF = 1 << 2, // BulkListFilled
	OCR = 1 << 3, // OwnershipChangeRequest
	SOC = 3 << 16 // SchedulingOverrunCount
};

enum HcInterruptEnableBits
{
	SO = 1 << 0, // SchedulingOverrun
	WDH = 1 << 1, // WritebackDoneHead
	SF = 1 << 2, // StartofFrame
	RD = 1 << 3, // ResumeDetected
	UE = 1 << 4, // UnrecoverableError
	FNO = 1 << 5, // FrameNumberOverflow
	RHSC = 1 << 6, // RootHubStatusChange
	OC = 1 << 30, // OwnershipChange
	MIE = 1 << 31, // MasterInterruptEnable
};


enum HcRhDescriptorABits
{
	NDP = 0xff << 0, // NumberDownstreamPorts
	PSM = 1 << 8, // PowerSwitchingMode
	NPS = 1 << 9, // NoPowerSwitching
	DT = 1 << 10, // DeviceType
	OCPM = 1 << 11, // OverCurrentProtectionMode
	NOCPM = 1 << 12, // NoOverCurrentProtection
	POTPGT = 0xff << 24 // PowerOnToPowerGoodTime
};

enum HcRhDescriptorBBits
{
	DR = 0xffff << 0, // DeviceRemovable
	PPCM = 0xffff << 16 // PortPowerControlMask
};

enum HcRhStatusBits
{
	LPS = 1 << 0, // LocalPowerStatus
	OCI = 1 << 1, // OverCurrentIndicator
	DRWE = 1 << 15, // DeviceRemoteWakeupEnable
	LPSC = 1 << 16, // LocalPowerStatusChange
	OCIC = 1 << 17, // OverCurrentIndicatorChange
	CRWE = 1 << 31, // ClearRemoteWakeupEnable
};

enum HcRhPortStatusBits
{
	CCS = 1 << 0, // CurrentConnectStatus
	PES = 1 << 1, // PortEnableStatus
	PSS = 1 << 2, // PortSuspendStatus
	POCI = 1 << 3, // PortOverCurrentIndicator
	PRS = 1 << 4, // PortResetStatus
	PPS = 1 << 8, // PortPowerStatus
	LSDA = 1 << 9, // LowSpeedDeviceAttached
	CSC = 1 << 16, // ConnectStatusChange
	PESC = 1 << 17, // PortEnableStatusChange
	PSSC = 1 << 18, // PortSuspendStatusChange
	POCIC = 1 << 19, // PortOverCurrentIndicatorChange
	PRSC = 1 << 20 // PortResetStatusChange
};

enum OHCIHostControllerFunctionalState {
	UsbReset=0,
	UsbResume,
	UsbOperational,
	UsbSuspend
};

enum OHCIInterrupt {
	SchedulingOverrun=1,
	WritebackDoneHead=2,
	StartofFrame=4,
	ResumeDetected=8,
	UnrecoverableError=16,
	FrameNumberOverflow=32,
	RootHubStatusChange=64,
	OwnershipChange=0x40000000,
	MasterInterruptEnable=0x80000000
};

enum OHCICompletionCode {
	NoError=0,
	CRC,
	BitStuffing,
	DataToggleMismatch,
	Stall,
	DeviceNotResponding,
	PIDCheckFailure,
	UnexpectedPID,
	DataOverrun,
	DataUnderrun,
	BufferOverrun=12,
	BufferUnderrun,
	NotAccessed=14
};

struct USBSetupPacket {
	uint8_t bmRequestType;
	uint8_t bRequest;
	uint16_t wValue;
	uint16_t wIndex;
	uint16_t wLength;
};

struct USBStandardDeviceDescriptor {
	uint8_t bLength;
	uint8_t bDescriptorType;
	uint16_t bcdUSB;
	uint8_t bDeviceClass;
	uint8_t bDeviceSubClass;
	uint8_t bDeviceProtocol;
	uint8_t bMaxPacketSize0;
	uint16_t idVendor;
	uint16_t idProduct;
	uint16_t bcdDevice;
	uint8_t iManufacturer;
	uint8_t iProduct;
	uint8_t iSerialNumber;
	uint8_t bNumConfigurations;
};

struct USBStandardConfigurationDescriptor {
	uint8_t bLength;
	uint8_t bDescriptorType;
	uint16_t wTotalLength;
	uint8_t bNumInterfaces;
	uint8_t bConfigurationValue;
	uint8_t iConfiguration;
	uint8_t bmAttributes;
	uint8_t MaxPower;
};

struct USBStandardInterfaceDescriptor {
	uint8_t bLength;
	uint8_t bDescriptorType;
	uint8_t bInterfaceNumber;
	uint8_t bAlternateSetting;
	uint8_t bNumEndpoints;
	uint8_t bInterfaceClass;
	uint8_t bInterfaceSubClass;
	uint8_t bInterfaceProtocol;
	uint8_t iInterface;
};

struct USBStandardEndpointDescriptor {
	uint8_t bLength;
	uint8_t bDescriptorType;
	uint8_t bEndpointAddress;
	uint8_t bmAttributes;
	uint16_t wMaxPacketSize;
	uint8_t bInterval;
};

enum USBPid {
	SetupPid=0,
	OutPid,
	InPid
};

enum USBRequestCode {
	GET_STATUS=0,
	CLEAR_FEATURE=1,
	SET_FEATURE=3,
	SET_ADDRESS=5,
	GET_DESCRIPTOR=6,
	SET_DESCRIPTOR=7,
	GET_CONFIGURATION=8,
	SET_CONFIGURATION=9,
	GET_INTERFACE=10,
	SET_INTERFACE=11,
	SYNCH_FRAME=12
};

enum USBDescriptorType {
	DEVICE=1,
	CONFIGURATION=2,
	STRING=3,
	INTERFACE=4,
	ENDPOINT=5
};

enum USBRequestType
{
	StandardType=0,
	ClassType,
	VendorType,
	ReservedType
};

enum USBRequestRecipient
{
	DeviceRecipient=0,
	InterfaceRecipient,
	EndpointRecipient,
	OtherRecipient
};

enum USBDeviceState
{
	DefaultState,
	AddressState,
	ConfiguredState
};

enum USBControlDirection
{
	HostToDevice=0,
	DeviceToHost=1
};

enum USBEndpointType
{
	ControlEndpoint=0,
	IsochronousEndpoint,
	BulkEndpoint,
	InterruptEndpoint
};

struct usb_device_string
{
	uint8_t *position;
	int size;
};

struct usb_device_interfac_alternate
{
	uint8_t *position;
	int size;
	USBStandardInterfaceDescriptor interface_descriptor;
	std::forward_list<USBStandardEndpointDescriptor> endpoint_descriptors;
};

struct usb_device_interfac
{
	uint8_t *position;
	int size;
	std::forward_list<usb_device_interfac_alternate> alternate_settings;
	int selected_alternate;
};

struct usb_device_configuration
{
	USBStandardConfigurationDescriptor configuration_descriptor;
	uint8_t *position;
	int size;
	std::forward_list<usb_device_interfac> interfaces;
};

/*
 * OHCI Usb Controller
 */

class device_usb_ohci_function_interface; // forward declaration

class ohci_usb_controller
{
public:
	ohci_usb_controller();
	~ohci_usb_controller() {}
	void usb_ohci_plug(int port, device_usb_ohci_function_interface *function);
	void usb_ohci_device_address_changed(int old_address, int new_address);
	void set_cpu(cpu_device *cpu) { m_maincpu = cpu; }
	void set_timer(emu_timer *timer) { ohcist.timer = timer; }
	void set_irq_callback(std::function<void(int state)> callback) { irq_callback = callback; }

	void start();
	void reset();
	void timer(emu_timer &timer, device_timer_id id, int param, void *ptr);

	DECLARE_READ32_MEMBER(read);
	DECLARE_WRITE32_MEMBER(write);

private:
	void usb_ohci_interrupts();
	void usb_ohci_read_endpoint_descriptor(uint32_t address);
	void usb_ohci_writeback_endpoint_descriptor(uint32_t address);
	void usb_ohci_read_transfer_descriptor(uint32_t address);
	void usb_ohci_writeback_transfer_descriptor(uint32_t address);
	void usb_ohci_read_isochronous_transfer_descriptor(uint32_t address);
	void usb_ohci_writeback_isochronous_transfer_descriptor(uint32_t address);
	std::function<void (int state)> irq_callback;
	cpu_device *m_maincpu;
	struct {
		uint32_t hc_regs[256];
		struct {
			device_usb_ohci_function_interface *function;
			int address;
			int delay;
		} ports[4 + 1];
		struct
		{
			device_usb_ohci_function_interface *function;
			int port;
		} address[256];
		emu_timer *timer;
		int state;
		uint32_t framenumber;
		uint32_t nextinterupted;
		uint32_t nextbulked;
		int interruptbulkratio;
		int writebackdonehadcounter;
		address_space *space;
		uint8_t buffer[1024];
		OHCIEndpointDescriptor endpoint_descriptor;
		OHCITransferDescriptor transfer_descriptor;
		OHCIIsochronousTransferDescriptor isochronous_transfer_descriptor;
	} ohcist;
};

/*
 * Base class for usb devices
 */

class device_usb_ohci_function_interface : public device_interface {
public:
	virtual void initialize();
	virtual void execute_reset();
	virtual void execute_connect() {}
	virtual void execute_disconnect() {}
	void set_bus_manager(ohci_usb_controller *usb_bus_manager);
	int execute_transfer(int endpoint, int pid, uint8_t *buffer, int size);
protected:
	device_usb_ohci_function_interface(const machine_config &config, device_t &device);
	virtual int handle_nonstandard_request(int endpoint, USBSetupPacket *setup) { return -1; }
	virtual int handle_get_status_request(int endpoint, USBSetupPacket *setup) { return 0; }
	virtual int handle_clear_feature_request(int endpoint, USBSetupPacket *setup) { return 0; }
	virtual int handle_set_feature_request(int endpoint, USBSetupPacket *setup) { return 0; }
	virtual int handle_set_descriptor_request(int endpoint, USBSetupPacket *setup) { return 0; }
	virtual int handle_synch_frame_request(int endpoint, USBSetupPacket *setup) { return 0; }
	virtual void handle_status_stage(int endpoint) { return; }
	virtual int handle_bulk_pid(int endpoint, int pid, uint8_t *buffer, int size) { return 0; }
	virtual int handle_interrupt_pid(int endpoint, int pid, uint8_t *buffer, int size) { return 0; }
	virtual int handle_isochronous_pid(int endpoint, int pid, uint8_t *buffer, int size) { return 0; }

	void add_device_descriptor(const USBStandardDeviceDescriptor &descriptor);
	void add_configuration_descriptor(const USBStandardConfigurationDescriptor &descriptor);
	void add_interface_descriptor(const USBStandardInterfaceDescriptor &descriptor);
	void add_endpoint_descriptor(const USBStandardEndpointDescriptor &descriptor);
	void add_string_descriptor(const uint8_t *descriptor);
	void select_configuration(int index);
	void select_alternate(int interfacei, int index);
	int find_alternate(int interfacei);
	uint8_t *position_device_descriptor(int &size);
	uint8_t *position_configuration_descriptor(int index, int &size);
	uint8_t *position_string_descriptor(int index, int &size);
	ohci_usb_controller *busmanager;
	struct {
		int type;
		int controldirection;
		int controltype;
		int controlrecipient;
		int remain;
		uint8_t *position;
		uint8_t buffer[128];
	} endpoints[256];
	int state;
	bool settingaddress;
	int newaddress;
	int address;
	int configurationvalue;
	std::unique_ptr<uint8_t []> descriptors;
	int descriptors_pos;
	bool wantstatuscallback;
	USBStandardDeviceDescriptor device_descriptor;
	std::forward_list<usb_device_configuration> configurations;
	std::forward_list<usb_device_string> device_strings;
	usb_device_configuration *latest_configuration;
	usb_device_interfac_alternate *latest_alternate;
	usb_device_configuration *selected_configuration;
};

/*
 * Usb port connector
 */

class ohci_usb_connector : public device_t, public device_single_card_slot_interface<device_usb_ohci_function_interface>
{
public:
	template <typename T>
	ohci_usb_connector(const machine_config &mconfig, const char *tag, device_t *owner, T &&opts, const char *dflt, bool fixed)
		: ohci_usb_connector(mconfig, tag, owner, 0)
	{
		option_reset();
		opts(*this);
		set_default_option(dflt);
		set_fixed(fixed);
	}

	ohci_usb_connector(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
	virtual ~ohci_usb_connector();

protected:
	virtual void device_start() override;
};

DECLARE_DEVICE_TYPE(OHCI_USB_CONNECTOR, ohci_usb_connector)

/*
 * Game controller usb device
 */

DECLARE_DEVICE_TYPE(OHCI_GAME_CONTROLLER, ohci_game_controller_device)

class ohci_game_controller_device : public device_t, public device_usb_ohci_function_interface
{
public:
	ohci_game_controller_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
	void initialize() override;
	int handle_nonstandard_request(int endpoint, USBSetupPacket *setup) override;
	int handle_interrupt_pid(int endpoint, int pid, uint8_t *buffer, int size) override;

protected:
	virtual void device_start() override;
	virtual ioport_constructor device_input_ports() const override;
private:
	static const USBStandardDeviceDescriptor devdesc;
	static const USBStandardConfigurationDescriptor condesc;
	static const USBStandardInterfaceDescriptor intdesc;
	static const USBStandardEndpointDescriptor enddesc82;
	static const USBStandardEndpointDescriptor enddesc02;
	required_ioport m_ThumbstickLh; // left analog thumbstick horizontal movement
	required_ioport m_ThumbstickLv; // left analog thumbstick vertical movement
	required_ioport m_ThumbstickRh; // right analog thumbstick horizontal movement
	required_ioport m_ThumbstickRv; // right analog thumbstick vertical movement
	required_ioport m_DPad; // pressure sensitive directional pad
	required_ioport m_TriggerL; // analog trigger
	required_ioport m_TriggerR; // analog trigger
	required_ioport m_Buttons; // digital buttons
	required_ioport m_AGreen; // analog button
	required_ioport m_BRed; // analog button
	required_ioport m_XBlue; // analog button
	required_ioport m_YYellow; // analog button
	required_ioport m_Black; // analog button
	required_ioport m_White; // analog button
};

#endif // MAME_INCLUDES_XBOX_USB_H