#include <Drivers.h>
#include <OS.h>
#include <bus_manager.h>
#include <malloc.h>
#include <module.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioccom.h>
#include <sys/ioctl.h>
#define __KERNEL__
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#define copy_from_user memcpy
#define copy_to_user memcpy
#define CardServices gPcmciaCs->_CardServices
#define get_handle gPcmciaDs->get_handle
const char sockname[] = "bus/pcmcia/sock/%ld";
static char ** devices;
uint32 devices_count = 0;
int32 api_version = B_CUR_DRIVER_API_VERSION;
cs_client_module_info *gPcmciaCs;
ds_module_info *gPcmciaDs;
static status_t
ds_open(const char *name, uint32 flags, void **_cookie)
{
int32 socket = -1;
int32 i;
*_cookie = NULL;
for (i=0; i<devices_count; i++) {
if (strcmp(name, devices[i]) == 0) {
socket = i;
break;
}
}
if (socket < 0) {
return B_BAD_VALUE;
}
if (get_handle(socket, (client_handle_t *)_cookie) != B_OK) {
return ENODEV;
}
return B_OK;
}
static status_t
ds_close(void *cookie)
{
return B_OK;
}
static status_t
ds_free(void *cookie)
{
return B_OK;
}
static status_t
ds_read(void *cookie, off_t position, void *data, size_t *numBytes)
{
return B_ERROR;
}
static status_t
ds_write(void *cookie, off_t position, const void *data, size_t *numBytes)
{
return B_ERROR;
}
static status_t
ds_ioctl(void *cookie, uint32 cmd, void *arg, size_t len)
{
client_handle_t h = (client_handle_t) cookie;
u_int size = IOCPARM_LEN(cmd);
status_t ret, err;
ds_ioctl_arg_t buf;
if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
err = ret = 0;
if (cmd & IOC_IN) copy_from_user((char *)&buf, (char *)arg, size);
switch (cmd) {
case DS_ADJUST_RESOURCE_INFO:
ret = CardServices(AdjustResourceInfo, h, &buf.adjust);
break;
case DS_GET_CARD_SERVICES_INFO:
ret = CardServices(GetCardServicesInfo, &buf.servinfo);
break;
case DS_GET_CONFIGURATION_INFO:
ret = CardServices(GetConfigurationInfo, h, &buf.config);
break;
case DS_GET_FIRST_TUPLE:
ret = CardServices(GetFirstTuple, h, &buf.tuple);
break;
case DS_GET_NEXT_TUPLE:
ret = CardServices(GetNextTuple, h, &buf.tuple);
break;
case DS_GET_TUPLE_DATA:
buf.tuple.TupleData = buf.tuple_parse.data;
buf.tuple.TupleDataMax = sizeof(buf.tuple_parse.data);
ret = CardServices(GetTupleData, h, &buf.tuple);
break;
case DS_PARSE_TUPLE:
buf.tuple.TupleData = buf.tuple_parse.data;
ret = CardServices(ParseTuple, h, &buf.tuple,
&buf.tuple_parse.parse);
break;
case DS_RESET_CARD:
ret = CardServices(ResetCard, h, NULL);
break;
case DS_GET_STATUS:
ret = CardServices(GetStatus, h, &buf.status);
break;
case DS_VALIDATE_CIS:
ret = CardServices(ValidateCIS, h, &buf.cisinfo);
break;
case DS_SUSPEND_CARD:
ret = CardServices(SuspendCard, h, NULL);
break;
case DS_RESUME_CARD:
ret = CardServices(ResumeCard, h, NULL);
break;
case DS_EJECT_CARD:
ret = CardServices(EjectCard, h, NULL);
break;
case DS_INSERT_CARD:
ret = CardServices(InsertCard, h, NULL);
break;
case DS_REPLACE_CIS:
ret = CardServices(ReplaceCIS, h, &buf.cisdump);
break;
default:
err = -EINVAL;
}
if ((err == 0) && (ret != CS_SUCCESS)) {
switch (ret) {
case CS_BAD_SOCKET: case CS_NO_CARD:
err = ENODEV; break;
case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
case CS_BAD_TUPLE:
err = EINVAL; break;
case CS_IN_USE:
err = EBUSY; break;
case CS_OUT_OF_RESOURCE:
err = ENOSPC; break;
case CS_NO_MORE_ITEMS:
err = ENODATA; break;
case CS_UNSUPPORTED_FUNCTION:
err = ENOSYS; break;
default:
err = EIO; break;
}
}
if (cmd & IOC_OUT) copy_to_user((char *)arg, (char *)&buf, size);
return err;
}
status_t
init_hardware()
{
return B_OK;
}
const char **
publish_devices(void)
{
return (const char **)devices;
}
static device_hooks hooks = {
&ds_open,
&ds_close,
&ds_free,
&ds_ioctl,
&ds_read,
&ds_write,
NULL,
NULL,
NULL,
NULL
};
device_hooks *
find_device(const char *name)
{
return &hooks;
}
status_t
init_driver()
{
status_t err;
client_handle_t handle;
uint32 i;
#if DEBUG && !defined(__HAIKU__)
load_driver_symbols("ds");
#endif
if ((err = get_module(CS_CLIENT_MODULE_NAME, (module_info **)&gPcmciaCs))!=B_OK)
return err;
if ((err = get_module(DS_MODULE_NAME, (module_info **)&gPcmciaDs))!=B_OK) {
put_module(CS_CLIENT_MODULE_NAME);
return err;
}
devices_count = 0;
while (get_handle(devices_count, &handle)==B_OK) {
devices_count++;
}
if (devices_count <= 0) {
put_module(CS_CLIENT_MODULE_NAME);
put_module(DS_MODULE_NAME);
return ENODEV;
}
devices = malloc(sizeof(char *) * (devices_count+1));
if (!devices) {
put_module(CS_CLIENT_MODULE_NAME);
put_module(DS_MODULE_NAME);
return ENOMEM;
}
for (i=0; i<devices_count; i++) {
devices[i] = strdup(sockname);
sprintf(devices[i], sockname, i);
}
devices[devices_count] = NULL;
return B_OK;
}
void
uninit_driver()
{
int32 i = 0;
for (i=0; i<devices_count; i++) {
free (devices[i]);
}
free(devices);
devices = NULL;
put_module(DS_MODULE_NAME);
put_module(CS_CLIENT_MODULE_NAME);
}