diff options
Diffstat (limited to 'mdk-stage1')
-rw-r--r-- | mdk-stage1/pcmcia/lex_config.l | 223 | ||||
-rw-r--r-- | mdk-stage1/pcmcia/startup.c | 271 | ||||
-rw-r--r-- | mdk-stage1/pcmcia/startup.h | 54 | ||||
-rw-r--r-- | mdk-stage1/pcmcia/yacc_config.y | 133 |
4 files changed, 681 insertions, 0 deletions
diff --git a/mdk-stage1/pcmcia/lex_config.l b/mdk-stage1/pcmcia/lex_config.l new file mode 100644 index 000000000..050d7479d --- /dev/null +++ b/mdk-stage1/pcmcia/lex_config.l @@ -0,0 +1,223 @@ +/* Special state for handling include files */ +%x src + +%{ +/* + * 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 + */ + +#undef src + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <syslog.h> + +#ifdef HAS_WORDEXP +#include <wordexp.h> +#else +#include <glob.h> +#endif + +#define src 1 + +#include "yacc_config.h" + +#define YY_NO_UNPUT 1 /* mdk-stage1 */ +extern int yyparse(void); /* mdk-stage1 */ + +/* For assembling nice error messages */ +char *current_file; +int current_lineno; + +static int lex_number(char *s); +static int lex_string(char *s); +static void do_source(char *fn); +static int do_eof(void); + +%} + +int [0-9]+ +hex 0x[0-9a-fA-F]+ +str \"([^"]|\\.)*\" + +%% + +source[ \t]+ BEGIN(src); return SOURCE; +<src>[^\n]+ do_source(yytext); BEGIN(INITIAL); +<<EOF>> if (do_eof()) yyterminate(); + +\n current_lineno++; +[ \t]* /* skip */ ; +[ ]*[#;].* /* skip */ ; + +exclude return EXCLUDE; +include return INCLUDE; +irq return IRQ_NO; +port return PORT; +memory return MEMORY; +module /* skip */ ; + +{int} return lex_number(yytext); + +{hex} return lex_number(yytext); + +{str} return lex_string(yytext); + +. return yytext[0]; + +%% + +#ifndef yywrap +int yywrap() { return 1; } +#endif + +/*====================================================================== + + Stuff to parse basic data types + +======================================================================*/ + +static int lex_number(char *s) +{ + yylval.num = strtoul(s, NULL, 0); + return NUMBER; +} + +static int lex_string(char *s) +{ + int n = strlen(s); + yylval.str = malloc(n-1); + strncpy(yylval.str, s+1, n-2); + yylval.str[n-2] = '\0'; + return STRING; +} + +/*====================================================================== + + Code to support nesting of configuration files + +======================================================================*/ + +#define MAX_SOURCE_DEPTH 4 +struct source_stack { + YY_BUFFER_STATE buffer; + char *filename; + int lineno, fileno; + FILE *file; +#ifdef HAS_WORDEXP + wordexp_t word; +#else + glob_t glob; +#endif +} source_stack[MAX_SOURCE_DEPTH]; +static int source_stack_ptr = 0; +static int parse_env = 0; + +static int get_glob(void) +{ + struct source_stack *s = &source_stack[source_stack_ptr]; +#ifdef HAS_WORDEXP + while (s->fileno < s->word.we_wordc) { + char *fn = s->word.we_wordv[s->fileno]; +#else + while (s->fileno < s->glob.gl_pathc) { + char *fn = s->glob.gl_pathv[s->fileno]; +#endif + s->file = fopen(fn, "r"); + if (s->file == NULL) { + if (strpbrk(fn, "?*[") == NULL) + syslog(LOG_ERR, "could not open '%s': %m", fn); + s->fileno++; + } else { + current_lineno = 1; + current_file = strdup(fn); + yy_switch_to_buffer(yy_create_buffer(s->file, YY_BUF_SIZE)); + source_stack_ptr++; + s->fileno++; + return 0; + } + } + return -1; +} + +static void do_source(char *fn) +{ + struct source_stack *s = &source_stack[source_stack_ptr]; + + if (source_stack_ptr >= MAX_SOURCE_DEPTH) { + syslog(LOG_ERR, "source depth limit exceeded"); + return; + } +#ifdef HAS_WORDEXP + wordexp(fn, &s->word, 0); +#else + glob(fn, GLOB_NOCHECK, NULL, &s->glob); +#endif + s->fileno = 0; + s->buffer = YY_CURRENT_BUFFER; + s->lineno = current_lineno; + s->filename = current_file; + get_glob(); +} + +static int do_eof(void) +{ + struct source_stack *s = &source_stack[--source_stack_ptr]; + if (source_stack_ptr < 0) { + if (parse_env == 0) { + char *t = getenv("PCMCIA_OPTS"); + if (t == NULL) return -1; + parse_env = 1; + source_stack_ptr = 0; + current_file = "PCMCIA_OPTS"; + current_lineno = 1; + yy_scan_string(t); + return 0; + } else + return -1; + } + fclose(s->file); + free(current_file); + yy_delete_buffer(YY_CURRENT_BUFFER); + if (get_glob() != 0) { + yy_switch_to_buffer(s->buffer); + current_lineno = s->lineno; + current_file = s->filename; + } + return 0; +} + +/*====================================================================== + + The main entry point... returns -1 if the file can't be accessed. + +======================================================================*/ + +int parse_configfile(char *fn) +{ + FILE *f; + + f = fopen(fn, "r"); + if (!f) { + syslog(LOG_ERR, "could not open '%s': %m", fn); + return -1; + } + current_lineno = 1; + current_file = fn; + source_stack_ptr = 0; + yyrestart(f); + yyparse(); + fclose(f); + return 0; +} + 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); + } +} diff --git a/mdk-stage1/pcmcia/startup.h b/mdk-stage1/pcmcia/startup.h new file mode 100644 index 000000000..ba6af2c15 --- /dev/null +++ b/mdk-stage1/pcmcia/startup.h @@ -0,0 +1,54 @@ +/* + * Startup tool for non statically mapped PCMCIA sockets + * + * 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 + * + */ + +#define MAX_SOCKS 8 +#define MAX_BINDINGS 4 +#define MAX_MODULES 4 + +/* for AdjustResourceInfo */ +typedef struct adjust_t { + unsigned int Action; + unsigned int Resource; + unsigned int Attributes; + union { + struct memory { + unsigned long Base; + unsigned long Size; + } memory; + struct io { + unsigned long BasePort; + unsigned long NumPorts; + unsigned int IOAddrLines; + } io; + struct irq { + unsigned int IRQ; + } irq; + } resource; +} adjust_t; + + +typedef struct adjust_list_t { + adjust_t adj; + struct adjust_list_t *next; +} adjust_list_t; + + +extern adjust_list_t *root_adjust; + +int parse_configfile(char *fn); + + +#define RES_MEMORY_RANGE 1 +#define RES_IO_RANGE 2 +#define RES_IRQ 3 +#define RES_RESERVED 0x10 +#define REMOVE_MANAGED_RESOURCE 1 +#define ADD_MANAGED_RESOURCE 2 diff --git a/mdk-stage1/pcmcia/yacc_config.y b/mdk-stage1/pcmcia/yacc_config.y new file mode 100644 index 000000000..be5ef98fe --- /dev/null +++ b/mdk-stage1/pcmcia/yacc_config.y @@ -0,0 +1,133 @@ +%{ +/* + * Startup tool for non statically mapped PCMCIA sockets - config file parsing + * + * (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 <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <sys/types.h> + +#include "startup.h" + +/* If bison: generate nicer error messages */ +#define YYERROR_VERBOSE 1 + +/* from lex_config, for nice error messages */ +extern char *current_file; +extern int current_lineno; + +extern int yylex(void); /* mdk-stage1 */ + +void yyerror(char *msg, ...); + +%} + +%token DEVICE CARD ANONYMOUS TUPLE MANFID VERSION FUNCTION PCI +%token BIND CIS TO NEEDS_MTD MODULE OPTS CLASS +%token REGION JEDEC DTYPE DEFAULT MTD +%token INCLUDE EXCLUDE RESERVE IRQ_NO PORT MEMORY +%token STRING NUMBER SOURCE + +%union { + char *str; + u_long num; + struct adjust_list_t *adjust; +} + +%type <str> STRING +%type <num> NUMBER +%type <adjust> adjust resource +%% +list: /* nothing */ + | list adjust + { + adjust_list_t **tail = &root_adjust; + while (*tail != NULL) tail = &(*tail)->next; + *tail = $2; + } + ; + +adjust: INCLUDE resource + { + $2->adj.Action = ADD_MANAGED_RESOURCE; + $$ = $2; + } + | EXCLUDE resource + { + $2->adj.Action = REMOVE_MANAGED_RESOURCE; + $$ = $2; + } + | RESERVE resource + { + $2->adj.Action = ADD_MANAGED_RESOURCE; + $2->adj.Attributes |= RES_RESERVED; + $$ = $2; + } + | adjust ',' resource + { + $3->adj.Action = $1->adj.Action; + $3->adj.Attributes = $1->adj.Attributes; + $3->next = $1; + $$ = $3; + } + ; + +resource: IRQ_NO NUMBER + { + $$ = calloc(sizeof(adjust_list_t), 1); + $$->adj.Resource = RES_IRQ; + $$->adj.resource.irq.IRQ = $2; + } + | PORT NUMBER '-' NUMBER + { + if (($4 < $2) || ($4 > 0xffff)) { + yyerror("invalid port range 0x%x-0x%x", $2, $4); + YYERROR; + } + $$ = calloc(sizeof(adjust_list_t), 1); + $$->adj.Resource = RES_IO_RANGE; + $$->adj.resource.io.BasePort = $2; + $$->adj.resource.io.NumPorts = $4 - $2 + 1; + } + | MEMORY NUMBER '-' NUMBER + { + if ($4 < $2) { + yyerror("invalid address range 0x%x-0x%x", $2, $4); + YYERROR; + } + $$ = calloc(sizeof(adjust_list_t), 1); + $$->adj.Resource = RES_MEMORY_RANGE; + $$->adj.resource.memory.Base = $2; + $$->adj.resource.memory.Size = $4 - $2 + 1; + } + ; + +%% +void yyerror(char *msg, ...) +{ + va_list ap; + char str[256]; + + va_start(ap, msg); + sprintf(str, "error in file '%s' line %d: ", + current_file, current_lineno); + vsprintf(str+strlen(str), msg, ap); +#if YYDEBUG + fprintf(stderr, "%s\n", str); +#else + syslog(LOG_ERR, "%s", str); +#endif + va_end(ap); +} + |