diff options
Diffstat (limited to 'mdk-stage1/pcmcia/startup.c')
| -rw-r--r-- | mdk-stage1/pcmcia/startup.c | 271 | 
1 files changed, 271 insertions, 0 deletions
| diff --git a/mdk-stage1/pcmcia/startup.c b/mdk-stage1/pcmcia/startup.c new file mode 100644 index 000000000..e9004484a --- /dev/null +++ b/mdk-stage1/pcmcia/startup.c @@ -0,0 +1,271 @@ +/* + * Startup tool for non statically mapped PCMCIA sockets + * + * (C) 2005		Dominik Brodowski <linux@brodo.de> + * + *  The initial developer of the original code is David A. Hinds + *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds + *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved. + * + * License: GPL v2 + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <syslog.h> +#include <unistd.h> + +#include <sysfs/libsysfs.h> + +#include "startup.h" + +/* uncomment for debug output */ +#ifdef DEBUG +#define dprintf printf +#else +#define dprintf(...) do { } while(0); +#endif + +/* Linked list of resource adjustments */ +struct adjust_list_t *root_adjust = NULL; + +/* path for config file, device scripts */ +static char *configpath = "/etc/pcmcia"; + +enum { +        RESOURCE_MEM, +        RESOURCE_IO, +        MAX_RESOURCE_FILES +}; + + +static const char *resource_files[MAX_RESOURCE_FILES] = { +	[RESOURCE_MEM]	= "available_resources_mem", +	[RESOURCE_IO]	= "available_resources_io", +}; + +#define PATH_TO_SOCKET "/sys/class/pcmcia_socket/" + + +static int add_available_resource(unsigned int socket_no, unsigned int type, +				  unsigned int action, +				  unsigned long start, unsigned long end) +{ +	char file[SYSFS_PATH_MAX]; +	char content[SYSFS_PATH_MAX]; +	struct sysfs_attribute *attr; +	int ret; +	size_t len; + +	if (type >= MAX_RESOURCE_FILES) +		return -EINVAL; + +	if (end <= start) +		return -EINVAL; + +	dprintf("%d %d %d 0x%lx 0x%lx\n", socket_no, type, action, start, end); + +	snprintf(file, SYSFS_PATH_MAX, PATH_TO_SOCKET "pcmcia_socket%u/%s", +		socket_no, resource_files[type]); + +	switch(action) { +	case ADD_MANAGED_RESOURCE: +		len = snprintf(content, SYSFS_PATH_MAX, +			       "0x%08lx - 0x%08lx", start, end); +		break; + +	case REMOVE_MANAGED_RESOURCE: +		len = snprintf(content, SYSFS_PATH_MAX, +			       "- 0x%08lx - 0x%08lx", start, end); +		break; + +	default: +		return -EINVAL; +	} + +	dprintf("content is %s\n", content); + +	dprintf("file is %s\n", file); + +	attr = sysfs_open_attribute(file); +	if (!attr) +		return -ENODEV; + +	dprintf("open, len %d\n", len); + +	ret = sysfs_write_attribute(attr, content, len); + +	dprintf("ret is %d\n", ret); + +	sysfs_close_attribute(attr); + +	return (ret); +} + +static int setup_done(unsigned int socket_no) +{ +	int ret; +	char file[SYSFS_PATH_MAX]; +	struct sysfs_attribute *attr; + +	snprintf(file, SYSFS_PATH_MAX, PATH_TO_SOCKET +		 "pcmcia_socket%u/available_resources_setup_done", +		 socket_no); + +	attr = sysfs_open_attribute(file); +	if (!attr) +		return -ENODEV; + +	ret = sysfs_write_attribute(attr, "42", 2); + +	sysfs_close_attribute(attr); + +	return (ret); +} + + +static int disallow_irq(unsigned int socket_no, unsigned int irq) +{ +	char file[SYSFS_PATH_MAX]; +	char content[SYSFS_PATH_MAX]; +	struct sysfs_attribute *attr; +	unsigned int mask = 0xfff; +	unsigned int new_mask; +	int ret; +	size_t len; + +	if (irq >= 32) +		return -EINVAL; + +	len = snprintf(file, SYSFS_PATH_MAX, PATH_TO_SOCKET +		 "pcmcia_socket%u/card_irq_mask", +		 socket_no); +	dprintf("file is %s\n", file); + +	attr = sysfs_open_attribute(file); +	if (!attr) +		return -ENODEV; + +	dprintf("open, len %d\n", len); + +	ret = sysfs_read_attribute(attr); +	if (ret) { +		ret = -EINVAL; +		goto out; +	} + +	if (!attr->value || (attr->len < 6)) { +		ret = -EIO; +		goto out; +	} + +	ret = sscanf(attr->value, "0x%x\n", &mask); + +	new_mask = 1 << irq; + +	mask &= ~new_mask; + +	len = snprintf(content, SYSFS_PATH_MAX, "0x%04x", mask); + +	dprintf("content is %s\n", content); + +	ret = sysfs_write_attribute(attr, content, len); + + out: +	sysfs_close_attribute(attr); + +	return (ret); +} + + +static void load_config(void) +{ +    if (chdir(configpath) != 0) { +	syslog(LOG_ERR, "chdir to %s failed: %m", configpath); +	exit(EXIT_FAILURE); +    } +    parse_configfile("config.opts"); +    return; +} + + +static void adjust_resources(unsigned int socket_no) +{ +    adjust_list_t *al; + +    for (al = root_adjust; al; al = al->next) { +	    switch (al->adj.Resource) { +	    case RES_MEMORY_RANGE: +		    add_available_resource(socket_no, RESOURCE_MEM, +					   al->adj.Action, +					   al->adj.resource.memory.Base, +					   al->adj.resource.memory.Base + +					   al->adj.resource.memory.Size - 1); +		    break; +	    case RES_IO_RANGE: +		    add_available_resource(socket_no, RESOURCE_IO, +					   al->adj.Action, +					   al->adj.resource.io.BasePort, +					   al->adj.resource.io.BasePort + +					   al->adj.resource.io.NumPorts - 1); +		    break; +	    case RES_IRQ: +		    if(al->adj.Action == REMOVE_MANAGED_RESOURCE) +			    disallow_irq(socket_no, al->adj.resource.irq.IRQ); +		    break; +	    } +    } +} + +/* mdk-stage1 +int main(int argc, char *argv[]) +{ +	char *socket_no; +	unsigned long socket, i; +	unsigned int all_sockets = 0; + + +	if ((socket_no = getenv("SOCKET_NO"))) { +		socket = strtoul(socket_no, NULL, 0); +	} else if (argc == 2) { +		socket = strtoul(argv[1], NULL, 0); +	} else if (argc == 1) { +		socket = 0; +		all_sockets = 1; +	} else { +		return -EINVAL; +	} + +	load_config(); + +	for (i = 0; i < MAX_SOCKS; i++) { +		if ((socket != i) && (!all_sockets)) +			continue; + +		adjust_resources(i); +		setup_done(i); +	} + +	return 0; +} +*/ + +void pcmcia_socket_startup(int socket_no) { +	unsigned long i; +	unsigned int all_sockets = 0; + +        if (socket_no == -1) +		all_sockets = 1; + +	load_config(); + +	for (i = 0; i < MAX_SOCKS; i++) { +		if ((socket_no != i) && (!all_sockets)) +			continue; + +		adjust_resources(i); +		setup_done(i); +	} +} | 
