Some corrections and cleanup to ACPI Embedded controller:

* Exposed ACPI API needed by Embedded Controller
	This will be removed again if moved inside the bus manager.
	It also duplicates ACPI's own headers so it might go out of sync atm.
 * Added mutex to controller and fixed the mixup between acpi_status needed in int handlers and Haiku status.
 * Major code cleanup
	Not for headers as they are mostly redundant if we move the controller.
	Variable names still needs some cleanup

This makes the ACPI errors from the controller understandable. I get AE_NO_HARDWARE_RESPONSE now.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36318 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Fredrik Holmqvist
2010-04-15 19:23:43 +00:00
parent dd41712c26
commit 186058c517
3 changed files with 585 additions and 575 deletions
+23 -3
View File
@@ -34,7 +34,8 @@ enum {
ACPI_ADR_SPACE_SMBUS = 4, ACPI_ADR_SPACE_SMBUS = 4,
ACPI_ADR_SPACE_CMOS = 5, ACPI_ADR_SPACE_CMOS = 5,
ACPI_ADR_SPACE_PCI_BAR_TARGET = 6, ACPI_ADR_SPACE_PCI_BAR_TARGET = 6,
ACPI_ADR_SPACE_DATA_TABLE = 7, ACPI_ADR_SPACE_IPMI = 7,
ACPI_ADR_SPACE_DATA_TABLE = 8,
ACPI_ADR_SPACE_FIXED_HARDWARE = 127 ACPI_ADR_SPACE_FIXED_HARDWARE = 127
}; };
@@ -66,6 +67,8 @@ enum {
ACPI_TYPE_PROCESSOR, ACPI_TYPE_PROCESSOR,
ACPI_TYPE_THERMAL, ACPI_TYPE_THERMAL,
ACPI_TYPE_BUFFER_FIELD, ACPI_TYPE_BUFFER_FIELD,
ACPI_TYPE_DDB_HANDLE,
ACPI_TYPE_DEBUG_OBJECT,
ACPI_TYPE_LOCAL_REFERENCE = 0x14 ACPI_TYPE_LOCAL_REFERENCE = 0x14
}; };
@@ -123,6 +126,23 @@ enum {
ACPI_ALLOCATE_BUFFER = -1, ACPI_ALLOCATE_BUFFER = -1,
}; };
/*
* acpi_status should return ACPI specific error codes, not BeOS ones.
*/
typedef uint32 acpi_status;
#define AE_CODE_PROGRAMMER 0x1000
#define AE_OK 0x0000
#define AE_ERROR 0x0001
#define AE_NOT_ACQUIRED 0x0014
#define AE_NO_HARDWARE_RESPONSE 0x0016
#define AE_BAD_PARAMETER (0x0001 | AE_CODE_PROGRAMMER)
#define AE_BAD_ADDRESS (0x0009 | AE_CODE_PROGRAMMER)
#else
#error "Our ACPI.h uses different naming than actypes.h.\n" \\
"If you need actypes.h this probably needs updating."
#endif // __ACTYPES_H__ #endif // __ACTYPES_H__
@@ -146,11 +166,11 @@ typedef struct acpi_prt
typedef uint32 (*acpi_event_handler)(void *Context); typedef uint32 (*acpi_event_handler)(void *Context);
typedef status_t (*acpi_adr_space_handler)(uint32 function, typedef acpi_status (*acpi_adr_space_handler)(uint32 function,
acpi_physical_address address, uint32 bitWidth, int *value, acpi_physical_address address, uint32 bitWidth, int *value,
void *handlerContext, void *regionContext); void *handlerContext, void *regionContext);
typedef status_t (*acpi_adr_space_setup)(acpi_handle regionHandle, typedef acpi_status (*acpi_adr_space_setup)(acpi_handle regionHandle,
uint32 function, void *handlerContext, void **regionContext); uint32 function, void *handlerContext, void **regionContext);
typedef void (*acpi_notify_handler)(acpi_handle device, uint32 value, typedef void (*acpi_notify_handler)(acpi_handle device, uint32 value,
@@ -76,22 +76,22 @@ status_t
acpi_GetInteger(acpi_device_module_info* acpi, acpi_device& acpiCookie, acpi_GetInteger(acpi_device_module_info* acpi, acpi_device& acpiCookie,
const char* path, int* number) const char* path, int* number)
{ {
status_t status;
acpi_data buf; acpi_data buf;
acpi_object_type object; acpi_object_type object;
buf.pointer = &object; buf.pointer = &object;
buf.length = sizeof(acpi_object_type); buf.length = sizeof(acpi_object_type);
/* /*
* Assume that what we've been pointed at is an Integer object, or * Assume that what we've been pointed at is an Integer object, or
* a method that will return an Integer. * a method that will return an Integer.
*/ */
status = acpi->evaluate_method(acpiCookie, path, NULL, &buf); status_t status = acpi->evaluate_method(acpiCookie, path, NULL, &buf);
if (status == B_OK) { if (status == B_OK) {
if (object.object_type == ACPI_TYPE_INTEGER) if (object.object_type == ACPI_TYPE_INTEGER)
*number = object.data.integer; *number = object.data.integer;
else else
status = B_ERROR; status = B_BAD_VALUE;
} }
return status; return status;
} }
@@ -99,69 +99,67 @@ acpi_GetInteger(acpi_device_module_info* acpi, acpi_device& acpiCookie,
acpi_handle acpi_handle
acpi_GetReference(acpi_module_info* acpi, acpi_handle scope, acpi_GetReference(acpi_module_info* acpi, acpi_handle scope,
acpi_object_type *obj) acpi_object_type* obj)
{ {
acpi_handle h;
if (obj == NULL) if (obj == NULL)
return (NULL); return NULL;
switch (obj->object_type) { switch (obj->object_type) {
case ACPI_TYPE_LOCAL_REFERENCE: case ACPI_TYPE_LOCAL_REFERENCE:
case ACPI_TYPE_ANY: case ACPI_TYPE_ANY:
h = obj->data.reference.handle; return obj->data.reference.handle;
break;
case ACPI_TYPE_STRING: case ACPI_TYPE_STRING:
{
/* /*
* The String object usually contains a fully-qualified path, so * The String object usually contains a fully-qualified path, so
* scope can be NULL. * scope can be NULL.
* *
* XXX This may not always be the case. * XXX This may not always be the case.
*/ */
if (acpi->get_handle(scope, obj->data.string.string, &h) != B_OK) acpi_handle handle;
h = NULL; if (acpi->get_handle(scope, obj->data.string.string, &handle)
break; == B_OK)
default: return handle;
h = NULL; }
break;
} }
return (h); return NULL;
} }
int status_t
acpi_PkgInt(acpi_object_type *res, int idx, int *dst) acpi_PkgInt(acpi_object_type* res, int idx, int* dst)
{ {
acpi_object_type *obj; acpi_object_type* obj = &res->data.package.objects[idx];
obj = &res->data.package.objects[idx];
if (obj == NULL || obj->object_type != ACPI_TYPE_INTEGER) if (obj == NULL || obj->object_type != ACPI_TYPE_INTEGER)
return (EINVAL); return B_BAD_VALUE;
*dst = obj->data.integer; *dst = obj->data.integer;
return (0); return B_OK;
} }
int status_t
acpi_PkgInt32(acpi_object_type *res, int idx, uint32 *dst) acpi_PkgInt32(acpi_object_type* res, int idx, uint32* dst)
{ {
int tmp; int tmp;
int error;
error = acpi_PkgInt(res, idx, &tmp); status_t status = acpi_PkgInt(res, idx, &tmp);
if (error == 0) if (status == B_OK)
*dst = (uint32)tmp; *dst = (uint32) tmp;
return (error); return status;
} }
static status_t static status_t
embedded_controller_open(void *initCookie, const char *path, int flags, void** cookie) embedded_controller_open(void* initCookie, const char* path, int flags,
void** cookie)
{ {
acpi_ec_cookie *device = (acpi_ec_cookie*)initCookie; acpi_ec_cookie* device = (acpi_ec_cookie*) initCookie;
*cookie = device; *cookie = device;
return B_OK; return B_OK;
@@ -176,14 +174,16 @@ embedded_controller_close(void* cookie)
static status_t static status_t
embedded_controller_read(void* _cookie, off_t position, void *buffer, size_t* numBytes) embedded_controller_read(void* _cookie, off_t position, void* buffer,
size_t* numBytes)
{ {
return B_IO_ERROR; return B_IO_ERROR;
} }
static status_t static status_t
embedded_controller_write(void* cookie, off_t position, const void* buffer, size_t* numBytes) embedded_controller_write(void* cookie, off_t position, const void* buffer,
size_t* numBytes)
{ {
return B_IO_ERROR; return B_IO_ERROR;
} }
@@ -225,17 +225,17 @@ acpi_get_type(device_node* dev)
static float static float
embedded_controller_support(device_node *dev) embedded_controller_support(device_node* dev)
{ {
static const char *ec_ids[] = { "PNP0C09", NULL }; static const char* ec_ids[] = { "PNP0C09", NULL };
/* Check that this is a device. */ /* Check that this is a device. */
if (acpi_get_type(dev) != ACPI_TYPE_DEVICE) if (acpi_get_type(dev) != ACPI_TYPE_DEVICE)
return 0.; return 0.0;
const char *name; const char* name;
if (gDeviceManager->get_attr_string(dev, ACPI_DEVICE_HID_ITEM, &name, if (gDeviceManager->get_attr_string(dev, ACPI_DEVICE_HID_ITEM, &name, false)
false) != B_OK || strcmp(name, ec_ids[0])) != B_OK || strcmp(name, ec_ids[0]))
return 0.0; return 0.0;
TRACE("supported device found %s\n", name); TRACE("supported device found %s\n", name);
@@ -244,7 +244,7 @@ embedded_controller_support(device_node *dev)
static status_t static status_t
embedded_controller_register_device(device_node *node) embedded_controller_register_device(device_node* node)
{ {
device_attr attrs[] = { device_attr attrs[] = {
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
@@ -258,7 +258,7 @@ embedded_controller_register_device(device_node *node)
static status_t static status_t
embedded_controller_init_driver(device_node *dev, void **_driverCookie) embedded_controller_init_driver(device_node* dev, void** _driverCookie)
{ {
TRACE("init driver\n"); TRACE("init driver\n");
// first get the cpu speed, needed to calculate a timeout // first get the cpu speed, needed to calculate a timeout
@@ -268,19 +268,18 @@ embedded_controller_init_driver(device_node *dev, void **_driverCookie)
return B_ERROR; return B_ERROR;
gHz = systemInfo.cpu_clock_speed; gHz = systemInfo.cpu_clock_speed;
acpi_ec_cookie *sc; acpi_ec_cookie* sc;
sc = (acpi_ec_cookie*)malloc(sizeof(acpi_ec_cookie)); sc = (acpi_ec_cookie*) malloc(sizeof(acpi_ec_cookie));
memset(sc, 0, sizeof(acpi_ec_cookie)); memset(sc, 0, sizeof(acpi_ec_cookie));
*_driverCookie = sc; *_driverCookie = sc;
sc->ec_dev = dev; sc->ec_dev = dev;
sc->ec_condition_var.Init(NULL, "ec condition variable"); sc->ec_condition_var.Init(NULL, "ec condition variable");
mutex_init(&sc->ec_lock, "ec lock");
device_node *parent; device_node* parent = gDeviceManager->get_parent_node(dev);
parent = gDeviceManager->get_parent_node(dev); gDeviceManager->get_driver(parent, (driver_module_info**)&sc->ec_acpi,
gDeviceManager->get_driver(parent, (driver_module_info **)&sc->ec_acpi, (void**) &sc->ec_handle);
(void **)&sc->ec_handle);
gDeviceManager->put_node(parent); gDeviceManager->put_node(parent);
SmallResourceData resourceData(sc->ec_acpi, sc->ec_handle, "_CRS"); SmallResourceData resourceData(sc->ec_acpi, sc->ec_handle, "_CRS");
@@ -290,19 +289,20 @@ embedded_controller_init_driver(device_node *dev, void **_driverCookie)
} }
io_port portData; io_port portData;
if (get_module(B_ACPI_MODULE_NAME, (module_info**)&sc->ec_acpi_module) != B_OK) if (get_module(B_ACPI_MODULE_NAME, (module_info**)&sc->ec_acpi_module)
!= B_OK)
return B_ERROR; return B_ERROR;
// DPC module // DPC module
if (gDPC == NULL && get_module(B_DPC_MODULE_NAME, if (gDPC == NULL && get_module(B_DPC_MODULE_NAME, (module_info**) &gDPC)
(module_info **)&gDPC) != B_OK) { != B_OK) {
dprintf("failed to get dpc module for os execution\n"); dprintf("failed to get dpc module for os execution\n");
return B_ERROR; return B_ERROR;
} }
if (gDPCHandle == NULL) { if (gDPCHandle == NULL) {
if (gDPC->new_dpc_queue(&gDPCHandle, "acpi_task", if (gDPC->new_dpc_queue(&gDPCHandle, "acpi_task", B_NORMAL_PRIORITY)
B_NORMAL_PRIORITY) != B_OK) { != B_OK) {
dprintf("failed to create os execution queue\n"); dprintf("failed to create os execution queue\n");
return B_ERROR; return B_ERROR;
} }
@@ -318,9 +318,8 @@ embedded_controller_init_driver(device_node *dev, void **_driverCookie)
* global lock value to see if we should acquire it when * global lock value to see if we should acquire it when
* accessing the EC. * accessing the EC.
*/ */
status_t status = acpi_GetInteger(sc->ec_acpi, sc->ec_handle, "_UID",
status_t status; &sc->ec_uid);
status = acpi_GetInteger(sc->ec_acpi, sc->ec_handle, "_UID", &sc->ec_uid);
if (status != B_OK) if (status != B_OK)
sc->ec_uid = 0; sc->ec_uid = 0;
status = acpi_GetInteger(sc->ec_acpi, sc->ec_handle, "_GLK", &sc->ec_glk); status = acpi_GetInteger(sc->ec_acpi, sc->ec_handle, "_GLK", &sc->ec_glk);
@@ -339,7 +338,7 @@ embedded_controller_init_driver(device_node *dev, void **_driverCookie)
} }
acpi_object_type* obj; acpi_object_type* obj;
obj = (acpi_object_type*)buf.pointer; obj = (acpi_object_type*) buf.pointer;
if (obj == NULL) if (obj == NULL)
goto error; goto error;
@@ -351,11 +350,10 @@ embedded_controller_init_driver(device_node *dev, void **_driverCookie)
case ACPI_TYPE_PACKAGE: case ACPI_TYPE_PACKAGE:
if (!ACPI_PKG_VALID(obj, 2)) if (!ACPI_PKG_VALID(obj, 2))
goto error; goto error;
sc->ec_gpehandle = sc->ec_gpehandle = acpi_GetReference(sc->ec_acpi_module, NULL,
acpi_GetReference(sc->ec_acpi_module, NULL,
&obj->data.package.objects[0]); &obj->data.package.objects[0]);
if (sc->ec_gpehandle == NULL || if (sc->ec_gpehandle == NULL
acpi_PkgInt32(obj, 1, (uint32*)&sc->ec_gpebit) != 0) || acpi_PkgInt32(obj, 1, (uint32*) &sc->ec_gpebit) != B_OK)
goto error; goto error;
break; break;
default: default:
@@ -388,9 +386,7 @@ embedded_controller_init_driver(device_node *dev, void **_driverCookie)
goto error; goto error;
} }
/* /* Install address space handler */
* Install address space handler
*/
TRACE("attaching address space handler\n"); TRACE("attaching address space handler\n");
status = sc->ec_acpi->install_address_space_handler(sc->ec_handle, status = sc->ec_acpi->install_address_space_handler(sc->ec_handle,
ACPI_ADR_SPACE_EC, &EcSpaceHandler, &EcSpaceSetup, sc); ACPI_ADR_SPACE_EC, &EcSpaceHandler, &EcSpaceSetup, sc);
@@ -413,7 +409,7 @@ embedded_controller_init_driver(device_node *dev, void **_driverCookie)
goto error; goto error;
} }
return (0); return 0;
error: error:
if (buf.pointer) if (buf.pointer)
@@ -424,14 +420,15 @@ error:
sc->ec_acpi->remove_address_space_handler(sc->ec_handle, ACPI_ADR_SPACE_EC, sc->ec_acpi->remove_address_space_handler(sc->ec_handle, ACPI_ADR_SPACE_EC,
EcSpaceHandler); EcSpaceHandler);
return (ENXIO); return ENXIO;
} }
static void static void
embedded_controller_uninit_driver(void *driverCookie) embedded_controller_uninit_driver(void* driverCookie)
{ {
acpi_ec_cookie* sc = (struct acpi_ec_cookie *)driverCookie; acpi_ec_cookie* sc = (struct acpi_ec_cookie*) driverCookie;
mutex_destroy(&sc->ec_lock);
free(sc); free(sc);
put_module(B_ACPI_MODULE_NAME); put_module(B_ACPI_MODULE_NAME);
put_module(B_DPC_MODULE_NAME); put_module(B_DPC_MODULE_NAME);
@@ -441,9 +438,9 @@ embedded_controller_uninit_driver(void *driverCookie)
static status_t static status_t
embedded_controller_register_child_devices(void *_cookie) embedded_controller_register_child_devices(void* _cookie)
{ {
device_node *node = ((acpi_ec_cookie*)_cookie)->ec_dev; device_node* node = ((acpi_ec_cookie*) _cookie)->ec_dev;
int pathID = gDeviceManager->create_id(ACPI_EC_PATHID_GENERATOR); int pathID = gDeviceManager->create_id(ACPI_EC_PATHID_GENERATOR);
if (pathID < 0) { if (pathID < 0) {
@@ -459,14 +456,14 @@ embedded_controller_register_child_devices(void *_cookie)
static status_t static status_t
embedded_controller_init_device(void *driverCookie, void **cookie) embedded_controller_init_device(void* driverCookie, void** cookie)
{ {
return B_ERROR; return B_ERROR;
} }
static void static void
embedded_controller_uninit_device(void *_cookie) embedded_controller_uninit_device(void* _cookie)
{ {
acpi_ec_cookie *device = (acpi_ec_cookie*)_cookie; acpi_ec_cookie *device = (acpi_ec_cookie*)_cookie;
free(device); free(device);
@@ -474,8 +471,8 @@ embedded_controller_uninit_device(void *_cookie)
module_dependency module_dependencies[] = { module_dependency module_dependencies[] = {
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **) &gDeviceManager },
{ B_PCI_MODULE_NAME, (module_info **)&gPCIManager}, { B_PCI_MODULE_NAME, (module_info **) &gPCIManager},
{} {}
}; };
@@ -521,25 +518,22 @@ struct device_module_info embedded_controller_device_module = {
}; };
module_info *modules[] = { module_info* modules[] = {
(module_info *)&embedded_controller_driver_module, (module_info*) &embedded_controller_driver_module,
(module_info *)&embedded_controller_device_module, (module_info*) &embedded_controller_device_module,
NULL NULL
}; };
static void static void
EcGpeQueryHandler(void *context) EcGpeQueryHandler(void* context)
{ {
struct acpi_ec_cookie *sc = (struct acpi_ec_cookie *)context; struct acpi_ec_cookie* sc = (struct acpi_ec_cookie*) context;
uint8 data;
status_t status;
char qxx[5];
ASSERT(context != NULL);//, ("EcGpeQueryHandler called with NULL")); ASSERT(context != NULL);//, ("EcGpeQueryHandler called with NULL"));
/* Serialize user access with EcSpaceHandler(). */ /* Serialize user access with EcSpaceHandler(). */
status = EcLock(sc); status_t status = EcLock(sc);
if (status != B_OK) { if (status != B_OK) {
TRACE("GpeQuery lock error.\n"); TRACE("GpeQuery lock error.\n");
return; return;
@@ -559,7 +553,7 @@ EcGpeQueryHandler(void *context)
TRACE("GPE query failed.\n"); TRACE("GPE query failed.\n");
return; return;
} }
data = EC_GET_DATA(sc); uint8 data = EC_GET_DATA(sc);
/* /*
* We have to unlock before running the _Qxx method below since that * We have to unlock before running the _Qxx method below since that
@@ -574,6 +568,7 @@ EcGpeQueryHandler(void *context)
return; return;
/* Evaluate _Qxx to respond to the controller. */ /* Evaluate _Qxx to respond to the controller. */
char qxx[5];
snprintf(qxx, sizeof(qxx), "_Q%02X", data); snprintf(qxx, sizeof(qxx), "_Q%02X", data);
AcpiUtStrupr(qxx); AcpiUtStrupr(qxx);
status = sc->ec_acpi->evaluate_method(sc->ec_handle, qxx, NULL, NULL); status = sc->ec_acpi->evaluate_method(sc->ec_handle, qxx, NULL, NULL);
@@ -582,16 +577,15 @@ EcGpeQueryHandler(void *context)
} }
} }
/* /*
* The GPE handler is called when IBE/OBF or SCI events occur. We are * The GPE handler is called when IBE/OBF or SCI events occur. We are
* called from an unknown lock context. * called from an unknown lock context.
*/ */
static uint32 static uint32
EcGpeHandler(void *context) EcGpeHandler(void* context)
{ {
struct acpi_ec_cookie *sc = (acpi_ec_cookie*)context; struct acpi_ec_cookie *sc = (acpi_ec_cookie*)context;
status_t status;
EC_STATUS EcStatus;
ASSERT(context != NULL);//, ("EcGpeHandler called with NULL")); ASSERT(context != NULL);//, ("EcGpeHandler called with NULL"));
TRACE("gpe handler start\n"); TRACE("gpe handler start\n");
@@ -604,26 +598,28 @@ EcGpeHandler(void *context)
*/ */
atomic_add(&sc->ec_gencount, 1); atomic_add(&sc->ec_gencount, 1);
sc->ec_condition_var.NotifyAll(); sc->ec_condition_var.NotifyAll();
/* /*
* If the EC_SCI bit of the status register is set, queue a query handler. * If the EC_SCI bit of the status register is set, queue a query handler.
* It will run the query and _Qxx method later, under the lock. * It will run the query and _Qxx method later, under the lock.
*/ */
EcStatus = EC_GET_CSR(sc); EC_STATUS EcStatus = EC_GET_CSR(sc);
if ((EcStatus & EC_EVENT_SCI) && !sc->ec_sci_pending) { if ((EcStatus & EC_EVENT_SCI) && !sc->ec_sci_pending) {
TRACE("gpe queueing query handler\n"); TRACE("gpe queueing query handler\n");
status = AcpiOsExecute(OSL_GPE_HANDLER, EcGpeQueryHandler, context); status_t status = AcpiOsExecute(OSL_GPE_HANDLER, EcGpeQueryHandler,
context);
if (status == B_OK) if (status == B_OK)
sc->ec_sci_pending = TRUE; sc->ec_sci_pending = TRUE;
else else
dprintf("EcGpeHandler: queuing GPE query handler failed\n"); dprintf("EcGpeHandler: queuing GPE query handler failed\n");
} }
return (0); return B_INVOKE_SCHEDULER;
} }
static status_t static acpi_status
EcSpaceSetup(acpi_handle region, uint32 function, void *context, EcSpaceSetup(acpi_handle region, uint32 function, void* context,
void **regionContext) void** regionContext)
{ {
/* /*
* If deactivating a region, always set the output to NULL. Otherwise, * If deactivating a region, always set the output to NULL. Otherwise,
@@ -634,93 +630,95 @@ EcSpaceSetup(acpi_handle region, uint32 function, void *context,
else else
*regionContext = context; *regionContext = context;
return B_OK; return AE_OK;
} }
static status_t static acpi_status
EcSpaceHandler(uint32 function, acpi_physical_address address, uint32 width, EcSpaceHandler(uint32 function, acpi_physical_address address, uint32 width,
int *value, void *context, void *regionContext) int* value, void* context, void* regionContext)
{ {
TRACE("enter EcSpaceHandler\n"); TRACE("enter EcSpaceHandler\n");
struct acpi_ec_cookie *sc = (struct acpi_ec_cookie *)context; struct acpi_ec_cookie* sc = (struct acpi_ec_cookie *) context;
status_t status; uint8 ecData;
uint8 ecAddr, ecData;
uint32 i;
if (width % 8 != 0 || value == NULL || context == NULL) if (width % 8 != 0 || value == NULL || context == NULL)
return B_BAD_VALUE; return AE_BAD_PARAMETER;
if (address + (width / 8) - 1 > 0xFF) if (address + (width / 8) - 1 > 0xFF)
return B_BAD_ADDRESS; return AE_BAD_ADDRESS;
if (function == ACPI_READ) if (function == ACPI_READ)
*value = 0; *value = 0;
ecAddr = address; uint8 ecAddr = address;
status = B_ERROR; acpi_status status = AE_ERROR;
/* /*
* If booting, check if we need to run the query handler. If so, we * If booting, check if we need to run the query handler. If so, we
* we call it directly here since our thread taskq is not active yet. * we call it directly here since our thread taskq is not active yet.
*/ */
/*if (cold || rebooting || sc->ec_suspending) { /*
if (cold || rebooting || sc->ec_suspending) {
if ((EC_GET_CSR(sc) & EC_EVENT_SCI)) { if ((EC_GET_CSR(sc) & EC_EVENT_SCI)) {
//CTR0(KTR_ACPI, "ec running gpe handler directly"); //CTR0(KTR_ACPI, "ec running gpe handler directly");
EcGpeQueryHandler(sc); EcGpeQueryHandler(sc);
} }
}*/ } */
/* Serialize with EcGpeQueryHandler() at transaction granularity. */ /* Serialize with EcGpeQueryHandler() at transaction granularity. */
status = EcLock(sc); status = EcLock(sc);
if (status != B_OK) if (status != B_OK)
return (status); return AE_NOT_ACQUIRED;
/* Perform the transaction(s), based on width. */ /* Perform the transaction(s), based on width. */
for (i = 0; i < width; i += 8, ecAddr++) { for (uint32 i = 0; i < width; i += 8, ecAddr++) {
switch (function) { switch (function) {
case ACPI_READ: case ACPI_READ:
status = EcRead(sc, ecAddr, &ecData); status = EcRead(sc, ecAddr, &ecData);
if (status == B_OK) if (status == AE_OK)
*value |= ((int)ecData) << i; *value |= ((int) ecData) << i;
break; break;
case ACPI_WRITE: case ACPI_WRITE:
ecData = (uint8)((*value) >> i); ecData = (uint8) ((*value) >> i);
status = EcWrite(sc, ecAddr, &ecData); status = EcWrite(sc, ecAddr, &ecData);
break; break;
default: default:
TRACE("invalid EcSpaceHandler function\n"); TRACE("invalid EcSpaceHandler function\n");
status = B_BAD_VALUE; status = AE_BAD_PARAMETER;
break; break;
} }
if (status != B_OK) if (status != AE_OK) {
break; break;
} }
}
EcUnlock(sc); EcUnlock(sc);
return (status); return status;
} }
static status_t
EcCheckStatus(struct acpi_ec_cookie *sc, const char *msg, EC_EVENT event)
{
status_t status = B_ERROR;
EC_STATUS ec_status;
ec_status = EC_GET_CSR(sc); static acpi_status
EcCheckStatus(struct acpi_ec_cookie* sc, const char* msg, EC_EVENT event)
{
acpi_status status = AE_NO_HARDWARE_RESPONSE;
EC_STATUS ec_status = EC_GET_CSR(sc);
if (sc->ec_burstactive && !(ec_status & EC_FLAG_BURST_MODE)) { if (sc->ec_burstactive && !(ec_status & EC_FLAG_BURST_MODE)) {
TRACE("burst disabled in waitevent (%s)\n", msg); TRACE("burst disabled in waitevent (%s)\n", msg);
sc->ec_burstactive = false; sc->ec_burstactive = false;
} }
if (EVENT_READY(event, ec_status)) { if (EVENT_READY(event, ec_status)) {
TRACE("%s wait ready, status %#x\n", msg, ec_status); TRACE("%s wait ready, status %#x\n", msg, ec_status);
status = B_OK; status = AE_OK;
} }
return (status); return status;
} }
static status_t
EcWaitEvent(struct acpi_ec_cookie *sc, EC_EVENT event, int32 gen_count) static acpi_status
EcWaitEvent(struct acpi_ec_cookie* sc, EC_EVENT event, int32 gen_count)
{ {
status_t status = B_ERROR; acpi_status status = AE_NO_HARDWARE_RESPONSE;
int32 count, i; int32 count, i;
// int need_poll = cold || rebooting || ec_polled_mode || sc->ec_suspending; // int need_poll = cold || rebooting || ec_polled_mode || sc->ec_suspending;
@@ -789,7 +787,7 @@ EcWaitEvent(struct acpi_ec_cookie *sc, EC_EVENT event, int32 gen_count)
*/ */
gen_count = sc->ec_gencount; gen_count = sc->ec_gencount;
status = EcCheckStatus(sc, "sleep", event); status = EcCheckStatus(sc, "sleep", event);
if (status == B_OK) if (status == AE_OK)
break; break;
} }
sc->ec_condition_var.Wait(B_RELATIVE_TIMEOUT, slp_ival); sc->ec_condition_var.Wait(B_RELATIVE_TIMEOUT, slp_ival);
@@ -801,32 +799,29 @@ EcWaitEvent(struct acpi_ec_cookie *sc, EC_EVENT event, int32 gen_count)
* the best we can do at this point. Then, force polled mode on * the best we can do at this point. Then, force polled mode on
* since this system doesn't appear to generate GPEs. * since this system doesn't appear to generate GPEs.
*/ */
if (status != B_OK) { if (status != AE_OK) {
status = EcCheckStatus(sc, "sleep_end", event); status = EcCheckStatus(sc, "sleep_end", event);
TRACE("wait timed out (%sresponse), forcing polled mode\n", TRACE("wait timed out (%sresponse), forcing polled mode\n",
status == B_OK ? "" : "no "); status == B_OK ? "" : "no ");
ec_polled_mode = TRUE; ec_polled_mode = TRUE;
} }
} }
if (status != B_OK) if (status != AE_OK)
TRACE("error: ec wait timed out\n"); TRACE("error: ec wait timed out\n");
return (status); return status;
} }
static status_t
EcCommand(struct acpi_ec_cookie *sc, EC_COMMAND cmd)
{
status_t status;
EC_EVENT event;
EC_STATUS ec_status;
u_int gen_count;
static acpi_status
EcCommand(struct acpi_ec_cookie* sc, EC_COMMAND cmd)
{
/* Don't use burst mode if user disabled it. */ /* Don't use burst mode if user disabled it. */
if (!ec_burst_mode && cmd == EC_COMMAND_BURST_ENABLE) if (!ec_burst_mode && cmd == EC_COMMAND_BURST_ENABLE)
return (B_ERROR); return AE_ERROR;
/* Decide what to wait for based on command type. */ /* Decide what to wait for based on command type. */
EC_EVENT event;
switch (cmd) { switch (cmd) {
case EC_COMMAND_READ: case EC_COMMAND_READ:
case EC_COMMAND_WRITE: case EC_COMMAND_WRITE:
@@ -839,40 +834,37 @@ EcCommand(struct acpi_ec_cookie *sc, EC_COMMAND cmd)
break; break;
default: default:
TRACE("EcCommand: invalid command %#x\n", cmd); TRACE("EcCommand: invalid command %#x\n", cmd);
return (B_BAD_VALUE); return AE_BAD_PARAMETER;
} }
/* Run the command and wait for the chosen event. */ /* Run the command and wait for the chosen event. */
TRACE("running command %#x\n", cmd); TRACE("running command %#x\n", cmd);
gen_count = sc->ec_gencount; u_int gen_count = sc->ec_gencount;
EC_SET_CSR(sc, cmd); EC_SET_CSR(sc, cmd);
status = EcWaitEvent(sc, event, gen_count); acpi_status status = EcWaitEvent(sc, event, gen_count);
if (status == B_OK) { if (status == AE_OK) {
/* If we succeeded, burst flag should now be present. */ /* If we succeeded, burst flag should now be present. */
if (cmd == EC_COMMAND_BURST_ENABLE) { if (cmd == EC_COMMAND_BURST_ENABLE) {
ec_status = EC_GET_CSR(sc); EC_STATUS ec_status = EC_GET_CSR(sc);
if ((ec_status & EC_FLAG_BURST_MODE) == 0) if ((ec_status & EC_FLAG_BURST_MODE) == 0)
status = B_ERROR; status = AE_ERROR;
} }
} else } else
TRACE("EcCommand: no response to %#x\n", cmd); TRACE("EcCommand: no response to %#x\n", cmd);
return (status); return status;
} }
static status_t
EcRead(struct acpi_ec_cookie *sc, uint8 address, uint8 *readData)
{
status_t status;
uint8 data;
u_int gen_count;
static acpi_status
EcRead(struct acpi_ec_cookie* sc, uint8 address, uint8* readData)
{
TRACE("read from %#x\n", address); TRACE("read from %#x\n", address);
/* If we can't start burst mode, continue anyway. */ /* If we can't start burst mode, continue anyway. */
status = EcCommand(sc, EC_COMMAND_BURST_ENABLE); acpi_status status = EcCommand(sc, EC_COMMAND_BURST_ENABLE);
if (status == B_OK) { if (status == AE_OK) {
data = EC_GET_DATA(sc); uint8 data = EC_GET_DATA(sc);
if (data == EC_BURST_ACK) { if (data == EC_BURST_ACK) {
TRACE("burst enabled\n"); TRACE("burst enabled\n");
sc->ec_burstactive = TRUE; sc->ec_burstactive = TRUE;
@@ -880,41 +872,38 @@ EcRead(struct acpi_ec_cookie *sc, uint8 address, uint8 *readData)
} }
status = EcCommand(sc, EC_COMMAND_READ); status = EcCommand(sc, EC_COMMAND_READ);
if (status != B_OK) if (status != AE_OK)
return (status); return status;
gen_count = sc->ec_gencount; u_int gen_count = sc->ec_gencount;
EC_SET_DATA(sc, address); EC_SET_DATA(sc, address);
status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL, gen_count); status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL, gen_count);
if (status != B_OK) { if (status != AE_OK) {
TRACE("EcRead: failed waiting to get data\n"); TRACE("EcRead: failed waiting to get data\n");
return (status); return status;
} }
*readData = EC_GET_DATA(sc); *readData = EC_GET_DATA(sc);
if (sc->ec_burstactive) { if (sc->ec_burstactive) {
sc->ec_burstactive = FALSE; sc->ec_burstactive = FALSE;
status = EcCommand(sc, EC_COMMAND_BURST_DISABLE); status = EcCommand(sc, EC_COMMAND_BURST_DISABLE);
if (status != B_OK) if (status != AE_OK)
return (status); return status;
TRACE("disabled burst ok\n"); TRACE("disabled burst ok\n");
} }
return (B_OK); return AE_OK;
} }
static status_t
EcWrite(struct acpi_ec_cookie *sc, uint8 address, uint8 *writeData)
{
status_t status;
uint8 data;
u_int gen_count;
static acpi_status
EcWrite(struct acpi_ec_cookie* sc, uint8 address, uint8* writeData)
{
/* If we can't start burst mode, continue anyway. */ /* If we can't start burst mode, continue anyway. */
status = EcCommand(sc, EC_COMMAND_BURST_ENABLE); acpi_status status = EcCommand(sc, EC_COMMAND_BURST_ENABLE);
if (status == B_OK) { if (status == AE_OK) {
data = EC_GET_DATA(sc); uint8 data = EC_GET_DATA(sc);
if (data == EC_BURST_ACK) { if (data == EC_BURST_ACK) {
TRACE("burst enabled\n"); TRACE("burst enabled\n");
sc->ec_burstactive = TRUE; sc->ec_burstactive = TRUE;
@@ -922,33 +911,32 @@ EcWrite(struct acpi_ec_cookie *sc, uint8 address, uint8 *writeData)
} }
status = EcCommand(sc, EC_COMMAND_WRITE); status = EcCommand(sc, EC_COMMAND_WRITE);
if (status != B_OK) if (status != AE_OK)
return (status); return status;
gen_count = sc->ec_gencount; u_int gen_count = sc->ec_gencount;
EC_SET_DATA(sc, address); EC_SET_DATA(sc, address);
status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, gen_count); status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, gen_count);
if (status != B_OK) { if (status != AE_OK) {
TRACE("EcRead: failed waiting for sent address\n"); TRACE("EcRead: failed waiting for sent address\n");
return (status); return status;
} }
gen_count = sc->ec_gencount; gen_count = sc->ec_gencount;
EC_SET_DATA(sc, *writeData); EC_SET_DATA(sc, *writeData);
status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, gen_count); status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, gen_count);
if (status != B_OK) { if (status != AE_OK) {
TRACE("EcWrite: failed waiting for sent data\n"); TRACE("EcWrite: failed waiting for sent data\n");
return (status); return status;
} }
if (sc->ec_burstactive) { if (sc->ec_burstactive) {
sc->ec_burstactive = FALSE; sc->ec_burstactive = FALSE;
status = EcCommand(sc, EC_COMMAND_BURST_DISABLE); status = EcCommand(sc, EC_COMMAND_BURST_DISABLE);
if (status != B_OK) if (status != AE_OK)
return (status); return (status);
TRACE("disabled burst ok\n"); TRACE("disabled burst ok\n");
} }
return (B_OK); return AE_OK;
} }
@@ -36,7 +36,7 @@
#include <dpc.h> #include <dpc.h>
#include <Drivers.h> #include <Drivers.h>
#include <KernelExport.h> #include <KernelExport.h>
#include <lock.h>
// #define TRACE_EMBEDDED_CONTROLLER // #define TRACE_EMBEDDED_CONTROLLER
#ifdef TRACE_EMBEDDED_CONTROLLER #ifdef TRACE_EMBEDDED_CONTROLLER
@@ -117,6 +117,7 @@ AcpiUtStrupr(char *SrcString)
#define ACPI_READ 0 #define ACPI_READ 0
#define ACPI_WRITE 1 #define ACPI_WRITE 1
typedef uint8 EC_COMMAND;
#define EC_COMMAND_UNKNOWN ((EC_COMMAND) 0x00) #define EC_COMMAND_UNKNOWN ((EC_COMMAND) 0x00)
#define EC_COMMAND_READ ((EC_COMMAND) 0x80) #define EC_COMMAND_READ ((EC_COMMAND) 0x80)
@@ -148,32 +149,26 @@ AcpiUtStrupr(char *SrcString)
typedef uint8 EC_STATUS; typedef uint8 EC_STATUS;
#define EC_FLAG_OUTPUT_BUFFER ((uint8) 0x01) #define EC_FLAG_OUTPUT_BUFFER ((EC_STATUS) 0x01)
#define EC_FLAG_INPUT_BUFFER ((uint8) 0x02) #define EC_FLAG_INPUT_BUFFER ((EC_STATUS) 0x02)
#define EC_FLAG_DATA_IS_CMD ((uint8) 0x08) #define EC_FLAG_DATA_IS_CMD ((EC_STATUS) 0x08)
#define EC_FLAG_BURST_MODE ((uint8) 0x10) #define EC_FLAG_BURST_MODE ((EC_STATUS) 0x10)
/* /*
* EC_EVENT: * EC_EVENT:
* --------- * ---------
*/ */
typedef uint8 EC_EVENT;
#define EC_EVENT_UNKNOWN ((uint8) 0x00) #define EC_EVENT_UNKNOWN ((EC_EVENT) 0x00)
#define EC_EVENT_OUTPUT_BUFFER_FULL ((uint8) 0x01) #define EC_EVENT_OUTPUT_BUFFER_FULL ((EC_EVENT) 0x01)
#define EC_EVENT_INPUT_BUFFER_EMPTY ((uint8) 0x02) #define EC_EVENT_INPUT_BUFFER_EMPTY ((EC_EVENT) 0x02)
#define EC_EVENT_SCI ((uint8) 0x20) #define EC_EVENT_SCI ((EC_EVENT) 0x20)
#define EC_EVENT_SMI ((uint8) 0x40) #define EC_EVENT_SMI ((EC_EVENT) 0x40)
/* Data byte returned after burst enable indicating it was successful. */ /* Data byte returned after burst enable indicating it was successful. */
#define EC_BURST_ACK 0x90 #define EC_BURST_ACK 0x90
/* Total time in ms spent waiting for a response from EC. */
#define EC_TIMEOUT 750
static int ec_burst_mode = 1;
static int ec_polled_mode = 0;
static int ec_timeout = EC_TIMEOUT;
/* /*
* Register access primitives * Register access primitives
@@ -214,6 +209,7 @@ struct acpi_ec_cookie {
int ec_glk; int ec_glk;
uint32 ec_glkhandle; uint32 ec_glkhandle;
mutex ec_lock;
int ec_burstactive; int ec_burstactive;
int ec_sci_pending; int ec_sci_pending;
vint32 ec_gencount; vint32 ec_gencount;
@@ -243,11 +239,17 @@ struct acpi_ec_cookie {
((status) & EC_FLAG_INPUT_BUFFER) == 0)) ((status) & EC_FLAG_INPUT_BUFFER) == 0))
static int ec_burst_mode = 1;
static int ec_polled_mode = 0;
static int ec_timeout = EC_TIMEOUT;
static status_t static status_t
EcLock(struct acpi_ec_cookie *sc) EcLock(struct acpi_ec_cookie *sc)
{ {
status_t status; status_t status;
/* If _GLK is non-zero, acquire the global lock. */ /* If _GLK is non-zero, acquire the global lock. */
status = B_OK; status = B_OK;
if (sc->ec_glk) { if (sc->ec_glk) {
@@ -256,7 +258,7 @@ EcLock(struct acpi_ec_cookie *sc)
if (status != B_OK) if (status != B_OK)
return status; return status;
} }
mutex_lock(&sc->ec_lock);
return status; return status;
} }
@@ -264,26 +266,26 @@ EcLock(struct acpi_ec_cookie *sc)
static void static void
EcUnlock(struct acpi_ec_cookie *sc) EcUnlock(struct acpi_ec_cookie *sc)
{ {
mutex_unlock(&sc->ec_lock);
if (sc->ec_glk) if (sc->ec_glk)
sc->ec_acpi_module->release_global_lock(sc->ec_glkhandle); sc->ec_acpi_module->release_global_lock(sc->ec_glkhandle);
} }
typedef unsigned int EC_EVENT;
typedef unsigned int EC_COMMAND;
static uint32 EcGpeHandler(void *context); static uint32 EcGpeHandler(void *context);
static status_t EcSpaceSetup(acpi_handle region, uint32 function,
static acpi_status EcSpaceSetup(acpi_handle region, uint32 function,
void *context, void **return_Context); void *context, void **return_Context);
static status_t EcSpaceHandler(uint32 function, static acpi_status EcSpaceHandler(uint32 function,
acpi_physical_address address, acpi_physical_address address,
uint32 width, int *value, uint32 width, int *value,
void *context, void *regionContext); void *context, void *regionContext);
static status_t EcWaitEvent(struct acpi_ec_cookie *sc, EC_EVENT event, static acpi_status EcWaitEvent(struct acpi_ec_cookie *sc, EC_EVENT event,
int32 gen_count); int32 gen_count);
static status_t EcCommand(struct acpi_ec_cookie *sc, EC_COMMAND cmd); static acpi_status EcCommand(struct acpi_ec_cookie *sc, EC_COMMAND cmd);
static status_t EcRead(struct acpi_ec_cookie *sc, uint8 address, static acpi_status EcRead(struct acpi_ec_cookie *sc, uint8 address,
uint8 *readData); uint8 *readData);
static status_t EcWrite(struct acpi_ec_cookie *sc, uint8 address, static acpi_status EcWrite(struct acpi_ec_cookie *sc, uint8 address,
uint8 *writeData); uint8 *writeData);