kvisc/vm/pc/device.c

161 lines
2.7 KiB
C

// The OS/K Team licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#include <pc/device.h>
//----------------------------------------------------------------------------//
//
// Add new builtin devices here
//
extern dev_t cpudev, memdev, clockdev, keybdev, diskdev;
static dev_t *arch_d[] =
{
&cpudev, // 0
&memdev, // 1
&clockdev, // 2
&keybdev, // 3
&diskdev, // 4
NULL,
};
int devinitall(void)
{
size_t it;
for (it = 0; arch_d[it] != NULL; it++) {
// trace("Adding device %s\n", arch_d[it]->name);
if (devinit(arch_d[it]) < 0)
return -1;
}
return 0;
}
int devfiniall(void)
{
int failed = 0;
while (ctx->dh)
if (devfini(ctx->dh) < 0)
failed = -1;
return failed;
}
//----------------------------------------------------------------------------//
dev_t *devalloc(void)
{
return calloc(sizeof(dev_t)/sizeof(ulong), sizeof(ulong));
}
void devfree(dev_t *dev)
{
assert(dev != NULL);
free(dev);
}
//----------------------------------------------------------------------------//
dev_t *devget(int idx)
{
if (idx < 0)
return NULL;
int i;
dev_t *dev;
for (i = 0, dev = ctx->dh; dev && i != idx; dev = dev->next, i++);
return dev;
}
void devattach(dev_t *dev)
{
dev_t *it;
assert(dev != NULL);
if (ctx->dh) {
for (it = ctx->dh; it->next != NULL; it = it->next);
it->next = dev;
}
else ctx->dh = dev;
}
int devinit(dev_t *dev)
{
if (!dev || dev->state != DEVPWOF)
return -1;
if (dev->fpwon)
dev->fpwon(dev);
else dev->state = DEVGOOD;
if (!(dev->state == DEVPLUG || dev->state == DEVGOOD))
return -1;
dev->id = random();
devattach(dev);
return 0;
}
//----------------------------------------------------------------------------//
// NEVER detach while some assembly code
// may still be running on the vm!
void devdetach(dev_t *dev)
{
dev_t *it;
assert(dev != NULL);
if (dev == ctx->dh) {
ctx->dh = dev->next;
}
for (it = ctx->dh; it; it = it->next) {
if (!it)
break;
if (it->next == dev) {
it->next = dev->next;
break;
}
}
}
int devfini(dev_t *dev)
{
if (dev->state == DEVPWOF || dev->state == DEVFERR) {
goto err;
}
if (dev->fpwoff)
dev->fpwoff(dev);
else dev->state = DEVPWOF;
if (dev->state != DEVPWOF)
goto err;
devdetach(dev);
return 0;
err:
devdetach(dev);
return -1;
}