1/*
2 * Copyright 2018-2024 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		B Krishnan Iyer, krishnaniyer97@gmail.com
7 *		Adrien Destugues, pulkomandy@pulkomandy.tk
8 *		Ron Ben Aroya, sed4906birdie@gmail.com
9 */
10#include <algorithm>
11#include <new>
12#include <stdio.h>
13#include <string.h>
14
15#include <bus/PCI.h>
16#include <ACPI.h>
17#include "acpi.h"
18
19#include <KernelExport.h>
20
21#include "IOSchedulerSimple.h"
22#include "mmc.h"
23#include "sdhci.h"
24
25
26#define TRACE_SDHCI
27#ifdef TRACE_SDHCI
28#	define TRACE(x...) dprintf("\33[33msdhci:\33[0m " x)
29#else
30#	define TRACE(x...) ;
31#endif
32#define TRACE_ALWAYS(x...)	dprintf("\33[33msdhci:\33[0m " x)
33#define ERROR(x...)			dprintf("\33[33msdhci:\33[0m " x)
34#define CALLED(x...)		TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
35
36
37#define SDHCI_DEVICE_MODULE_NAME "busses/mmc/sdhci/driver_v1"
38#define SDHCI_ACPI_MMC_BUS_MODULE_NAME "busses/mmc/sdhci/acpi/device/v1"
39#define SDHCI_PCI_MMC_BUS_MODULE_NAME "busses/mmc/sdhci/pci/device/v1"
40
41#define SLOT_NUMBER				"device/slot"
42#define BAR_INDEX				"device/bar"
43
44device_manager_info* gDeviceManager;
45device_module_info* gMMCBusController;
46
47static int32
48sdhci_generic_interrupt(void* data)
49{
50	SdhciBus* bus = (SdhciBus*)data;
51	return bus->HandleInterrupt();
52}
53
54
55SdhciBus::SdhciBus(struct registers* registers, uint8_t irq, bool poll)
56	:
57	fRegisters(registers),
58	fIrq(irq),
59	fSemaphore(0)
60{
61	if (irq == 0 || irq == 0xff) {
62		ERROR("IRQ not assigned\n");
63		fStatus = B_BAD_DATA;
64		return;
65	}
66
67	fSemaphore = create_sem(0, "SDHCI interrupts");
68
69	DisableInterrupts();
70
71	fStatus = install_io_interrupt_handler(fIrq,
72		sdhci_generic_interrupt, this, 0);
73
74	if (fStatus != B_OK) {
75		ERROR("can't install interrupt handler\n");
76		return;
77	}
78
79	// First of all, we have to make sure we are in a sane state. The easiest
80	// way is to reset everything.
81	Reset();
82
83	// Turn on the power supply to the card, if there is a card inserted
84	if (PowerOn()) {
85		// Then we configure the clock to the frequency needed for
86		// initialization
87		SetClock(400);
88	}
89
90	// Finally, configure some useful interrupts
91	EnableInterrupts(SDHCI_INT_CMD_CMP | SDHCI_INT_CARD_REM
92		| SDHCI_INT_TRANS_CMP);
93
94	// We want to see the error bits in the status register, but not have an
95	// interrupt trigger on them (we get a "command complete" interrupt on
96	// errors already)
97	fRegisters->interrupt_status_enable |= SDHCI_INT_ERROR
98		| SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | SDHCI_INT_INDEX
99		| SDHCI_INT_BUS_POWER | SDHCI_INT_END_BIT;
100
101	if (poll) {
102		// Spawn a polling thread, as the interrupts won't currently work on ACPI.
103		fWorkerThread = spawn_kernel_thread(_WorkerThread, "SD bus poller",
104			B_NORMAL_PRIORITY, this);
105		resume_thread(fWorkerThread);
106	}
107}
108
109
110SdhciBus::~SdhciBus()
111{
112	DisableInterrupts();
113
114	if (fSemaphore != 0)
115		delete_sem(fSemaphore);
116
117	if (fIrq != 0)
118		remove_io_interrupt_handler(fIrq, sdhci_generic_interrupt, this);
119
120	area_id regs_area = area_for(fRegisters);
121	delete_area(regs_area);
122
123	fStatus = B_SHUTTING_DOWN;
124
125	status_t result;
126	if (fWorkerThread != 0)
127		wait_for_thread(fWorkerThread, &result);
128}
129
130
131void
132SdhciBus::EnableInterrupts(uint32_t mask)
133{
134	fRegisters->interrupt_status_enable |= mask;
135	fRegisters->interrupt_signal_enable |= mask;
136}
137
138
139void
140SdhciBus::DisableInterrupts()
141{
142	fRegisters->interrupt_status_enable = 0;
143	fRegisters->interrupt_signal_enable = 0;
144}
145
146
147// #pragma mark -
148/*
149PartA2, SD Host Controller Simplified Specification, Version 4.20
150��3.7.1.1 The sequence to issue an SD Command
151*/
152status_t
153SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response)
154{
155	TRACE("ExecuteCommand(%d, %x)\n", command, argument);
156
157	// First of all clear the result
158	fCommandResult = 0;
159
160	// Check if it's possible to send a command right now.
161	// It is not possible to send a command as long as the command line is busy.
162	// The spec says we should wait, but we can't do that on kernel side, since
163	// it leaves no chance for the upper layers to handle the problem. So we
164	// just say we're busy and the caller can retry later.
165	// Note that this should normally never happen: the command line is busy
166	// only during command execution, and we don't leave this function with ac
167	// command running.
168	if (fRegisters->present_state.CommandInhibit()) {
169		panic("Command execution impossible, command inhibit\n");
170		return B_BUSY;
171	}
172	if (fRegisters->present_state.DataInhibit()) {
173		panic("Command execution unwise, data inhibit\n");
174		return B_BUSY;
175	}
176
177	uint32_t replyType;
178
179	switch (command) {
180		case SD_GO_IDLE_STATE:
181			replyType = Command::kNoReplyType;
182			break;
183		case SD_ALL_SEND_CID:
184		case SD_SEND_CSD:
185			replyType = Command::kR2Type;
186			break;
187		case SD_SEND_RELATIVE_ADDR:
188			replyType = Command::kR6Type;
189			break;
190		case SD_SELECT_DESELECT_CARD:
191		case SD_ERASE:
192			replyType = Command::kR1bType;
193			break;
194		case SD_SEND_IF_COND:
195			replyType = Command::kR7Type;
196			break;
197		case SD_READ_SINGLE_BLOCK:
198		case SD_READ_MULTIPLE_BLOCKS:
199		case SD_WRITE_SINGLE_BLOCK:
200		case SD_WRITE_MULTIPLE_BLOCKS:
201			replyType = Command::kR1Type | Command::kDataPresent;
202			break;
203		case SD_APP_CMD:
204		case SD_ERASE_WR_BLK_START:
205		case SD_ERASE_WR_BLK_END:
206		case SD_SET_BUS_WIDTH: // SD Application command
207			replyType = Command::kR1Type;
208			break;
209		case SD_SEND_OP_COND: // SD Application command
210			replyType = Command::kR3Type;
211			break;
212		default:
213			ERROR("Unknown command %x\n", command);
214			return B_BAD_DATA;
215	}
216
217	// Check if DATA line is available (if needed)
218	if ((replyType & Command::k32BitResponseCheckBusy) != 0
219		&& command != SD_STOP_TRANSMISSION && command != SD_IO_ABORT) {
220		if (fRegisters->present_state.DataInhibit()) {
221			ERROR("Execution aborted, data inhibit\n");
222			return B_BUSY;
223		}
224	}
225
226	if (fRegisters->present_state.CommandInhibit())
227		panic("Command line busy at start of execute command\n");
228
229	if (replyType == Command::kR1bType)
230		fRegisters->transfer_mode = 0;
231
232	fRegisters->argument = argument;
233	fRegisters->command.SendCommand(command, replyType);
234
235	// Wait for command response to be available ("command complete" interrupt)
236	TRACE("Wait for command complete...");
237	do {
238		//fCommandResult = fRegisters->interrupt_status;
239		acquire_sem(fSemaphore);
240		TRACE("command complete sem acquired, status: %x\n", fCommandResult);
241		TRACE("real status = %x command line busy: %d\n",
242			fRegisters->interrupt_status,
243			fRegisters->present_state.CommandInhibit());
244	} while (fCommandResult == 0);
245
246	TRACE("Command response available\n");
247
248	if (fCommandResult & SDHCI_INT_ERROR) {
249		fRegisters->interrupt_status |= fCommandResult;
250		if (fCommandResult & SDHCI_INT_TIMEOUT) {
251			ERROR("Command execution timed out\n");
252			if (fRegisters->present_state.CommandInhibit()) {
253				TRACE("Command line is still busy, clearing it\n");
254				// Clear the stall
255				fRegisters->software_reset.ResetCommandLine();
256			}
257			return B_TIMED_OUT;
258		}
259		if (fCommandResult & SDHCI_INT_CRC) {
260			ERROR("CRC error\n");
261			return B_BAD_VALUE;
262		}
263		ERROR("Command execution failed %x\n", fCommandResult);
264		// TODO look at errors in interrupt_status register for more details
265		// and return a more appropriate error code
266		return B_ERROR;
267	}
268
269	if (fRegisters->present_state.CommandInhibit()) {
270		TRACE("Command execution failed, card stalled\n");
271		// Clear the stall
272		fRegisters->software_reset.ResetCommandLine();
273		return B_ERROR;
274	}
275
276	switch (replyType & Command::kReplySizeMask) {
277		case Command::k32BitResponse:
278			*response = fRegisters->response[0];
279			break;
280		case Command::k128BitResponse:
281			response[0] = fRegisters->response[0];
282			response[1] = fRegisters->response[1];
283			response[2] = fRegisters->response[2];
284			response[3] = fRegisters->response[3];
285			break;
286
287		default:
288			// No response
289			break;
290	}
291
292	if (replyType == Command::kR1bType
293			&& (fCommandResult & SDHCI_INT_TRANS_CMP) == 0) {
294		// R1b commands may use the data line so we must wait for the
295		// "transfer complete" interrupt here.
296		TRACE("Waiting for data line...\n");
297		do {
298			acquire_sem(fSemaphore);
299		} while (fRegisters->present_state.DataInhibit());
300		TRACE("Dataline is released.\n");
301	}
302
303	ERROR("Command execution %d complete\n", command);
304	return B_OK;
305}
306
307
308status_t
309SdhciBus::InitCheck()
310{
311	return fStatus;
312}
313
314
315void
316SdhciBus::Reset()
317{
318	if (!fRegisters->software_reset.ResetAll())
319		ERROR("SdhciBus::Reset: SoftwareReset timeout\n");
320}
321
322
323void
324SdhciBus::SetClock(int kilohertz)
325{
326	int base_clock = fRegisters->capabilities.BaseClockFrequency();
327	// Try to get as close to 400kHz as possible, but not faster
328	int divider = base_clock * 1000 / kilohertz;
329
330	if (fRegisters->host_controller_version.specVersion <= 1) {
331		// Old controller only support power of two dividers up to 256,
332		// round to next power of two up to 256
333		if (divider > 256)
334			divider = 256;
335
336		divider--;
337		divider |= divider >> 1;
338		divider |= divider >> 2;
339		divider |= divider >> 4;
340		divider++;
341	}
342
343	divider = fRegisters->clock_control.SetDivider(divider);
344
345	// Log the value after possible rounding by SetDivider (only even values
346	// are allowed).
347	TRACE("SDCLK frequency: %dMHz / %d = %dkHz\n", base_clock, divider,
348		base_clock * 1000 / divider);
349
350	// We have set the divider, now we can enable the internal clock.
351	fRegisters->clock_control.EnableInternal();
352
353	// wait until internal clock is stabilized
354	while (!(fRegisters->clock_control.InternalStable()));
355
356	fRegisters->clock_control.EnablePLL();
357	while (!(fRegisters->clock_control.InternalStable()));
358
359	// Finally, route the clock to the SD card
360	fRegisters->clock_control.EnableSD();
361}
362
363
364status_t
365SdhciBus::DoIO(uint8_t command, IOOperation* operation, bool offsetAsSectors)
366{
367	bool isWrite = operation->IsWrite();
368
369	static const uint32 kBlockSize = 512;
370	off_t offset = operation->Offset();
371	generic_size_t length = operation->Length();
372
373	TRACE("%s %" B_PRIu64 " bytes at %" B_PRIdOFF "\n",
374		isWrite ? "Write" : "Read", length, offset);
375
376	// Check that the IO scheduler did its job in following our DMA restrictions
377	// We can start a read only at a sector boundary
378	ASSERT(offset % kBlockSize == 0);
379	// We can only read complete sectors
380	ASSERT(length % kBlockSize == 0);
381
382	const generic_io_vec* vecs = operation->Vecs();
383	generic_size_t vecOffset = 0;
384
385	// FIXME can this be moved to the init function instead?
386	//
387	// For simplicity we use a transfer size equal to the sector size. We could
388	// go up to 2K here if the length to read in each individual vec is a
389	// multiple of 2K, but we have no easy way to know this (we would need to
390	// iterate through the IOOperation vecs and check the size of each of them).
391	// We could also do smaller transfers, but it is not possible to start a
392	// transfer anywhere else than the start of a sector, so it's a lot simpler
393	// to always work in complete sectors. We set the B_DMA_ALIGNMENT device
394	// node property accordingly, making sure that we don't get asked to do
395	// transfers that are not aligned with sectors.
396	//
397	// Additionnally, set SDMA buffer boundary aligment to 512K. This is the
398	// largest possible size. We also set the B_DMA_BOUNDARY property on the
399	// published device node, so that the DMA resource manager knows that it
400	// must respect this boundary. As a result, we will never be asked to
401	// do a transfer that crosses this boundary, and we don't need to handle
402	// the DMA boundary interrupt (the transfer will be split in two at an
403	// upper layer).
404	fRegisters->block_size.ConfigureTransfer(kBlockSize,
405		BlockSize::kDmaBoundary512K);
406	status_t result = B_OK;
407
408	while (length > 0) {
409		size_t toCopy = std::min((generic_size_t)length,
410			vecs->length - vecOffset);
411
412		// If the current vec is empty, we can move to the next
413		if (toCopy == 0) {
414			vecs++;
415			vecOffset = 0;
416			continue;
417		}
418
419		// With SDMA we can only transfer multiples of 1 sector
420		ASSERT(toCopy % kBlockSize == 0);
421
422		fRegisters->system_address = vecs->base + vecOffset;
423		// fRegisters->adma_system_address = fDmaMemory;
424
425		fRegisters->block_count = toCopy / kBlockSize;
426
427		uint16 direction;
428		if (isWrite)
429			direction = TransferMode::kWrite;
430		else
431			direction = TransferMode::kRead;
432		fRegisters->transfer_mode = TransferMode::kMulti | direction
433			| TransferMode::kAutoCmd12Enable
434			| TransferMode::kBlockCountEnable | TransferMode::kDmaEnable;
435
436		uint32_t response;
437		result = ExecuteCommand(command,
438			offset / (offsetAsSectors ? kBlockSize : 1), &response);
439		if (result != B_OK)
440			break;
441
442		// Wait for DMA transfer to complete
443		// In theory we could go on and send other commands as long as they
444		// don't need the DAT lines, but it's overcomplicating things.
445		TRACE("Wait for transfer complete...");
446		//while ((fRegisters->interrupt_status & SDHCI_INT_TRANS_CMP) == 0);
447		acquire_sem(fSemaphore);
448		TRACE("transfer complete OK.\n");
449
450		length -= toCopy;
451		vecOffset += toCopy;
452		offset += toCopy;
453	}
454
455	return result;
456}
457
458
459void
460SdhciBus::SetScanSemaphore(sem_id sem)
461{
462	fScanSemaphore = sem;
463
464	// If there is already a card in, start a scan immediately
465	if (fRegisters->present_state.IsCardInserted())
466		release_sem(fScanSemaphore);
467
468	// We can now enable the card insertion interrupt for next time a card
469	// is inserted
470	EnableInterrupts(SDHCI_INT_CARD_INS);
471}
472
473
474void
475SdhciBus::SetBusWidth(int width)
476{
477	uint8_t widthBits;
478	switch(width) {
479		case 1:
480			widthBits = HostControl::kDataTransfer1Bit;
481			break;
482		case 4:
483			widthBits = HostControl::kDataTransfer4Bit;
484			break;
485		case 8:
486			widthBits = HostControl::kDataTransfer8Bit;
487			break;
488		default:
489			panic("Incorrect bitwidth value");
490			return;
491	}
492	fRegisters->host_control.SetDataTransferWidth(widthBits);
493}
494
495
496bool
497SdhciBus::PowerOn()
498{
499	if (!fRegisters->present_state.IsCardInserted()) {
500		TRACE("Card not inserted, not powering on for now\n");
501		return false;
502	}
503
504	uint8_t supportedVoltages = fRegisters->capabilities.SupportedVoltages();
505	if ((supportedVoltages & Capabilities::k3v3) != 0)
506		fRegisters->power_control.SetVoltage(PowerControl::k3v3);
507	else if ((supportedVoltages & Capabilities::k3v0) != 0)
508		fRegisters->power_control.SetVoltage(PowerControl::k3v0);
509	else if ((supportedVoltages & Capabilities::k1v8) != 0)
510		fRegisters->power_control.SetVoltage(PowerControl::k1v8);
511	else {
512		fRegisters->power_control.PowerOff();
513		ERROR("No voltage is supported\n");
514		return false;
515	}
516
517	return true;
518}
519
520
521void
522SdhciBus::RecoverError()
523{
524	fRegisters->interrupt_signal_enable &= ~(SDHCI_INT_CMD_CMP
525		| SDHCI_INT_TRANS_CMP | SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM);
526
527	if (fRegisters->interrupt_status & 7)
528		fRegisters->software_reset.ResetCommandLine();
529
530	int16_t error_status = fRegisters->interrupt_status;
531	fRegisters->interrupt_status &= ~(error_status);
532}
533
534
535int32
536SdhciBus::HandleInterrupt()
537{
538#if 0
539	// We could use the slot register to quickly see for which slot the
540	// interrupt is. But since we have an interrupt handler call for each slot
541	// anyway, it's just as simple to let each of them scan its own interrupt
542	// status register.
543	if ( !(fRegisters->slot_interrupt_status & (1 << fSlot)) ) {
544		TRACE("interrupt not for me.\n");
545		return B_UNHANDLED_INTERRUPT;
546	}
547#endif
548
549	uint32_t intmask = fRegisters->interrupt_status;
550
551	// Shortcut: exit early if there is no interrupt or if the register is
552	// clearly invalid.
553	if ((intmask == 0) || (intmask == 0xffffffff)) {
554		return B_UNHANDLED_INTERRUPT;
555	}
556
557	TRACE("interrupt function called %x\n", intmask);
558
559	// handling card presence interrupts
560	if ((intmask & SDHCI_INT_CARD_REM) != 0) {
561		// We can get spurious interrupts as the card is inserted or removed,
562		// so check the actual state before acting
563		if (!fRegisters->present_state.IsCardInserted())
564			fRegisters->power_control.PowerOff();
565		else
566			TRACE("Card removed interrupt, but card is inserted\n");
567
568		fRegisters->interrupt_status |= SDHCI_INT_CARD_REM;
569		TRACE("Card removal interrupt handled\n");
570	}
571
572	if ((intmask & SDHCI_INT_CARD_INS) != 0) {
573		// We can get spurious interrupts as the card is inserted or removed,
574		// so check the actual state before acting
575		if (fRegisters->present_state.IsCardInserted()) {
576			if (PowerOn())
577				SetClock(400);
578			release_sem_etc(fScanSemaphore, 1, B_DO_NOT_RESCHEDULE);
579		} else
580			TRACE("Card insertion interrupt, but card is removed\n");
581
582		fRegisters->interrupt_status |= SDHCI_INT_CARD_INS;
583		TRACE("Card presence interrupt handled\n");
584	}
585
586	// handling command interrupt
587	if (intmask & SDHCI_INT_CMD_MASK) {
588		fCommandResult = intmask;
589			// Save the status before clearing so the thread can handle it
590		fRegisters->interrupt_status |= (intmask & SDHCI_INT_CMD_MASK);
591
592		// Notify the thread
593		release_sem_etc(fSemaphore, 1, B_DO_NOT_RESCHEDULE);
594		TRACE("Command complete interrupt handled\n");
595	}
596
597	if (intmask & SDHCI_INT_TRANS_CMP) {
598		fCommandResult = intmask;
599		fRegisters->interrupt_status |= SDHCI_INT_TRANS_CMP;
600		release_sem_etc(fSemaphore, 1, B_DO_NOT_RESCHEDULE);
601		TRACE("Transfer complete interrupt handled\n");
602	}
603
604	// handling bus power interrupt
605	if (intmask & SDHCI_INT_BUS_POWER) {
606		fRegisters->interrupt_status |= SDHCI_INT_BUS_POWER;
607		TRACE("card is consuming too much power\n");
608	}
609
610	// Check that all interrupts have been cleared (we check all the ones we
611	// enabled, so that should always be the case)
612	intmask = fRegisters->interrupt_status;
613	if (intmask != 0) {
614		ERROR("Remaining interrupts at end of handler: %x\n", intmask);
615	}
616
617	return B_HANDLED_INTERRUPT;
618}
619
620status_t
621SdhciBus::_WorkerThread(void* cookie) {
622	SdhciBus* bus = (SdhciBus*)cookie;
623	while (bus->fStatus != B_SHUTTING_DOWN) {
624		uint32_t intmask = bus->fRegisters->interrupt_status;
625		if (intmask & SDHCI_INT_CMD_CMP) {
626			bus->fCommandResult = intmask;
627			bus->fRegisters->interrupt_status |= (intmask & SDHCI_INT_CMD_MASK);
628			release_sem(bus->fSemaphore);
629		}
630		if (intmask & SDHCI_INT_TRANS_CMP) {
631			bus->fCommandResult = intmask;
632			bus->fRegisters->interrupt_status |= SDHCI_INT_TRANS_CMP;
633			release_sem(bus->fSemaphore);
634		}
635		snooze(100);
636	}
637	TRACE("poller thread terminating");
638	return B_OK;
639}
640
641// #pragma mark -
642
643void
644uninit_bus(void* bus_cookie)
645{
646	SdhciBus* bus = (SdhciBus*)bus_cookie;
647	delete bus;
648
649	// FIXME do we need to put() the PCI module here?
650}
651
652
653void
654bus_removed(void* bus_cookie)
655{
656	return;
657}
658
659static status_t
660register_child_devices(void* cookie)
661{
662	CALLED();
663	SdhciDevice* context = (SdhciDevice*)cookie;
664	status_t status = B_OK;
665	const char* bus;
666	device_node* parent = gDeviceManager->get_parent_node(context->fNode);
667	status = gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false);
668	if (status != B_OK) {
669		TRACE("Could not find required attribute device/bus\n");
670		return status;
671	}
672
673	if (strcmp(bus, "pci") == 0)
674		status = register_child_devices_pci(cookie);
675	else if (strcmp(bus, "acpi") == 0)
676		status = register_child_devices_acpi(cookie);
677	else
678		status = B_BAD_VALUE;
679
680	return status;
681}
682
683static status_t
684init_device(device_node* node, void** device_cookie)
685{
686	CALLED();
687
688	SdhciDevice* context = new(std::nothrow)SdhciDevice;
689	if (context == NULL)
690		return B_NO_MEMORY;
691	context->fNode = node;
692	*device_cookie = context;
693
694	status_t status = B_OK;
695	const char* bus;
696	device_node* parent = gDeviceManager->get_parent_node(node);
697	status = gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false);
698	if (status != B_OK) {
699		TRACE("Could not find required attribute device/bus\n");
700		return status;
701	}
702
703	if (strcmp(bus, "pci") == 0)
704		return init_device_pci(node, context);
705
706	return B_OK;
707}
708
709static void
710uninit_device(void* device_cookie)
711{
712	SdhciDevice* context = (SdhciDevice*)device_cookie;
713	device_node* parent = gDeviceManager->get_parent_node(context->fNode);
714
715	const char* bus;
716	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) != B_OK) {
717		TRACE("Could not find required attribute device/bus\n");
718	}
719
720	if (strcmp(bus, "pci") == 0)
721		uninit_device_pci(context, parent);
722
723	gDeviceManager->put_node(parent);
724
725	delete context;
726}
727
728
729static status_t
730register_device(device_node* parent)
731{
732	device_attr attrs[] = {
733		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "SD Host Controller"}},
734		{}
735	};
736
737	return gDeviceManager->register_node(parent, SDHCI_DEVICE_MODULE_NAME,
738		attrs, NULL, NULL);
739}
740
741static float
742supports_device(device_node* parent)
743{
744	const char* bus;
745
746	// make sure parent is either an ACPI or PCI SDHCI device node
747	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)
748		!= B_OK) {
749		TRACE("Could not find required attribute device/bus\n");
750		return -1;
751	}
752
753	if (strcmp(bus, "pci") == 0)
754		return supports_device_pci(parent);
755	else if (strcmp(bus, "acpi") == 0)
756		return supports_device_acpi(parent);
757
758	return 0.0f;
759}
760
761
762module_dependency module_dependencies[] = {
763	{ MMC_BUS_MODULE_NAME, (module_info**)&gMMCBusController},
764	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
765	{}
766};
767
768status_t
769set_clock(void* controller, uint32_t kilohertz)
770{
771	SdhciBus* bus = (SdhciBus*)controller;
772	bus->SetClock(kilohertz);
773	return B_OK;
774}
775
776
777status_t
778execute_command(void* controller, uint8_t command, uint32_t argument,
779	uint32_t* response)
780{
781	SdhciBus* bus = (SdhciBus*)controller;
782	return bus->ExecuteCommand(command, argument, response);
783}
784
785
786status_t
787do_io(void* controller, uint8_t command, IOOperation* operation,
788	bool offsetAsSectors)
789{
790	SdhciBus* bus = (SdhciBus*)controller;
791	return bus->DoIO(command, operation, offsetAsSectors);
792}
793
794
795void
796set_scan_semaphore(void* controller, sem_id sem)
797{
798	SdhciBus* bus = (SdhciBus*)controller;
799	return bus->SetScanSemaphore(sem);
800}
801
802
803void
804set_bus_width(void* controller, int width)
805{
806	SdhciBus* bus = (SdhciBus*)controller;
807	return bus->SetBusWidth(width);
808}
809
810// Root device that binds to the ACPI or PCI bus. It will register an mmc_bus_interface
811// node for each SD slot in the device.
812static driver_module_info sSDHCIDevice = {
813	{
814		SDHCI_DEVICE_MODULE_NAME,
815		0,
816		NULL
817	},
818	supports_device,
819	register_device,
820	init_device,
821	uninit_device,
822	register_child_devices,
823	NULL,	// rescan
824	NULL,	// device removed
825};
826
827
828module_info* modules[] = {
829	(module_info* )&sSDHCIDevice,
830	(module_info* )&gSDHCIPCIDeviceModule,
831	(module_info* )&gSDHCIACPIDeviceModule,
832	NULL
833};
834