xref: /haiku/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp (revision 8c78892580f132d10e624aef96f835df8d94bf19)
1 /*
2  * Copyright 2018-2020 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  */
8 #include <new>
9 #include <stdio.h>
10 #include <string.h>
11 
12 #include <bus/PCI.h>
13 #include <PCI_x86.h>
14 
15 #include <KernelExport.h>
16 
17 #include "mmc.h"
18 #include "sdhci_pci.h"
19 
20 
21 #define TRACE_SDHCI
22 #ifdef TRACE_SDHCI
23 #	define TRACE(x...) dprintf("\33[33msdhci_pci:\33[0m " x)
24 #else
25 #	define TRACE(x...) ;
26 #endif
27 #define TRACE_ALWAYS(x...)	dprintf("\33[33msdhci_pci:\33[0m " x)
28 #define ERROR(x...)			dprintf("\33[33msdhci_pci:\33[0m " x)
29 #define CALLED(x...)		TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
30 
31 
32 #define SDHCI_PCI_DEVICE_MODULE_NAME "busses/mmc/sdhci_pci/driver_v1"
33 #define SDHCI_PCI_MMC_BUS_MODULE_NAME "busses/mmc/sdhci_pci/device/v1"
34 
35 #define SLOTS_COUNT				"device/slots_count"
36 #define SLOT_NUMBER				"device/slot"
37 #define BAR_INDEX				"device/bar"
38 
39 
40 class SdhciBus {
41 	public:
42 							SdhciBus(struct registers* registers, uint8_t irq);
43 							~SdhciBus();
44 
45 		void				EnableInterrupts(uint32_t mask);
46 		status_t			ExecuteCommand(uint8_t command, uint32_t argument,
47 								uint32_t* response);
48 		int32				HandleInterrupt();
49 		status_t			InitCheck();
50 		void				Reset();
51 		void				SetClock(int kilohertz);
52 
53 	private:
54 		void				DumpRegisters(uint8_t slot);
55 		bool				PowerOn();
56 		void				RecoverError();
57 
58 	private:
59 		struct registers*	fRegisters;
60 		uint32_t			fCommandResult;
61 		uint8_t				fIrq;
62 		sem_id				fSemaphore;
63 		status_t			fStatus;
64 };
65 
66 
67 device_manager_info* gDeviceManager;
68 device_module_info* gMMCBusController;
69 static pci_x86_module_info* sPCIx86Module;
70 
71 
72 static int32
73 sdhci_generic_interrupt(void* data)
74 {
75 	SdhciBus* bus = (SdhciBus*)data;
76 	return bus->HandleInterrupt();
77 }
78 
79 
80 SdhciBus::SdhciBus(struct registers* registers, uint8_t irq)
81 	:
82 	fRegisters(registers),
83 	fIrq(irq),
84 	fSemaphore(0)
85 {
86 	if (irq == 0 || irq == 0xff) {
87 		ERROR("PCI IRQ not assigned\n");
88 		fStatus = B_BAD_DATA;
89 		return;
90 	}
91 
92 	fSemaphore = create_sem(0, "SDHCI interrupts");
93 
94 	fStatus = install_io_interrupt_handler(fIrq,
95 		sdhci_generic_interrupt, this, 0);
96 
97 	if (fStatus != B_OK) {
98 		ERROR("can't install interrupt handler\n");
99 		return;
100 	}
101 
102 	// First of all, we have to make sure we are in a sane state. The easiest
103 	// way is to reset everything.
104 	Reset();
105 
106 	// Then we configure the clock to the frequency needed for initialization
107 	SetClock(400);
108 
109 	// And we turn on the power supply to the card
110 	// FIXME maybe this should only be done when a card is inserted?
111 	if (!PowerOn()) {
112 		ERROR("Failed to power on the card\n");
113 		fStatus = B_NO_INIT;
114 		return;
115 	}
116 
117 	// FIXME do we need all these? Wouldn't card insertion/removal and command
118 	// completion be enough?
119 	EnableInterrupts(SDHCI_INT_CMD_CMP
120 		| SDHCI_INT_TRANS_CMP | SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM
121 		| SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | SDHCI_INT_INDEX
122 		| SDHCI_INT_BUS_POWER | SDHCI_INT_END_BIT);
123 
124 	fRegisters->interrupt_status_enable |= SDHCI_INT_ERROR;
125 }
126 
127 
128 SdhciBus::~SdhciBus()
129 {
130 	if (fSemaphore != 0)
131 		delete_sem(fSemaphore);
132 
133 	EnableInterrupts(0);
134 	if (fIrq != 0)
135 		remove_io_interrupt_handler(fIrq, sdhci_generic_interrupt, this);
136 
137 	area_id regs_area = area_for(fRegisters);
138 	delete_area(regs_area);
139 }
140 
141 
142 void
143 SdhciBus::DumpRegisters(uint8_t slot)
144 {
145 #ifdef TRACE_SDHCI
146 	TRACE("Register values for slot %d:\n", slot);
147 	TRACE("system_address: %d\n", fRegisters->system_address);
148 	TRACE("%d blocks of size %d\n", fRegisters->block_count,
149 		fRegisters->block_size);
150 	TRACE("argument: %x\n", fRegisters->argument);
151 	TRACE("transfer_mode: %d\n", fRegisters->transfer_mode);
152 	TRACE("command: %x\n", fRegisters->command.Bits());
153 	TRACE("response:");
154 	for (int i = 0; i < 4; i++)
155 		dprintf(" %d", fRegisters->response[i]);
156 	dprintf("\n");
157 	TRACE("buffer_data_port: %d\n", fRegisters->buffer_data_port);
158 	TRACE("present_state: %x\n", fRegisters->present_state.Bits());
159 	TRACE("power_control: %d\n", fRegisters->power_control.Bits());
160 	TRACE("host_control: %d\n", fRegisters->host_control);
161 	TRACE("wakeup_control: %d\n", fRegisters->wakeup_control);
162 	TRACE("block_gap_control: %d\n", fRegisters->block_gap_control);
163 	TRACE("clock_control: %x\n", fRegisters->clock_control.Bits());
164 	TRACE("software_reset: %d\n", fRegisters->software_reset.Bits());
165 	TRACE("timeout_control: %d\n", fRegisters->timeout_control);
166 	TRACE("interrupt_status: %x enable: %x signal: %x\n",
167 		fRegisters->interrupt_status, fRegisters->interrupt_status_enable,
168 		fRegisters->interrupt_signal_enable);
169 	TRACE("auto_cmd12_error_status: %d\n", fRegisters->auto_cmd12_error_status);
170 	TRACE("capabilities: %lld\n", fRegisters->capabilities.Bits());
171 	TRACE("max_current_capabilities: %lld\n",
172 		fRegisters->max_current_capabilities);
173 	TRACE("slot_interrupt_status: %d\n", fRegisters->slot_interrupt_status);
174 	TRACE("host_controller_version spec %x vendor %x\n",
175 		fRegisters->host_controller_version.specVersion,
176 		fRegisters->host_controller_version.vendorVersion);
177 #endif
178 }
179 
180 
181 void
182 SdhciBus::EnableInterrupts(uint32_t mask)
183 {
184 	fRegisters->interrupt_status_enable = mask;
185 	fRegisters->interrupt_signal_enable = mask;
186 }
187 
188 
189 status_t
190 SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response)
191 {
192 	TRACE("ExecuteCommand(%d, %x)\n", command, argument);
193 	if (fRegisters->present_state.CommandInhibit()) {
194 		ERROR("Execution aborted, command inhibit\n");
195 		return B_BUSY;
196 	}
197 
198 	fRegisters->argument = argument;
199 
200 	uint32_t replyType;
201 
202 	switch(command) {
203 		case 0:
204 			replyType = Command::kNoReplyType;
205 			break;
206 		case 55:
207 			replyType = Command::kR1Type;
208 			break;
209 		case 2:
210 		case 9:
211 			replyType = Command::kR2Type;
212 			break;
213 		case 41: // ACMD
214 			replyType = Command::kR3Type;
215 			break;
216 		case 3:
217 			replyType = Command::kR6Type;
218 			break;
219 		case 8:
220 			replyType = Command::kR7Type;
221 			break;
222 		default:
223 			ERROR("Unknown command\n");
224 			return B_BAD_DATA;
225 	}
226 
227 	fRegisters->command.SendCommand(command, replyType);
228 	acquire_sem(fSemaphore);
229 
230 	if (fCommandResult & SDHCI_INT_ERROR) {
231 		fRegisters->interrupt_status |= fCommandResult;
232 		if (fCommandResult & SDHCI_INT_TIMEOUT) {
233 			ERROR("Command execution timed out\n");
234 			return B_TIMED_OUT;
235 		}
236 		if (fCommandResult & SDHCI_INT_CRC) {
237 			ERROR("CRC error\n");
238 			return B_BAD_VALUE;
239 		}
240 		ERROR("Command execution failed %x\n", fCommandResult);
241 		// TODO look at errors in interrupt_status register for more details
242 		// and return a more appropriate error code
243 		return B_ERROR;
244 	}
245 
246 	if (fRegisters->present_state.CommandInhibit()) {
247 		TRACE("Command execution failed, card stalled\n");
248 		// Clear the stall
249 		fRegisters->software_reset.ResetCommandLine();
250 		return B_ERROR;
251 	}
252 
253 	switch (replyType & Command::kReplySizeMask) {
254 		case Command::k32BitResponse:
255 			*response = fRegisters->response[0];
256 			break;
257 		case Command::k128BitResponse:
258 			response[0] = fRegisters->response[0];
259 			response[1] = fRegisters->response[1];
260 			response[2] = fRegisters->response[2];
261 			response[3] = fRegisters->response[3];
262 			break;
263 		default:
264 			// No response
265 			break;
266 	}
267 
268 	ERROR("Command execution complete\n");
269 	return B_OK;
270 }
271 
272 
273 status_t
274 SdhciBus::InitCheck()
275 {
276 	return fStatus;
277 }
278 
279 
280 void
281 SdhciBus::Reset()
282 {
283 	fRegisters->software_reset.ResetAll();
284 }
285 
286 
287 void
288 SdhciBus::SetClock(int kilohertz)
289 {
290 	int base_clock = fRegisters->capabilities.BaseClockFrequency();
291 	// Try to get as close to 400kHz as possible, but not faster
292 	int divider = base_clock * 1000 / kilohertz;
293 
294 	if (fRegisters->host_controller_version.specVersion <= 1) {
295 		// Old controller only support power of two dividers up to 256,
296 		// round to next power of two up to 256
297 		if (divider > 256)
298 			divider = 256;
299 
300 		divider--;
301 		divider |= divider >> 1;
302 		divider |= divider >> 2;
303 		divider |= divider >> 4;
304 		divider++;
305 	}
306 
307 	divider = fRegisters->clock_control.SetDivider(divider);
308 
309 	// Log the value after possible rounding by SetDivider (only even values
310 	// are allowed).
311 	TRACE("SDCLK frequency: %dMHz / %d = %dkHz\n", base_clock, divider,
312 		base_clock * 1000 / divider);
313 
314 	// We have set the divider, now we can enable the internal clock.
315 	fRegisters->clock_control.EnableInternal();
316 
317 	// wait until internal clock is stabilized
318 	while (!(fRegisters->clock_control.InternalStable()));
319 
320 	fRegisters->clock_control.EnablePLL();
321 	while (!(fRegisters->clock_control.InternalStable()));
322 
323 	// Finally, route the clock to the SD card
324 	fRegisters->clock_control.EnableSD();
325 }
326 
327 
328 static void
329 sdhci_stop_clock(struct registers* regs)
330 {
331 	regs->clock_control.DisableSD();
332 }
333 
334 
335 bool
336 SdhciBus::PowerOn()
337 {
338 	if (!fRegisters->present_state.IsCardInserted()) {
339 		TRACE("Card not inserted, not powering on for now\n");
340 		return false;
341 	}
342 
343 	uint8_t supportedVoltages = fRegisters->capabilities.SupportedVoltages();
344 	if ((supportedVoltages & Capabilities::k3v3) != 0)
345 		fRegisters->power_control.SetVoltage(PowerControl::k3v3);
346 	else if ((supportedVoltages & Capabilities::k3v0) != 0)
347 		fRegisters->power_control.SetVoltage(PowerControl::k3v0);
348 	else if ((supportedVoltages & Capabilities::k1v8) != 0)
349 		fRegisters->power_control.SetVoltage(PowerControl::k1v8);
350 	else {
351 		fRegisters->power_control.PowerOff();
352 		ERROR("No voltage is supported\n");
353 		return false;
354 	}
355 
356 	return true;
357 }
358 
359 
360 static status_t
361 init_bus(device_node* node, void** bus_cookie)
362 {
363 	CALLED();
364 
365 	// Get the PCI driver and device
366 	pci_device_module_info* pci;
367 	pci_device* device;
368 
369 	device_node* parent = gDeviceManager->get_parent_node(node);
370 	device_node* pciParent = gDeviceManager->get_parent_node(parent);
371 	gDeviceManager->get_driver(pciParent, (driver_module_info**)&pci,
372 	        (void**)&device);
373 	gDeviceManager->put_node(pciParent);
374 	gDeviceManager->put_node(parent);
375 
376 	if (get_module(B_PCI_X86_MODULE_NAME, (module_info**)&sPCIx86Module)
377 	    != B_OK) {
378 	    sPCIx86Module = NULL;
379 		ERROR("PCIx86Module not loaded\n");
380 		// FIXME try probing FDT as well
381 		return -1;
382 	}
383 
384 	uint8_t bar, slot;
385 	if (gDeviceManager->get_attr_uint8(node, SLOT_NUMBER, &slot, false) < B_OK
386 		|| gDeviceManager->get_attr_uint8(node, BAR_INDEX, &bar, false) < B_OK)
387 		return -1;
388 
389 	TRACE("Register SD bus at slot %d, using bar %d\n", slot + 1, bar);
390 
391 	pci_info pciInfo;
392 	pci->get_pci_info(device, &pciInfo);
393 	int msiCount = sPCIx86Module->get_msi_count(pciInfo.bus,
394 		pciInfo.device, pciInfo.function);
395 	TRACE("interrupts count: %d\n",msiCount);
396 	// FIXME if available, use MSI rather than good old IRQ...
397 
398 	// enable bus master and io
399 	uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2);
400 	pcicmd &= ~(PCI_command_int_disable | PCI_command_io);
401 	pcicmd |= PCI_command_master | PCI_command_memory;
402 	pci->write_pci_config(device, PCI_command, 2, pcicmd);
403 
404 	// map the slot registers
405 	area_id	regs_area;
406 	struct registers* _regs;
407 	regs_area = map_physical_memory("sdhc_regs_map",
408 		pciInfo.u.h0.base_registers[bar],
409 		pciInfo.u.h0.base_register_sizes[bar], B_ANY_KERNEL_BLOCK_ADDRESS,
410 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&_regs);
411 
412 	if (regs_area < B_OK) {
413 		ERROR("Could not map registers\n");
414 		return B_BAD_VALUE;
415 	}
416 
417 	// the interrupt is shared between all busses in an SDHC controller, but
418 	// they each register an handler. Not a problem, we will just test the
419 	// interrupt registers for all busses one after the other and find no
420 	// interrupts on the idle busses.
421 	uint8_t irq = pciInfo.u.h0.interrupt_line;
422 	TRACE("irq interrupt line: %d\n", irq);
423 
424 	SdhciBus* bus = new(std::nothrow) SdhciBus(_regs, irq);
425 
426 	status_t status = B_NO_MEMORY;
427 	if (bus != NULL)
428 		status = bus->InitCheck();
429 
430 	if (status != B_OK) {
431 		if (sPCIx86Module != NULL) {
432 			put_module(B_PCI_X86_MODULE_NAME);
433 			sPCIx86Module = NULL;
434 		}
435 
436 		if (bus != NULL)
437 			delete bus;
438 		else
439 			delete_area(regs_area);
440 		return status;
441 	}
442 
443 	// Store the created object as a cookie, allowing users of the bus to
444 	// locate it.
445 	*bus_cookie = bus;
446 
447 	return status;
448 }
449 
450 
451 static void
452 uninit_bus(void* bus_cookie)
453 {
454 	SdhciBus* bus = (SdhciBus*)bus_cookie;
455 	delete bus;
456 
457 	// FIXME do we need to put() the PCI module here?
458 }
459 
460 
461 void
462 SdhciBus::RecoverError()
463 {
464 	fRegisters->interrupt_signal_enable &= ~(SDHCI_INT_CMD_CMP
465 		| SDHCI_INT_TRANS_CMP | SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM);
466 
467 	if (fRegisters->interrupt_status & 7)
468 		fRegisters->software_reset.ResetCommandLine();
469 
470 	int16_t error_status = fRegisters->interrupt_status;
471 	fRegisters->interrupt_status &= ~(error_status);
472 }
473 
474 
475 int32
476 SdhciBus::HandleInterrupt()
477 {
478 	uint32_t intmask = fRegisters->interrupt_status;
479 
480 	if ((intmask == 0) || (intmask == 0xffffffff)) {
481 		return B_UNHANDLED_INTERRUPT;
482 	}
483 
484 	TRACE("interrupt function called %x\n", intmask);
485 
486 	// FIXME use the global "slot interrupt" register to quickly decide if an
487 	// interrupt is targetted to this slot
488 
489 	// handling card presence interrupt
490 	if (intmask & (SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM)) {
491 		uint32_t card_present = ((intmask & SDHCI_INT_CARD_INS) != 0);
492 		fRegisters->interrupt_status_enable &= ~(SDHCI_INT_CARD_INS
493 			| SDHCI_INT_CARD_REM);
494 		fRegisters->interrupt_signal_enable &= ~(SDHCI_INT_CARD_INS
495 			| SDHCI_INT_CARD_REM);
496 
497 		fRegisters->interrupt_status_enable |= card_present
498 		 	? SDHCI_INT_CARD_REM : SDHCI_INT_CARD_INS;
499 		fRegisters->interrupt_signal_enable |= card_present
500 			? SDHCI_INT_CARD_REM : SDHCI_INT_CARD_INS;
501 
502 		fRegisters->interrupt_status |= (intmask &
503 			(SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM));
504 		TRACE("Card presence interrupt handled\n");
505 
506 		return B_HANDLED_INTERRUPT;
507 	}
508 
509 	// handling command interrupt
510 	if (intmask & SDHCI_INT_CMD_MASK) {
511 		fCommandResult = intmask;
512 			// Save the status before clearing so the thhread can handle it
513 		fRegisters->interrupt_status |= (intmask & SDHCI_INT_CMD_MASK);
514 		// Notify the thread
515 		release_sem_etc(fSemaphore, 1, B_DO_NOT_RESCHEDULE);
516 		TRACE("Command interrupt handled\n");
517 
518 		return B_HANDLED_INTERRUPT;
519 	}
520 
521 	// handling bus power interrupt
522 	if (intmask & SDHCI_INT_BUS_POWER) {
523 		fRegisters->interrupt_status |= SDHCI_INT_BUS_POWER;
524 		TRACE("card is consuming too much power\n");
525 
526 		return B_HANDLED_INTERRUPT;
527 	}
528 
529 	intmask = fRegisters->slot_interrupt_status;
530 	if (intmask != 0) {
531 		ERROR("Remaining interrupts at end of handler: %x\n", intmask);
532 	}
533 
534 	return B_UNHANDLED_INTERRUPT;
535 }
536 
537 
538 static void
539 bus_removed(void* bus_cookie)
540 {
541 	return;
542 }
543 
544 
545 static status_t
546 register_child_devices(void* cookie)
547 {
548 	CALLED();
549 	device_node* node = (device_node*)cookie;
550 	device_node* parent = gDeviceManager->get_parent_node(node);
551 	pci_device_module_info* pci;
552 	pci_device* device;
553 	uint8 slots_count, bar, slotsInfo;
554 
555 	gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
556 		(void**)&device);
557 	slotsInfo = pci->read_pci_config(device, SDHCI_PCI_SLOT_INFO, 1);
558 	bar = SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(slotsInfo);
559 	slots_count = SDHCI_PCI_SLOTS(slotsInfo);
560 
561 	char prettyName[25];
562 
563 	if (slots_count > 6 || bar > 5) {
564 		ERROR("Invalid slots count: %d or BAR count: %d \n", slots_count, bar);
565 		return B_BAD_VALUE;
566 	}
567 
568 	for (uint8_t slot = 0; slot <= slots_count; slot++) {
569 
570 		bar = bar + slot;
571 		sprintf(prettyName, "SDHC bus %" B_PRIu8, slot);
572 		device_attr attrs[] = {
573 			// properties of this controller for SDHCI bus manager
574 			{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: prettyName } },
575 			{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
576 				{string: MMC_BUS_MODULE_NAME} },
577 			{ B_DEVICE_BUS, B_STRING_TYPE, {string: "mmc"} },
578 			{ SLOT_NUMBER, B_UINT8_TYPE, { ui8: slot} },
579 			{ BAR_INDEX, B_UINT8_TYPE, { ui8: bar} },
580 			{ NULL }
581 		};
582 		if (gDeviceManager->register_node(node, SDHCI_PCI_MMC_BUS_MODULE_NAME,
583 				attrs, NULL, &node) != B_OK)
584 			return B_BAD_VALUE;
585 	}
586 	return B_OK;
587 }
588 
589 
590 static status_t
591 init_device(device_node* node, void** device_cookie)
592 {
593 	CALLED();
594 	*device_cookie = node;
595 	return B_OK;
596 }
597 
598 
599 static status_t
600 register_device(device_node* parent)
601 {
602 	device_attr attrs[] = {
603 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "SD Host Controller"}},
604 		{}
605 	};
606 
607 	return gDeviceManager->register_node(parent, SDHCI_PCI_DEVICE_MODULE_NAME,
608 		attrs, NULL, NULL);
609 }
610 
611 
612 static float
613 supports_device(device_node* parent)
614 {
615 	CALLED();
616 	const char* bus;
617 	uint16 type, subType;
618 	uint8 pciSubDeviceId;
619 	uint16 vendorId, deviceId;
620 
621 	// make sure parent is a PCI SDHCI device node
622 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)
623 		!= B_OK) {
624 		TRACE("Could not find required attribute device/bus\n");
625 		return -1;
626 	}
627 
628 	if (strcmp(bus, "pci") != 0)
629 		return 0.0f;
630 
631 	if (gDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID, &vendorId,
632 			false) != B_OK
633 		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &deviceId,
634 			false) != B_OK) {
635 		TRACE("No vendor or device id attribute\n");
636 		return 0.0f;
637 	}
638 
639 	TRACE("Probe device %p (%04x:%04x)\n", parent, vendorId, deviceId);
640 
641 	if (gDeviceManager->get_attr_uint16(parent, B_DEVICE_SUB_TYPE, &subType,
642 			false) < B_OK
643 		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_TYPE, &type,
644 			false) < B_OK) {
645 		TRACE("Could not find type/subtype attributes\n");
646 		return -1;
647 	}
648 
649 	if (type == PCI_base_peripheral) {
650 		if (subType != PCI_sd_host) {
651 			// Also accept some compliant devices that do not advertise
652 			// themselves as such.
653 			if (vendorId != 0x1180 && deviceId != 0xe823) {
654 				TRACE("Not the right subclass, and not a Ricoh device\n");
655 				return 0.0f;
656 			}
657 		}
658 
659 		pci_device_module_info* pci;
660 		pci_device* device;
661 		gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
662 			(void**)&device);
663 		pciSubDeviceId = pci->read_pci_config(device, PCI_revision, 1);
664 		TRACE("SDHCI Device found! Subtype: 0x%04x, type: 0x%04x\n",
665 			subType, type);
666 		return 0.8f;
667 	}
668 
669 	return 0.0f;
670 }
671 
672 
673 static status_t
674 set_clock(void* controller, uint32_t kilohertz)
675 {
676 	SdhciBus* bus = (SdhciBus*)controller;
677 	bus->SetClock(kilohertz);
678 	return B_OK;
679 }
680 
681 
682 static status_t
683 execute_command(void* controller, uint8_t command, uint32_t argument,
684 	uint32_t* response)
685 {
686 	SdhciBus* bus = (SdhciBus*)controller;
687 	return bus->ExecuteCommand(command, argument, response);
688 }
689 
690 
691 module_dependency module_dependencies[] = {
692 	{ MMC_BUS_MODULE_NAME, (module_info**)&gMMCBusController},
693 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
694 	{}
695 };
696 
697 
698 // Device node registered for each SD slot. It implements the MMC operations so
699 // the bus manager can use it to communicate with SD cards.
700 static mmc_bus_interface gSDHCIPCIDeviceModule = {
701 	{
702 		{
703 			SDHCI_PCI_MMC_BUS_MODULE_NAME,
704 			0,
705 			NULL
706 		},
707 		NULL,	// supports device
708 		NULL,	// register device
709 		init_bus,
710 		uninit_bus,
711 		NULL,	// register child devices
712 		NULL,	// rescan
713 		bus_removed,
714 	},
715 
716 	set_clock,
717 	execute_command,
718 };
719 
720 
721 // Root device that binds to the PCI bus. It will register an mmc_bus_interface
722 // node for each SD slot in the device.
723 static driver_module_info sSDHCIDevice = {
724 	{
725 		SDHCI_PCI_DEVICE_MODULE_NAME,
726 		0,
727 		NULL
728 	},
729 	supports_device,
730 	register_device,
731 	init_device,
732 	NULL,	// uninit
733 	register_child_devices,
734 	NULL,	// rescan
735 	NULL,	// device removed
736 };
737 
738 
739 module_info* modules[] = {
740 	(module_info* )&sSDHCIDevice,
741 	(module_info* )&gSDHCIPCIDeviceModule,
742 	NULL
743 };
744