SDHCI MMC Driver
1. SDHCI PCI Bus: Discovering SDHC device from the PCI bus and registers a child node(MMC bus) to which slots are attached. SDHC registers are mapped by MMUIO, they are binded in a structure(struct* registers). A pin based interrupt handler is also installed, which triggers the handler function and interrupts are being taken care of. Added API's to set-up and the clock for SD/MMC card, change frequency and reset the registers. 2. Device Manager: Currently, busses subdir lists are har- dcoded and in order to load the driver. We hard coded the bus dir under PCI devices. 3. MMC Disk Driver: In order to register the slots under /dev/disk/mmc and hence data transfer and other operations can be done. 4. MMC Bus Manager: Setted up a bus manager to create an object to do a particular for eg certain data transfer and get freed until another operation is requested. Change-Id: I369354da6b79adc6b6dfb08fe160334af1392a34 Reviewed-on: https://review.haiku-os.org/318 Reviewed-by: Alexander von Gluck IV <[email protected]>
This commit is contained in:
committed by
Alexander von Gluck IV
parent
42cc463169
commit
25b6a6f19b
@@ -7,6 +7,7 @@ SubInclude HAIKU_TOP src add-ons kernel bus_managers fdt ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers firewire ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers ata ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers isa ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers mmc ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers pci ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers ps2 ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel bus_managers random ;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel bus_managers mmc ;
|
||||
|
||||
UsePrivateKernelHeaders ;
|
||||
|
||||
KernelAddon mmc_bus :
|
||||
mmc_module.cpp
|
||||
mmc_bus.cpp
|
||||
;
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2018 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* B Krishnan Iyer, [email protected]
|
||||
*/
|
||||
#include "mmc_bus.h"
|
||||
|
||||
|
||||
MMCBus::MMCBus(device_node* node)
|
||||
:
|
||||
fNode(node),
|
||||
fController(NULL),
|
||||
fCookie(NULL),
|
||||
fStatus(B_OK),
|
||||
fDriverCookie(NULL)
|
||||
{
|
||||
CALLED();
|
||||
device_node* parent = gDeviceManager->get_parent_node(node);
|
||||
fStatus = gDeviceManager->get_driver(parent,
|
||||
(driver_module_info**)&fController, &fCookie);
|
||||
gDeviceManager->put_node(parent);
|
||||
|
||||
if (fStatus != B_OK) {
|
||||
ERROR("Not able to establish the bus %s\n",
|
||||
strerror(fStatus));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MMCBus::~MMCBus()
|
||||
{
|
||||
CALLED();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
MMCBus::InitCheck()
|
||||
{
|
||||
return fStatus;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2018 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* B Krishnan Iyer, [email protected]
|
||||
*/
|
||||
#ifndef MMC_BUS_H
|
||||
#define MMC_BUS_H
|
||||
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <lock.h>
|
||||
#include <util/AutoLock.h>
|
||||
#include "../../busses/mmc/sdhci_pci.h"
|
||||
|
||||
|
||||
#define MMCBUS_TRACE
|
||||
#ifdef MMCBUS_TRACE
|
||||
# define TRACE(x...) dprintf("\33[33mmmc_bus:\33[0m " x)
|
||||
#else
|
||||
# define TRACE(x...)
|
||||
#endif
|
||||
#define TRACE_ALWAYS(x...) dprintf("\33[33mmmc_bus:\33[0m " x)
|
||||
#define ERROR(x...) dprintf("\33[33mmmc_bus:\33[0m " x)
|
||||
#define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
|
||||
|
||||
extern device_manager_info *gDeviceManager;
|
||||
|
||||
|
||||
class MMCBus;
|
||||
|
||||
class MMCBus {
|
||||
public:
|
||||
|
||||
MMCBus(device_node *node);
|
||||
~MMCBus();
|
||||
status_t InitCheck();
|
||||
|
||||
private:
|
||||
|
||||
device_node* fNode;
|
||||
sdhci_mmc_bus_interface* fController;
|
||||
void* fCookie;
|
||||
status_t fStatus;
|
||||
void* fDriverCookie;
|
||||
};
|
||||
|
||||
|
||||
#endif /*MMC_BUS_H*/
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2018 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* B Krishnan Iyer, [email protected]
|
||||
*/
|
||||
#include "mmc_bus.h"
|
||||
|
||||
|
||||
device_manager_info* gDeviceManager = NULL;
|
||||
|
||||
|
||||
static status_t
|
||||
mmc_bus_init(device_node* node, void** _device)
|
||||
{
|
||||
CALLED();
|
||||
MMCBus* device = new(std::nothrow) MMCBus(node);
|
||||
if (device == NULL) {
|
||||
ERROR("Unable to allocate MMC bus\n");
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
status_t result = device->InitCheck();
|
||||
if (result != B_OK) {
|
||||
TRACE("failed to set up mmc bus device object\n");
|
||||
return result;
|
||||
}
|
||||
TRACE("MMC bus object created\n");
|
||||
|
||||
*_device = device;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mmc_bus_uninit(void* _device)
|
||||
{
|
||||
CALLED();
|
||||
MMCBus* device = (MMCBus*)_device;
|
||||
delete device;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mmc_bus_removed(void* _device)
|
||||
{
|
||||
CALLED();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
mmc_bus_added_device(device_node* parent)
|
||||
{
|
||||
CALLED();
|
||||
uint16 deviceType;
|
||||
if (gDeviceManager->get_attr_uint16(parent,
|
||||
SDHCI_DEVICE_TYPE_ITEM, &deviceType, true) != B_OK) {
|
||||
TRACE("device is missing\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
TRACE("MMC bus device added\n");
|
||||
|
||||
device_attr attributes[] = {
|
||||
{ B_DEVICE_BUS, B_STRING_TYPE, { string: "mmc bus"}},
|
||||
{ SDHCI_DEVICE_TYPE_ITEM, B_UINT16_TYPE,
|
||||
{ ui16: deviceType }},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return gDeviceManager->register_node(parent, MMC_BUS_MODULE_NAME,
|
||||
attributes, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
std_ops(int32 op, ...)
|
||||
{
|
||||
switch (op) {
|
||||
case B_MODULE_INIT:
|
||||
// Nothing to do
|
||||
case B_MODULE_UNINIT:
|
||||
return B_OK;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
driver_module_info mmc_bus_device_module = {
|
||||
{
|
||||
MMC_BUS_MODULE_NAME,
|
||||
0,
|
||||
std_ops
|
||||
},
|
||||
NULL, // supported devices
|
||||
NULL, // register node
|
||||
mmc_bus_init,
|
||||
mmc_bus_uninit,
|
||||
NULL, // register child devices
|
||||
NULL, // rescan
|
||||
mmc_bus_removed,
|
||||
NULL, // suspend
|
||||
NULL // resume
|
||||
};
|
||||
|
||||
|
||||
driver_module_info mmc_bus_controller_module = {
|
||||
{
|
||||
SDHCI_BUS_CONTROLLER_MODULE_NAME,
|
||||
0,
|
||||
&std_ops
|
||||
},
|
||||
|
||||
NULL, // supported devices
|
||||
mmc_bus_added_device,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
module_dependency module_dependencies[] = {
|
||||
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager },
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
module_info* modules[] = {
|
||||
(module_info*)&mmc_bus_controller_module,
|
||||
(module_info*)&mmc_bus_device_module,
|
||||
NULL
|
||||
};
|
||||
@@ -2,6 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel busses ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons kernel busses ata ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel busses agp_gart ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel busses mmc ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel busses random ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel busses scsi ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel busses usb ;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel busses mmc ;
|
||||
|
||||
SubDirC++Flags -fno-rtti ;
|
||||
|
||||
KernelAddon sdhci_pci :
|
||||
sdhci_pci.cpp
|
||||
;
|
||||
@@ -0,0 +1,534 @@
|
||||
/*
|
||||
* Copyright 2018 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* B Krishnan Iyer, [email protected]
|
||||
*/
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <bus/PCI.h>
|
||||
#include <PCI_x86.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include "sdhci_pci.h"
|
||||
|
||||
|
||||
#define TRACE_SDHCI
|
||||
#ifdef TRACE_SDHCI
|
||||
# define TRACE(x...) dprintf("\33[33msdhci_pci:\33[0m " x)
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
#define TRACE_ALWAYS(x...) dprintf("\33[33msdhci_pci:\33[0m " x)
|
||||
#define ERROR(x...) dprintf("\33[33msdhci_pci:\33[0m " x)
|
||||
#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
|
||||
|
||||
|
||||
#define SDHCI_PCI_DEVICE_MODULE_NAME "busses/mmc/sdhci_pci/driver_v1"
|
||||
#define SDHCI_PCI_MMC_BUS_MODULE_NAME "busses/mmc/sdhci_pci/device/v1"
|
||||
|
||||
#define SDHCI_PCI_CONTROLLER_TYPE_NAME "sdhci pci controller"
|
||||
|
||||
#define SLOTS_COUNT "device/slots_count"
|
||||
#define SLOT_NUMBER "device/slot"
|
||||
#define BAR_INDEX "device/bar"
|
||||
|
||||
typedef struct {
|
||||
pci_device_module_info* pci;
|
||||
pci_device* device;
|
||||
addr_t base_addr;
|
||||
uint8 irq;
|
||||
sdhci_mmc_bus mmc_bus;
|
||||
area_id regs_area;
|
||||
device_node* node;
|
||||
pci_info info;
|
||||
struct registers* _regs;
|
||||
|
||||
} sdhci_pci_mmc_bus_info;
|
||||
|
||||
|
||||
device_manager_info* gDeviceManager;
|
||||
device_module_info* gSDHCIDeviceController;
|
||||
static pci_x86_module_info* sPCIx86Module;
|
||||
|
||||
|
||||
static void
|
||||
sdhci_register_dump(uint8_t slot, struct registers* regs)
|
||||
{
|
||||
TRACE("Register values for slot: %d\n", slot);
|
||||
TRACE("system_address: %d\n", regs->system_address);
|
||||
TRACE("block_size: %d\n", regs->block_size);
|
||||
TRACE("block_count: %d\n", regs->block_count);
|
||||
TRACE("argument: %d\n", regs->argument);
|
||||
TRACE("transfer_mode: %d\n", regs->transfer_mode);
|
||||
TRACE("command: %d\n", regs->command);
|
||||
TRACE("response0: %d\n", regs->response0);
|
||||
TRACE("response2: %d\n", regs->response2);
|
||||
TRACE("response4: %d\n", regs->response4);
|
||||
TRACE("response6: %d\n", regs->response6);
|
||||
TRACE("buffer_data_port: %d\n", regs->buffer_data_port);
|
||||
TRACE("present_state: %d\n", regs->present_state);
|
||||
TRACE("power_control: %d\n", regs->power_control);
|
||||
TRACE("host_control: %d\n", regs->host_control);
|
||||
TRACE("wakeup_control: %d\n", regs->wakeup_control);
|
||||
TRACE("block_gap_control: %d\n", regs->block_gap_control);
|
||||
TRACE("clock_control: %d\n", regs->clock_control);
|
||||
TRACE("software_reset: %d\n", regs->software_reset);
|
||||
TRACE("timeout_control: %d\n", regs->timeout_control);
|
||||
TRACE("interrupt_status: %d\n", regs->interrupt_status);
|
||||
TRACE("interrupt_status_enable: %d\n", regs->interrupt_status_enable);
|
||||
TRACE("interrupt_signal_enable: %d\n", regs->interrupt_signal_enable);
|
||||
TRACE("auto_cmd12_error_status: %d\n", regs->auto_cmd12_error_status);
|
||||
TRACE("capabilities: %d\n", regs->capabilities);
|
||||
TRACE("capabilities_rsvd: %d\n", regs->capabilities_rsvd);
|
||||
TRACE("max_current_capabilities: %d\n",
|
||||
regs->max_current_capabilities);
|
||||
TRACE("max_current_capabilities_rsvd: %d\n",
|
||||
regs->max_current_capabilities_rsvd);
|
||||
TRACE("slot_interrupt_status: %d\n", regs->slot_interrupt_status);
|
||||
TRACE("host_control_version %d\n", regs->host_control_version);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sdhci_reset(struct registers* regs)
|
||||
{
|
||||
// if card is not present then no point of reseting the registers
|
||||
if (!(regs->present_state & SDHCI_CARD_DETECT))
|
||||
return;
|
||||
|
||||
// enabling software reset all
|
||||
regs->software_reset |= SDHCI_SOFTWARE_RESET_ALL;
|
||||
|
||||
// waiting for clock and power to get off
|
||||
while (regs->clock_control != 0 && regs->power_control != 0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sdhci_set_clock(struct registers* regs, uint16_t base_clock_div)
|
||||
{
|
||||
uint32_t clock_control = regs->clock_control;
|
||||
int base_clock = SDHCI_BASE_CLOCK_FREQ(regs->capabilities);
|
||||
|
||||
TRACE("SDCLK frequency: %dMHz\n", base_clock);
|
||||
|
||||
// clearing previous frequency
|
||||
clock_control &= SDHCI_CLR_FREQ_SEL;
|
||||
clock_control |= base_clock_div;
|
||||
|
||||
// enabling internal clock
|
||||
clock_control |= SDHCI_INTERNAL_CLOCK_ENABLE;
|
||||
regs->clock_control = clock_control;
|
||||
|
||||
// waiting till internal clock gets stable
|
||||
while (!(regs->clock_control & SDHCI_INTERNAL_CLOCK_STABLE));
|
||||
|
||||
regs->clock_control |= SDHCI_SD_CLOCK_ENABLE; // enabling the SD clock
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sdhci_stop_clock(struct registers* regs)
|
||||
{
|
||||
regs->clock_control &= SDHCI_SD_CLOCK_DISABLE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sdhci_set_power(struct registers* _regs)
|
||||
{
|
||||
uint16_t command = _regs->command;
|
||||
|
||||
if (SDHCI_VOLTAGE_SUPPORTED(_regs->capabilities))
|
||||
if (SDHCI_VOLTAGE_SUPPORTED_33(_regs->capabilities))
|
||||
_regs->power_control |= SDHCI_VOLTAGE_SUPPORT_33;
|
||||
else if (SDHCI_VOLTAGE_SUPPORTED_30(_regs->capabilities))
|
||||
_regs->power_control |= SDHCI_VOLTAGE_SUPPORT_30;
|
||||
else
|
||||
_regs->power_control |= SDHCI_VOLTAGE_SUPPORT_18;
|
||||
else
|
||||
TRACE("No voltage is supported\n");
|
||||
|
||||
if (SDHCI_CARD_INSERTED(_regs->present_state) == 0) {
|
||||
TRACE("Card not inserted\n");
|
||||
return;
|
||||
}
|
||||
|
||||
_regs->power_control |= SDHCI_BUS_POWER_ON;
|
||||
TRACE("Executed CMD0\n");
|
||||
|
||||
command = SDHCI_RESPONSE_R1 | SDHCI_CMD_CRC_EN
|
||||
| SDHCI_CMD_INDEX_EN | SDHCI_CMD_0;
|
||||
_regs->command |= command;
|
||||
|
||||
DELAY(1000);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
init_bus(device_node* node, void** bus_cookie)
|
||||
{
|
||||
CALLED();
|
||||
status_t status = B_OK;
|
||||
area_id regs_area;
|
||||
volatile uint32_t* regs;
|
||||
uint8_t bar, slot;
|
||||
|
||||
sdhci_pci_mmc_bus_info* bus = new(std::nothrow) sdhci_pci_mmc_bus_info;
|
||||
if (bus == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
pci_info* pciInfo = &bus->info;
|
||||
pci_device_module_info* pci;
|
||||
pci_device* device;
|
||||
|
||||
device_node* parent = gDeviceManager->get_parent_node(node);
|
||||
device_node* pciParent = gDeviceManager->get_parent_node(parent);
|
||||
gDeviceManager->get_driver(pciParent, (driver_module_info**)&pci,
|
||||
(void**)&device);
|
||||
gDeviceManager->put_node(pciParent);
|
||||
gDeviceManager->put_node(parent);
|
||||
|
||||
if (get_module(B_PCI_X86_MODULE_NAME, (module_info**)&sPCIx86Module)
|
||||
!= B_OK) {
|
||||
sPCIx86Module = NULL;
|
||||
TRACE("PCIx86Module not loaded\n");
|
||||
}
|
||||
|
||||
int msiCount = sPCIx86Module->get_msi_count(pciInfo->bus,
|
||||
pciInfo->device, pciInfo->function);
|
||||
|
||||
TRACE("interrupts count: %d\n",msiCount);
|
||||
|
||||
if (gDeviceManager->get_attr_uint8(node, SLOT_NUMBER, &slot, false) < B_OK
|
||||
|| gDeviceManager->get_attr_uint8(node, BAR_INDEX, &bar, false) < B_OK)
|
||||
return -1;
|
||||
|
||||
bus->node = node;
|
||||
bus->pci = pci;
|
||||
bus->device = device;
|
||||
|
||||
pci->get_pci_info(device, pciInfo);
|
||||
|
||||
// legacy interrupt
|
||||
bus->base_addr = pciInfo->u.h0.base_registers[bar];
|
||||
|
||||
// enable bus master and io
|
||||
uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2);
|
||||
pcicmd &= ~(PCI_command_int_disable | PCI_command_io);
|
||||
pcicmd |= PCI_command_master | PCI_command_memory;
|
||||
pci->write_pci_config(device, PCI_command, 2, pcicmd);
|
||||
|
||||
TRACE("init_bus() %p node %p pci %p device %p\n", bus, node,
|
||||
bus->pci, bus->device);
|
||||
|
||||
// mapping the registers by MMUIO method
|
||||
int bar_size = pciInfo->u.h0.base_register_sizes[bar];
|
||||
|
||||
regs_area = map_physical_memory("sdhc_regs_map",
|
||||
pciInfo->u.h0.base_registers[bar],
|
||||
pciInfo->u.h0.base_register_sizes[bar], B_ANY_KERNEL_BLOCK_ADDRESS,
|
||||
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)®s);
|
||||
|
||||
if (regs_area < B_OK) {
|
||||
TRACE("mapping failed");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
bus->regs_area = regs_area;
|
||||
struct registers* _regs = (struct registers*)regs;
|
||||
bus->_regs = _regs;
|
||||
sdhci_reset(_regs);
|
||||
bus->irq = pciInfo->u.h0.interrupt_line;
|
||||
|
||||
TRACE("irq interrupt line: %d\n",bus->irq);
|
||||
|
||||
if (bus->irq == 0 || bus->irq == 0xff) {
|
||||
TRACE("PCI IRQ not assigned\n");
|
||||
if (sPCIx86Module != NULL) {
|
||||
put_module(B_PCI_X86_MODULE_NAME);
|
||||
sPCIx86Module = NULL;
|
||||
}
|
||||
delete bus;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
status = install_io_interrupt_handler(bus->irq,
|
||||
sdhci_generic_interrupt, bus, 0);
|
||||
|
||||
if (status != B_OK) {
|
||||
TRACE("can't install interrupt handler\n");
|
||||
return status;
|
||||
}
|
||||
TRACE("interrupt handler installed\n");
|
||||
|
||||
_regs->interrupt_status_enable = SDHCI_INT_CMD_CMP
|
||||
| SDHCI_INT_TRANS_CMP | SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM
|
||||
| SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | SDHCI_INT_INDEX
|
||||
| SDHCI_INT_BUS_POWER | SDHCI_INT_END_BIT;
|
||||
_regs->interrupt_signal_enable = SDHCI_INT_CMD_CMP
|
||||
| SDHCI_INT_TRANS_CMP | SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM
|
||||
| SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | SDHCI_INT_INDEX
|
||||
| SDHCI_INT_BUS_POWER | SDHCI_INT_END_BIT;
|
||||
|
||||
sdhci_register_dump(slot, _regs);
|
||||
sdhci_set_clock(_regs, SDHCI_BASE_CLOCK_DIV_128);
|
||||
sdhci_set_power(_regs);
|
||||
sdhci_register_dump(slot, _regs);
|
||||
|
||||
*bus_cookie = bus;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
sdhci_error_interrupt_recovery(struct registers* _regs)
|
||||
{
|
||||
_regs->interrupt_signal_enable &= ~(SDHCI_INT_CMD_CMP
|
||||
| SDHCI_INT_TRANS_CMP | SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM);
|
||||
|
||||
if (_regs->interrupt_status & 7) {
|
||||
_regs->software_reset |= 1 << 1;
|
||||
while (_regs->command);
|
||||
}
|
||||
|
||||
int16_t erorr_status = _regs->interrupt_status;
|
||||
_regs->interrupt_status &= ~(erorr_status);
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
sdhci_generic_interrupt(void* data)
|
||||
{
|
||||
TRACE("interrupt function called\n");
|
||||
sdhci_pci_mmc_bus_info* bus = (sdhci_pci_mmc_bus_info*)data;
|
||||
|
||||
uint16_t intmask, card_present;
|
||||
|
||||
intmask = bus->_regs->slot_interrupt_status;
|
||||
|
||||
if (intmask == 0 || intmask == 0xffffffff) {
|
||||
TRACE("invalid command interrupt\n");
|
||||
|
||||
return B_UNHANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
// handling card presence interrupt
|
||||
if (intmask & (SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM)) {
|
||||
card_present = ((intmask & SDHCI_INT_CARD_INS) != 0);
|
||||
bus->_regs->interrupt_status_enable &= ~(SDHCI_INT_CARD_INS
|
||||
| SDHCI_INT_CARD_REM);
|
||||
bus->_regs->interrupt_signal_enable &= ~(SDHCI_INT_CARD_INS
|
||||
| SDHCI_INT_CARD_REM);
|
||||
|
||||
bus->_regs->interrupt_status_enable |= card_present
|
||||
? SDHCI_INT_CARD_REM : SDHCI_INT_CARD_INS;
|
||||
bus->_regs->interrupt_signal_enable |= card_present
|
||||
? SDHCI_INT_CARD_REM : SDHCI_INT_CARD_INS;
|
||||
|
||||
bus->_regs->interrupt_status |= (intmask &
|
||||
(SDHCI_INT_CARD_INS | SDHCI_INT_CARD_REM));
|
||||
TRACE("Card presence interrupt handled\n");
|
||||
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
// handling command interrupt
|
||||
if (intmask & SDHCI_INT_CMD_MASK) {
|
||||
TRACE("interrupt status error: %d\n", bus->_regs->interrupt_status);
|
||||
bus->_regs->interrupt_status |= (intmask & SDHCI_INT_CMD_MASK);
|
||||
TRACE("Command interrupt handled\n");
|
||||
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
// handling bus power interrupt
|
||||
if (intmask & SDHCI_INT_BUS_POWER) {
|
||||
bus->_regs->interrupt_status |= SDHCI_INT_BUS_POWER;
|
||||
TRACE("card is consuming too much power\n");
|
||||
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
intmask &= ~(SDHCI_INT_BUS_POWER | SDHCI_INT_CARD_INS
|
||||
|SDHCI_INT_CARD_REM | SDHCI_INT_CMD_MASK);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
uninit_bus(void* bus_cookie)
|
||||
{
|
||||
sdhci_pci_mmc_bus_info* bus = (sdhci_pci_mmc_bus_info*)bus_cookie;
|
||||
delete bus;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
bus_removed(void* bus_cookie)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
register_child_devices(void* cookie)
|
||||
{
|
||||
CALLED();
|
||||
device_node* node = (device_node*)cookie;
|
||||
device_node* parent = gDeviceManager->get_parent_node(node);
|
||||
pci_device_module_info* pci;
|
||||
pci_device* device;
|
||||
uint8 slots_count, bar, slotsInfo;
|
||||
|
||||
gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
|
||||
(void**)&device);
|
||||
uint16 pciSubDeviceId = pci->read_pci_config(device, PCI_subsystem_id, 2);
|
||||
slotsInfo = pci->read_pci_config(device, SDHCI_PCI_SLOT_INFO, 1);
|
||||
bar = SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(slotsInfo);
|
||||
slots_count = SDHCI_PCI_SLOTS(slotsInfo);
|
||||
|
||||
char prettyName[25];
|
||||
|
||||
if (slots_count > 6 || bar > 5) {
|
||||
TRACE("Invalid slots count: %d or BAR count: %d \n", slots_count, bar);
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
for (uint8_t slot = 0; slot <= slots_count; slot++) {
|
||||
|
||||
bar = bar + slot;
|
||||
sprintf(prettyName, "SDHC bus %" B_PRIu16 " slot %"
|
||||
B_PRIu8, pciSubDeviceId, slot);
|
||||
device_attr attrs[] = {
|
||||
// properties of this controller for SDHCI bus manager
|
||||
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
|
||||
{ string: prettyName }},
|
||||
{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
|
||||
{string: SDHCI_BUS_CONTROLLER_MODULE_NAME}},
|
||||
{SDHCI_DEVICE_TYPE_ITEM, B_UINT16_TYPE,
|
||||
{ ui16: pciSubDeviceId}},
|
||||
{B_DEVICE_BUS, B_STRING_TYPE,{string: "mmc"}},
|
||||
{SLOT_NUMBER, B_UINT8_TYPE,
|
||||
{ ui8: slot}},
|
||||
{BAR_INDEX, B_UINT8_TYPE,
|
||||
{ ui8: bar}},
|
||||
{ NULL }
|
||||
};
|
||||
if (gDeviceManager->register_node(node, SDHCI_PCI_MMC_BUS_MODULE_NAME,
|
||||
attrs, NULL, &node) != B_OK)
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
init_device(device_node* node, void** device_cookie)
|
||||
{
|
||||
CALLED();
|
||||
*device_cookie = node;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
register_device(device_node* parent)
|
||||
{
|
||||
device_attr attrs[] = {
|
||||
{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "SDHC PCI controller"}},
|
||||
{}
|
||||
};
|
||||
|
||||
return gDeviceManager->register_node(parent, SDHCI_PCI_DEVICE_MODULE_NAME,
|
||||
attrs, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
static float
|
||||
supports_device(device_node* parent)
|
||||
{
|
||||
CALLED();
|
||||
const char* bus;
|
||||
uint16 type, subType;
|
||||
uint8 pciSubDeviceId;
|
||||
|
||||
// make sure parent is a PCI SDHCI device node
|
||||
if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)
|
||||
!= B_OK || gDeviceManager->get_attr_uint16(parent, B_DEVICE_SUB_TYPE,
|
||||
&subType, false) < B_OK || gDeviceManager->get_attr_uint16(parent,
|
||||
B_DEVICE_TYPE, &type, false) < B_OK)
|
||||
return -1;
|
||||
|
||||
if (strcmp(bus, "pci") != 0)
|
||||
return 0.0f;
|
||||
|
||||
if (type == PCI_base_peripheral) {
|
||||
if (subType != PCI_sd_host)
|
||||
return 0.0f;
|
||||
|
||||
pci_device_module_info* pci;
|
||||
pci_device* device;
|
||||
gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
|
||||
(void**)&device);
|
||||
pciSubDeviceId = pci->read_pci_config(device, PCI_revision, 1);
|
||||
TRACE("SDHCI Device found! Subtype: 0x%04x, type: 0x%04x\n",
|
||||
subType, type);
|
||||
return 0.8f;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
|
||||
module_dependency module_dependencies[] = {
|
||||
{ SDHCI_BUS_CONTROLLER_MODULE_NAME, (module_info**)&gSDHCIDeviceController},
|
||||
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
static sdhci_mmc_bus_interface gSDHCIPCIDeviceModule = {
|
||||
{
|
||||
{
|
||||
SDHCI_PCI_MMC_BUS_MODULE_NAME,
|
||||
0,
|
||||
NULL
|
||||
},
|
||||
NULL, // supports device
|
||||
NULL, // register device
|
||||
init_bus,
|
||||
uninit_bus,
|
||||
NULL, // register child devices
|
||||
NULL, // rescan
|
||||
bus_removed,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static driver_module_info sSDHCIDevice = {
|
||||
{
|
||||
SDHCI_PCI_DEVICE_MODULE_NAME,
|
||||
0,
|
||||
NULL
|
||||
},
|
||||
supports_device,
|
||||
register_device,
|
||||
init_device,
|
||||
NULL, // uninit
|
||||
register_child_devices,
|
||||
NULL, // rescan
|
||||
NULL, // device removed
|
||||
};
|
||||
|
||||
|
||||
module_info* modules[] = {
|
||||
(module_info* )&sSDHCIDevice,
|
||||
(module_info* )&gSDHCIPCIDeviceModule,
|
||||
NULL
|
||||
};
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2018 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* B Krishnan Iyer, [email protected]
|
||||
*/
|
||||
#ifndef _SDHCI_PCI_H
|
||||
#define _SDHCI_PCI_H
|
||||
|
||||
|
||||
#include <device_manager.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
|
||||
#define SDHCI_PCI_SLOT_INFO 0x40
|
||||
#define SDHCI_PCI_SLOTS(x) ((( x >> 4) & 7))
|
||||
#define SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(x) (( x ) & 7)
|
||||
|
||||
#define SDHCI_DEVICE_TYPE_ITEM "sdhci/type"
|
||||
#define SDHCI_BUS_TYPE_NAME "bus/sdhci/v1"
|
||||
|
||||
#define SDHCI_CARD_DETECT 1 << 16
|
||||
|
||||
#define SDHCI_SOFTWARE_RESET_ALL 1 << 0
|
||||
|
||||
#define SDHCI_BASE_CLOCK_FREQ(x) ((x >> 8) & 63)
|
||||
#define SDHCI_VOLTAGE_SUPPORTED(x) ((x >> 24) & 7)
|
||||
#define SDHCI_VOLTAGE_SUPPORTED_33(x) ((x >> 24) & 1)
|
||||
#define SDHCI_VOLTAGE_SUPPORTED_30(x) ((x >> 24) & 3)
|
||||
#define SDHCI_VOLTAGE_SUPPORT_33 7 << 1
|
||||
#define SDHCI_VOLTAGE_SUPPORT_30 6 << 1
|
||||
#define SDHCI_VOLTAGE_SUPPORT_18 5 << 1
|
||||
#define SDHCI_CARD_INSERTED(x) ((x >> 16) & 1)
|
||||
#define SDHCI_BASE_CLOCK_DIV_1 0 << 8
|
||||
#define SDHCI_BASE_CLOCK_DIV_2 1 << 8
|
||||
#define SDHCI_BASE_CLOCK_DIV_4 2 << 8
|
||||
#define SDHCI_BASE_CLOCK_DIV_8 4 << 8
|
||||
#define SDHCI_BASE_CLOCK_DIV_16 8 << 8
|
||||
#define SDHCI_BASE_CLOCK_DIV_32 16 << 8
|
||||
#define SDHCI_BASE_CLOCK_DIV_64 32 << 8
|
||||
#define SDHCI_BASE_CLOCK_DIV_128 64 << 8
|
||||
#define SDHCI_BASE_CLOCK_DIV_256 128 << 8
|
||||
#define SDHCI_INTERNAL_CLOCK_ENABLE 1 << 0
|
||||
#define SDHCI_INTERNAL_CLOCK_STABLE 1 << 1
|
||||
#define SDHCI_SD_CLOCK_ENABLE 1 << 2
|
||||
#define SDHCI_SD_CLOCK_DISABLE ~(1 << 2)
|
||||
#define SDHCI_CLR_FREQ_SEL ~(255 << 8)
|
||||
#define SDHCI_BUS_POWER_ON 1
|
||||
#define SDHCI_RESPONSE_R1 2
|
||||
#define SDHCI_CMD_CRC_EN 1 << 3
|
||||
#define SDHCI_CMD_INDEX_EN 1 << 4
|
||||
#define SDHCI_CMD_0 ~(63 << 8)
|
||||
/* Interrupt registers */
|
||||
#define SDHCI_INT_CMD_CMP 0x00000001 // command complete enable
|
||||
#define SDHCI_INT_TRANS_CMP 0x00000002 // transfer complete enable
|
||||
#define SDHCI_INT_CARD_INS 0x00000040 // card insertion enable
|
||||
#define SDHCI_INT_CARD_REM 0x00000080 // card removal enable
|
||||
#define SDHCI_INT_TIMEOUT 0x00010000 // Timeout error
|
||||
#define SDHCI_INT_CRC 0x00020000 // CRC error
|
||||
#define SDHCI_INT_END_BIT 0x00040000 // end bit error
|
||||
#define SDHCI_INT_INDEX 0x00080000 // index error
|
||||
#define SDHCI_INT_BUS_POWER 0x00800000 // power fail
|
||||
|
||||
#define SDHCI_INT_CMD_ERROR_MASK (SDHCI_INT_TIMEOUT | \
|
||||
SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
|
||||
|
||||
#define SDHCI_INT_CMD_MASK (SDHCI_INT_CMD_CMP | SDHCI_INT_CMD_ERROR_MASK)
|
||||
|
||||
|
||||
struct registers {
|
||||
volatile uint32_t system_address;
|
||||
volatile uint16_t block_size;
|
||||
volatile uint16_t block_count;
|
||||
volatile uint32_t argument;
|
||||
volatile uint16_t transfer_mode;
|
||||
volatile uint16_t command;
|
||||
volatile uint32_t response0;
|
||||
volatile uint32_t response2;
|
||||
volatile uint32_t response4;
|
||||
volatile uint32_t response6;
|
||||
volatile uint32_t buffer_data_port;
|
||||
volatile uint32_t present_state;
|
||||
volatile uint8_t host_control;
|
||||
volatile uint8_t power_control;
|
||||
volatile uint8_t block_gap_control;
|
||||
volatile uint8_t wakeup_control;
|
||||
volatile uint16_t clock_control;
|
||||
volatile uint8_t timeout_control;
|
||||
volatile uint8_t software_reset;
|
||||
volatile uint32_t interrupt_status;
|
||||
volatile uint32_t interrupt_status_enable;
|
||||
volatile uint32_t interrupt_signal_enable;
|
||||
volatile uint16_t auto_cmd12_error_status;
|
||||
volatile uint16_t : 16;
|
||||
volatile uint32_t capabilities;
|
||||
volatile uint32_t capabilities_rsvd;
|
||||
volatile uint32_t max_current_capabilities;
|
||||
volatile uint32_t max_current_capabilities_rsvd;
|
||||
volatile uint64_t padding[21];
|
||||
volatile uint32_t : 32;
|
||||
volatile uint16_t slot_interrupt_status;
|
||||
volatile uint16_t host_control_version;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef void* sdhci_mmc_bus;
|
||||
|
||||
#define DELAY(n) snooze(n)
|
||||
|
||||
#define SDHCI_BUS_CONTROLLER_MODULE_NAME "bus_managers/mmc_bus/driver_v1"
|
||||
|
||||
#define MMC_BUS_MODULE_NAME "bus_managers/mmc_bus/device/v1"
|
||||
|
||||
static void sdhci_register_dump(uint8_t, struct registers*);
|
||||
static void sdhci_reset(struct registers*);
|
||||
static void sdhci_set_clock(struct registers*, uint16_t);
|
||||
static void sdhci_set_power(struct registers*);
|
||||
static void sdhci_stop_clock(struct registers*);
|
||||
void sdhci_error_interrupt_recovery(struct registers*);
|
||||
|
||||
status_t sdhci_generic_interrupt(void*);
|
||||
|
||||
typedef struct {
|
||||
driver_module_info info;
|
||||
|
||||
} sdhci_mmc_bus_interface;
|
||||
|
||||
|
||||
#endif /*_SDHCI_PCI_H*/
|
||||
@@ -2,6 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers disk ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers disk floppy ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers disk norflash ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers disk mmc ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers disk scsi ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers disk usb ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers disk virtual ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel drivers disk virtual ;
|
||||
@@ -0,0 +1,8 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel drivers disk mmc ;
|
||||
|
||||
UsePrivateKernelHeaders ;
|
||||
SubDirHdrs $(HAIKU_TOP) src system kernel device_manager ;
|
||||
|
||||
KernelAddon mmc_disk :
|
||||
mmc_disk.cpp
|
||||
;
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 2018 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* B Krishnan Iyer, krishnaniyer97@gmail.com
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "mmc_disk.h"
|
||||
|
||||
#include <drivers/device_manager.h>
|
||||
#include <drivers/KernelExport.h>
|
||||
#include <drivers/Drivers.h>
|
||||
#include <kernel/OS.h>
|
||||
|
||||
// #include <fs/devfs.h>
|
||||
|
||||
#define TRACE_MMC_DISK
|
||||
#ifdef TRACE_MMC_DISK
|
||||
# define TRACE(x...) dprintf("mmc_disk: " x)
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
#define ERROR(x...) dprintf("\33[33mmc_disk:\33[0m " x)
|
||||
#define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
|
||||
|
||||
#define MMC_DISK_DRIVER_MODULE_NAME "drivers/disk/mmc/mmc_disk/driver_v1"
|
||||
#define MMC_DISK_DEVICE_MODULE_NAME "drivers/disk/mmc/mmc_disk/device_v1"
|
||||
#define MMC_DEVICE_ID_GENERATOR "mmc/device_id"
|
||||
|
||||
static device_manager_info* sDeviceManager;
|
||||
|
||||
|
||||
static float
|
||||
mmc_disk_supports_device(device_node* parent)
|
||||
{
|
||||
CALLED();
|
||||
const char* bus;
|
||||
// uint16 deviceType;
|
||||
|
||||
if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus,
|
||||
true) != B_OK)
|
||||
return -1;
|
||||
|
||||
if (strcmp(bus, "mmc") != 0) {
|
||||
TRACE("bus value %s, parent: %p\n",bus, parent);
|
||||
return 0.0;
|
||||
}
|
||||
// Used to check the device type but later we have attached an
|
||||
// attribute(mmc) to the bus. Not a compulsion to use this condition
|
||||
#if 0
|
||||
if (sDeviceManager->get_attr_uint16(parent, SDHCI_DEVICE_TYPE_ITEM,
|
||||
&deviceType, true) != B_OK)
|
||||
{
|
||||
TRACE(" Inavlid device type, bus found: %s and attr val %d\n",
|
||||
bus, deviceType);
|
||||
return 0.0;
|
||||
}
|
||||
#endif
|
||||
TRACE("sdhci device found, parent: %p\n", parent);
|
||||
|
||||
return 0.8;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
mmc_disk_register_device(device_node* node)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
device_attr attrs[] = {
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return sDeviceManager->register_node(node
|
||||
, MMC_DISK_DRIVER_MODULE_NAME, attrs, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
mmc_disk_init_driver(device_node* node, void** cookie)
|
||||
{
|
||||
CALLED();
|
||||
mmc_disk_driver_info* info = (mmc_disk_driver_info*)malloc(
|
||||
sizeof(mmc_disk_driver_info));
|
||||
|
||||
if (info == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
info->node = node;
|
||||
|
||||
*cookie = info;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
mmc_disk_uninit_driver(void* _cookie)
|
||||
{
|
||||
CALLED();
|
||||
mmc_disk_driver_info* info = (mmc_disk_driver_info*)_cookie;
|
||||
free(info);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
mmc_disk_register_child_devices(void* _cookie)
|
||||
{
|
||||
CALLED();
|
||||
mmc_disk_driver_info* info = (mmc_disk_driver_info*)_cookie;
|
||||
status_t status;
|
||||
|
||||
int32 id = sDeviceManager->create_id(MMC_DEVICE_ID_GENERATOR);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
char name[64];
|
||||
snprintf(name, sizeof(name), "disk/mmc/%" B_PRId32 "/raw", id);
|
||||
|
||||
status = sDeviceManager->publish_device(info->node, name,
|
||||
MMC_DISK_DEVICE_MODULE_NAME);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
module_dependency module_dependencies[] = {
|
||||
{B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager},
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
struct driver_module_info sMMCDiskDriver = {
|
||||
{
|
||||
MMC_DISK_DRIVER_MODULE_NAME,
|
||||
0,
|
||||
NULL
|
||||
},
|
||||
mmc_disk_supports_device,
|
||||
mmc_disk_register_device,
|
||||
mmc_disk_init_driver,
|
||||
mmc_disk_uninit_driver,
|
||||
mmc_disk_register_child_devices,
|
||||
NULL, // mmc_disk_rescan_child_devices,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
module_info* modules[] = {
|
||||
(module_info*)&sMMCDiskDriver,
|
||||
NULL
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2018 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* B Krishnan Iyer, krishnaniyer97@gmail.com
|
||||
*/
|
||||
#ifndef _MMC_DISK_H
|
||||
#define _MMC_DISK_H
|
||||
|
||||
|
||||
#include <device_manager.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
|
||||
#define SDHCI_DEVICE_TYPE_ITEM "sdhci/type"
|
||||
|
||||
typedef struct {
|
||||
device_node* node;
|
||||
status_t media_status;
|
||||
} mmc_disk_driver_info;
|
||||
|
||||
|
||||
#endif /*_MMC_DISK_H*/
|
||||
@@ -42,7 +42,6 @@
|
||||
# define TRACE(a) ;
|
||||
#endif
|
||||
|
||||
|
||||
#define DEVICE_MANAGER_ROOT_NAME "system/devices_root/driver_v1"
|
||||
#define DEVICE_MANAGER_GENERIC_NAME "system/devices_generic/driver_v1"
|
||||
|
||||
@@ -1538,7 +1537,9 @@ device_node::_GetNextDriverPath(void*& cookie, KPath& _path)
|
||||
if (get_attr_uint16(this, B_DEVICE_TYPE, &type, false) != B_OK
|
||||
|| get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false)
|
||||
!= B_OK)
|
||||
{
|
||||
generic = true;
|
||||
}
|
||||
|
||||
get_attr_uint16(this, B_DEVICE_INTERFACE, &interface, false);
|
||||
|
||||
@@ -1599,6 +1600,16 @@ device_node::_GetNextDriverPath(void*& cookie, KPath& _path)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PCI_base_peripheral:
|
||||
switch (subType) {
|
||||
case PCI_sd_host:
|
||||
_AddPath(*stack, "busses", "mmc");
|
||||
break;
|
||||
default:
|
||||
_AddPath(*stack, "drivers");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (sRootNode == this) {
|
||||
_AddPath(*stack, "busses/pci");
|
||||
@@ -1885,7 +1896,8 @@ device_node::Probe(const char* devicePath, uint32 updateCycle)
|
||||
// Check if this node matches the device path
|
||||
// TODO: maybe make this extendible via settings file?
|
||||
if (!strcmp(devicePath, "disk")) {
|
||||
matches = type == PCI_mass_storage;
|
||||
matches = type == PCI_mass_storage
|
||||
&& (type == PCI_base_peripheral || subType == PCI_sd_host);
|
||||
} else if (!strcmp(devicePath, "audio")) {
|
||||
matches = type == PCI_multimedia
|
||||
&& (subType == PCI_audio || subType == PCI_hd_audio);
|
||||
|
||||
Reference in New Issue
Block a user