commit 46438969c67cfddade9f55244aff9a8ce0ac09f7 Author: Anton Kachalov Date: Tue Jan 20 18:32:43 2004 +0000 Initial revision diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..36f56f6 --- /dev/null +++ b/.cvsignore @@ -0,0 +1,11 @@ +init +stage1-full +stage1-cdrom +stage1-disk +stage1-network +debug.log +.depend +*.rdz* +mkinitrd_helper.tar.bz2 +hack_* +stage1-usbnet diff --git a/MANIFEST.doc b/MANIFEST.doc new file mode 100644 index 0000000..736ad5b --- /dev/null +++ b/MANIFEST.doc @@ -0,0 +1,24 @@ +# +# Master Manifest file for documentation-only distribution +# +doc d +MANIFEST.doc f +doc/article.ps f +doc/rose94.ps f +doc/bash.ps f +doc/bashbug.ps f +doc/builtins.ps f +doc/rbash.ps f +doc/bashref.ps f +doc/bashref.dvi f +doc/bash.0 f +doc/bashbug.0 f +doc/builtins.0 f +doc/rbash.0 f +doc/article.txt f +doc/bash.html f +doc/bashref.html f +doc/article.pdf f +doc/bash.pdf f +doc/bashref.pdf f +doc/rose94.pdf f diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b08c91d --- /dev/null +++ b/Makefile @@ -0,0 +1,265 @@ + #****************************************************************************** + # + # mdk-stage1 - the program that will load second-stage install + # + # $Id$ + # + # Guillaume Cottenceau (gc@mandrakesoft.com) + # + # Copyright 2000 MandrakeSoft + # + # This software may be freely redistributed under the terms of the GNU + # public license. + # + # You should have received a copy of the GNU General Public License + # along with this program; if not, write to the Free Software + # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + # + # Portions from Erik Troan (ewt@redhat.com) Copyright 1996 Red Hat Software + # + #***************************************************************************** + # + # Currently: + # + # ix86 + # init with minilibc + # stage1 with dietlibc except some targets + # + # ppc + # init with dietlibc + # stage1 with glibc + # + # ia64 + # init with glibc + # stage1 with glibc + # + #***************************************************************************** + + +top_dir = . + +include $(top_dir)/Makefile.common +include $(TOP)/config + +VERSION = $(CFGversion) + +DEFS = -DVERSION=\"$(VERSION)\" -DSPAWN_SHELL -DDISTRIB_NAME=\"$(CFGdistribname)\" + +COMPILE = $(CC) $(DEFS) $(CFLAGS) + + + #- stage1 "loader" +ifeq (i386, $(ARCH)) +INITSRC = minilibc.c init.c +INIT_DEFS = -DINIT_HEADERS=\"minilibc.h\" +else +INITSRC = init.c +ifeq (ia64, $(ARCH)) +INIT_DEFS = -DINIT_HEADERS=\"init-libc-headers.h\" $(GLIBC_INCLUDES) +else +INIT_DEFS = -DINIT_HEADERS=\"init-libc-headers.h\" $(DIETLIBC_INCLUDES) +endif +endif + +INITOBJS = $(subst .c,.o,$(INITSRC)) + + + #- frontends +NEWT_FRONTEND_SRC = newt-frontend.c +GLIBC_NEWT_FRONTEND_LIBS = newt/libnewt.a slang/libslang.a +DIETLIBC_NEWT_FRONTEND_LIBS = $(subst .a,-DIET.a,$(GLIBC_NEWT_FRONTEND_LIBS)) + +STDIO_FRONTEND_SRC = stdio-frontend.c +GLIBC_STDIO_FRONTEND_LIBS = +DIETLIBC_STDIO_FRONTEND_LIBS = + + +FRONTEND_OBJS = $(subst .c,.o,$($(F)_FRONTEND_SRC)) + +FRONTEND_LINK = $(FRONTEND_OBJS) $($(L)_$(F)_FRONTEND_LIBS) + +ifeq (i386, $(ARCH)) +# INSMOD = insmod-busybox +INSMOD = insmod-modutils +else +INSMOD = insmod-modutils +endif + +GLIBC_STAGE1_OWN_LIBS = $(INSMOD)/libinsmod.a mar/libmar.a bzlib/libbz2.a +#$(top_dir)/$(TMP_PKG)/usr/lib/libbz2.a +DIETLIBC_STAGE1_OWN_LIBS = $(subst .a,-DIET.a,$(GLIBC_STAGE1_OWN_LIBS)) +STAGE1_OWN_LIBS = $($(L)_STAGE1_OWN_LIBS) + + +ifeq (DIETLIBC, $(L)) +STAGE1_NETWORK_LIBS = $(top_dir)/$(TMP_PKG)/usr/lib/dietlibc/lib-$(ARCH)/librpc.a +endif + +ifeq (GLIBC, $(L)) +STAGE1_NETWORK_LIBS = /usr/lib/libresolv.a +endif + + #- stage1 itself +STAGE1SRC = stage1.c log.c tools.c modules.c probing.c mount.c automatic.c frontend-common.c +CDROMSRC = cdrom.c +DISKSRC = disk.c lomount.c +NETWORKSRC = network.c nfsmount.c dhcp.c url.c dns.c adsl.c + +ALLSRC = $(INITSRC) $(STAGE1SRC) $(CDROMSRC) $(DISKSRC) $(NETWORKSRC) + + + +STAGE1OBJS-CDROM = $(subst .c,-CDROM.o,$(STAGE1SRC) $(CDROMSRC)) + +CDROM_DEFS = -DDISABLE_DISK -DDISABLE_NETWORK -DAUTO_METHOD=\""cdrom"\" + + +STAGE1OBJS-DISK = $(subst .c,-DISK.o,$(STAGE1SRC) $(DISKSRC)) + +DISK_DEFS = -DDISABLE_CDROM -DDISABLE_NETWORK -DAUTO_METHOD=\""disk"\" + + +STAGE1OBJS-NETWORK = $(subst .c,-NETWORK.o,$(STAGE1SRC) $(NETWORKSRC)) + +NETWORK_DEFS = -DDISABLE_CDROM -DDISABLE_DISK + + +STAGE1OBJS-USBNET = $(subst .c,-USBNET.o,$(STAGE1SRC) $(NETWORKSRC)) + + +STAGE1OBJS-FULL = $(subst .c,-FULL.o,$(STAGE1SRC) $(CDROMSRC) $(DISKSRC) $(NETWORKSRC)) + + +ifeq (i386, $(ARCH)) +LDFLAGS_INIT = -static -nostdlib /usr/lib/crt1.o +else +ifeq (ia64, $(ARCH)) +LDFLAGS_INIT = $(GLIBC_LDFLAGS_STAGE1) +INIT_LIBC = $(GLIBC_LIBC) +else +LDFLAGS_INIT = $(DIETLIBC_LDFLAGS_STAGE1) +INIT_LIBC = $(DIETLIBC_LIBC) +endif +endif + + +BINS = init stage1-full + +ifeq (i386, $(ARCH)) +BINS += stage1-cdrom stage1-disk stage1-network stage1-usbnet +endif + +#DIRS += mar pci-resource usb-resource $(INSMOD) slang newt ppp/pppd rp-pppoe/src +DIRS += mar pci-resource usb-resource $(INSMOD) slang newt bzlib ppp/pppd rp-pppoe/src +ifeq (i386,$(ARCH)) +DIRS += pcmcia +endif + + +ifeq (i386,$(ARCH)) +GLIBC_PCMCIA_LIB = pcmcia/libpcmcia.a +DIETLIBC_PCMCIA_LIB = $(subst .a,-DIET.a,$(GLIBC_PCMCIA_LIB)) +PCMCIA_LIB = $($(L)_PCMCIA_LIB) +PCMCIA_DEFS = -DENABLE_PCMCIA +endif + + +USBNET_DEFS_GEN = -DENABLE_USB -DENABLE_USBNET +USBNET_DEFS = $(USBNET_DEFS_GEN) -DDISABLE_PCINET + +all: unpack dirs $(BINS) + +unpack: + rm -rf $(top_dir)/$(TMP_PKG) + mkdir $(top_dir)/$(TMP_PKG) + pushd $(top_dir)/$(TMP_PKG); \ + for f in `cat $(top_dir)/../REQ`; do \ + rpm2cpio $(CFGrepo)/$$f-*.rpm | cpio -id; \ + done + +dirs: + @for n in . $(DIRS); do \ + [ "$$n" = "." ] || make -C $$n ;\ + done + +init: $(INITOBJS) $(INIT_LIBC) + $(CC) -o $@ $^ $(LDFLAGS_INIT) + $(STRIPCMD) $@ + +stage1-cdrom: $(STAGE1OBJS-CDROM) $(STAGE1_OWN_LIBS) $(FRONTEND_LINK) $(STAGE1_LIBC) + $(CC) -o $@ $^ $(LDFLAGS_STAGE1) + $(STRIPCMD) $@ + +stage1-disk: $(STAGE1OBJS-DISK) $(STAGE1_OWN_LIBS) $(FRONTEND_LINK) $(STAGE1_LIBC) + $(CC) -o $@ $^ $(LDFLAGS_STAGE1) + $(STRIPCMD) $@ + +stage1-network: $(STAGE1OBJS-NETWORK) $(STAGE1_OWN_LIBS) $(STAGE1_NETWORK_LIBS) $(FRONTEND_LINK) $(STAGE1_LIBC) + $(CC) -o $@ $^ $(LDFLAGS_STAGE1) + $(STRIPCMD) $@ + +stage1-usbnet: $(STAGE1OBJS-USBNET) $(STAGE1_OWN_LIBS) $(STAGE1_NETWORK_LIBS) $(FRONTEND_LINK) $(STAGE1_LIBC) + $(CC) -o $@ $^ $(LDFLAGS_STAGE1) + $(STRIPCMD) $@ + +stage1-full: $(STAGE1OBJS-FULL) $(STAGE1_OWN_LIBS) $(STAGE1_NETWORK_LIBS) $(FRONTEND_LINK) $(PCMCIA_LIB) $(STAGE1_LIBC) + $(CC) -o $@ $^ $(LDFLAGS_STAGE1) + $(STRIPCMD) $@ + + +$(INITOBJS): %.o: %.c + $(COMPILE) $(INIT_DEFS) -c $< + +$(STAGE1OBJS-CDROM): %-CDROM.o: %.c + $(COMPILE) $(INCLUDES) $(CDROM_DEFS) -c $< -o $@ + +$(STAGE1OBJS-DISK): %-DISK.o: %.c + $(COMPILE) $(INCLUDES) $(DISK_DEFS) -c $< -o $@ + +$(STAGE1OBJS-NETWORK): %-NETWORK.o: %.c + $(COMPILE) $(INCLUDES) $(NETWORK_DEFS) -c $< -o $@ + +$(STAGE1OBJS-USBNET): %-USBNET.o: %.c + $(COMPILE) $(INCLUDES) $(NETWORK_DEFS) $(USBNET_DEFS) -c $< -o $@ + +$(STAGE1OBJS-FULL): %-FULL.o: %.c + $(COMPILE) $(INCLUDES) $(USBNET_DEFS_GEN) $(PCMCIA_DEFS) -c $< -o $@ + +.c.o: + $(COMPILE) $(INCLUDES) -c $< + + +clean: + @for n in $(DIRS); do \ + (cd $$n; make clean) \ + done + rm -f *.o .depend *.rdz *.img $(BINS) + + +tar-mkinitrd_helper: clean + rm -rf mkinitrd_helper-subdir + mkdir mkinitrd_helper-subdir + cd mkinitrd_helper-subdir ; cp -a ../dietlibc ../insmod-busybox ../Makefile.common ../insmod.h ../log.h . ; \ + cp ../Makefile.mkinitrd_helper Makefile + tar cfj mkinitrd_helper.tar.bz2 mkinitrd_helper-subdir --exclude CVS + rm -rf mkinitrd_helper-subdir + + +.depend: + $(CPP) $(CFLAGS) -M $(ALLSRC) > .depend + +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + + +*-CDROM.o: %-CDROM.o: %.o + +*-DISK.o: %-DISK.o: %.o + +*-NETWORK.o: %-NETWORK.o: %.o + +*-USBNET.o: %-USBNET.o: %.o + +*-FULL.o: %-FULL.o: %.o + diff --git a/Makefile.common b/Makefile.common new file mode 100644 index 0000000..fc08bb0 --- /dev/null +++ b/Makefile.common @@ -0,0 +1,59 @@ + # -*- makefile -*- + #****************************************************************************** + # + # Guillaume Cottenceau (gc@mandrakesoft.com) + # + # Copyright 2000 MandrakeSoft + # + # This software may be freely redistributed under the terms of the GNU + # public license. + # + # You should have received a copy of the GNU General Public License + # along with this program; if not, write to the Free Software + # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + # + #***************************************************************************** + +ARCH := $(patsubst i%86,i386,$(shell uname -m)) +ARCH := $(patsubst sparc%,sparc,$(ARCH)) + + #- default lib is dietlibc (honoured by main Makefile whenever possible) +L = DIETLIBC +#L = GLIBC + + #- default frontend is newt (honoured by main Makefile whenever possible) +F = NEWT +# F = STDIO + + #- override in some situations +ifeq (ia64, $(ARCH)) +L = GLIBC +endif +ifeq (ppc, $(ARCH)) +L = GLIBC +endif + +TMP_PKG=tmp_rpm + + #- flags used by all stuff +ifeq (ppc, $(ARCH)) +CFLAGS = -Os -pipe -Wall -fomit-frame-pointer +else +CFLAGS = -Os -pipe -Wall -fomit-frame-pointer -D_BSD_SOURCE -D_GNU_SOURCE -D__LIBC_DIETLIBC__ +endif + +DIETLIBC_INCLUDES = -I$(top_dir)/$(TMP_PKG)/usr/lib/dietlibc/include -I. -I$(top_dir)/$(TMP_PKG)/usr/include +GLIBC_INCLUDES = -I. -I$(top_dir)/$(TMP_PKG)/usr/include +# -I$(top_dir)/$(TMP_PKG)/usr/lib/dietlibc/include -I$(top_dir)/$(TMP_PKG)/usr/include +INCLUDES = $($(L)_INCLUDES) + +GLIBC_LDFLAGS_STAGE1 = -static +DIETLIBC_LDFLAGS_STAGE1 = -nostdlib $(top_dir)/$(TMP_PKG)/usr/lib/dietlibc/lib-$(ARCH)/start.o -L/usr/lib/gcc-lib/i*86-alt-linux/3.*/ -lgcc +LDFLAGS_STAGE1 = $($(L)_LDFLAGS_STAGE1) + +GLIBC_LIBC = +DIETLIBC_LIBC = $(top_dir)/$(TMP_PKG)/usr/lib/dietlibc/lib-$(ARCH)/libc.a $(top_dir)/$(TMP_PKG)/usr/lib/dietlibc/lib-$(ARCH)/libcompat.a +STAGE1_LIBC = $($(L)_LIBC) + +STRIPCMD = strip -R .note -R .comment + diff --git a/Makefile.mkinitrd_helper b/Makefile.mkinitrd_helper new file mode 100644 index 0000000..72bef59 --- /dev/null +++ b/Makefile.mkinitrd_helper @@ -0,0 +1,30 @@ + #****************************************************************************** + # + # Guillaume Cottenceau (gc@mandrakesoft.com) + # + # Copyright 2000 MandrakeSoft + # + # This software may be freely redistributed under the terms of the GNU + # public license. + # + # You should have received a copy of the GNU General Public License + # along with this program; if not, write to the Free Software + # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + # + #***************************************************************************** + + +DIRS = dietlibc insmod-busybox + + +all: dirs + +dirs: + @for n in . $(DIRS); do \ + [ "$$n" = "." ] || make -C $$n ;\ + done + +clean: + @for n in $(DIRS); do \ + (cd $$n; make clean) \ + done diff --git a/REQ b/REQ new file mode 100644 index 0000000..f0f29af --- /dev/null +++ b/REQ @@ -0,0 +1,3 @@ +bzlib-devel +bzlib-devel-static +dietlibc diff --git a/adsl.c b/adsl.c new file mode 100644 index 0000000..2bf15a9 --- /dev/null +++ b/adsl.c @@ -0,0 +1,172 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +// #include +#include +#include +#include +#include +#include +#include +#include + +#include "stage1.h" +#include "log.h" +#include "network.h" +#include "modules.h" +#include "tools.h" +#include "frontend.h" +#include "automatic.h" + +#include "adsl.h" + + +static enum return_type adsl_connect(char * net_device, char * username, char * password) +{ + char pppoe_call[500]; + char * pppd_launch[] = { "/sbin/pppd", "pty", pppoe_call, "noipdefault", "noauth", "default-asyncmap", "defaultroute", + "hide-password", "nodetach", "usepeerdns", "local", "mtu", "1492", "mru", "1492", "noaccomp", + "noccp", "nobsdcomp", "nodeflate", "nopcomp", "novj", "novjccomp", "user", username, + "password", password, "lcp-echo-interval", "20", "lcp-echo-failure", "3", "lock", "persist", NULL }; + int fd; + int retries = 10; + char * tty_adsl = "/dev/tty6"; + enum return_type status = RETURN_ERROR; + pid_t ppp_pid; + + snprintf(pppoe_call, sizeof(pppoe_call), "/sbin/pppoe -p /var/run/pppoe.conf-adsl.pid.pppoe -I %s -T 80 -U -m 1412", net_device); + + + fd = open(tty_adsl, O_RDWR); + if (fd == -1) { + log_message("cannot open tty -- no pppd"); + return RETURN_ERROR; + } + else if (access(pppd_launch[0], X_OK)) { + log_message("cannot open pppd - %s doesn't exist", pppd_launch[0]); + return RETURN_ERROR; + } + + if (!(ppp_pid = fork())) { + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + + close(fd); + setsid(); + if (ioctl(0, TIOCSCTTY, NULL)) + log_perror("could not set new controlling tty"); + + printf("\t(exec of pppd)\n"); + execve(pppd_launch[0], pppd_launch, grab_env()); + log_message("execve of %s failed: %s", pppd_launch[0], strerror(errno)); + exit(-1); + } + close(fd); + while (retries > 0 && kill(ppp_pid, 0) == 0) { + FILE * f; + if ((f = fopen("/var/run/pppd.tdb", "rb"))) { + while (1) { + char buf[500]; + if (!fgets(buf, sizeof(buf), f)) + break; + if (strstr(buf, "IPLOCAL=")) + status = RETURN_OK; + } + fclose(f); + if (status == RETURN_OK) { + log_message("PPP: connected!"); + break; + } + } + retries--; + log_message("PPP: "); + sleep(2); + } + + if (status != RETURN_OK) { + log_message("PPP: could not connect"); + kill(ppp_pid, SIGTERM); + sleep(1); + kill(ppp_pid, SIGKILL); + sleep(1); + } + return status; +} + + +enum return_type perform_adsl(struct interface_info * intf) +{ + struct in_addr addr; + char * questions[] = { "Username", "Password", NULL }; + char * questions_auto[] = { "adsluser", "adslpass", NULL }; + static char ** answers = NULL; + enum return_type results; + + inet_aton("10.0.0.10", &addr); + memcpy(&intf->ip, &addr, sizeof(addr)); + + inet_aton("255.255.255.0", &addr); + memcpy(&intf->netmask, &addr, sizeof(addr)); + + *((uint32_t *) &intf->broadcast) = (*((uint32_t *) &intf->ip) & + *((uint32_t *) &intf->netmask)) | ~(*((uint32_t *) &intf->netmask)); + + intf->is_ptp = 0; + + if (configure_net_device(intf)) { + stg1_error_message("Could not configure.."); + return RETURN_ERROR; + } + + results = ask_from_entries_auto("Please enter the username and password for your ADSL account.\n" + "(Warning! only PPPoE protocol is supported)", + questions, &answers, 40, questions_auto, NULL); + if (results != RETURN_OK) + return results; + + intf->boot_proto = BOOTPROTO_ADSL_PPPOE; + + wait_message("Waiting for ADSL connection to show up..."); + my_insmod("ppp_generic", ANY_DRIVER_TYPE, NULL); + my_insmod("ppp_async", ANY_DRIVER_TYPE, NULL); + my_insmod("ppp", ANY_DRIVER_TYPE, NULL); + results = adsl_connect(intf->device, answers[0], answers[1]); + remove_wait_message(); + + if (results != RETURN_OK) { + wait_message("Retrying the ADSL connection..."); + results = adsl_connect(intf->device, answers[0], answers[1]); + remove_wait_message(); + } else { + intf->user = strdup(answers[0]); + intf->pass = strdup(answers[1]); + } + + if (results != RETURN_OK) { + stg1_error_message("I could not connect to the ADSL network."); + return perform_adsl(intf); + } + + sleep(1); + res_init(); /* reinit the resolver, pppd modified /etc/resolv.conf */ + + return RETURN_OK; +} diff --git a/adsl.h b/adsl.h new file mode 100644 index 0000000..9d32cc6 --- /dev/null +++ b/adsl.h @@ -0,0 +1,34 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * View the homepage: http://us.mandrakesoft.com/~gc/html/stage1.html + * + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from GRUB -- GRand Unified Bootloader + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * Itself based on etherboot-4.6.4 by Martin Renters. + * + */ + +#ifndef _ADSL_H_ +#define _ADSL_H_ + +#include "stage1.h" +#include "network.h" + +enum return_type perform_adsl(struct interface_info * intf); + +#endif diff --git a/automatic.c b/automatic.c new file mode 100644 index 0000000..ec80616 --- /dev/null +++ b/automatic.c @@ -0,0 +1,162 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * This is supposed to replace the redhat "kickstart", by name but + * also by design (less code pollution). + * + */ + + +#include +#include +#include +#include "tools.h" +#include "stage1.h" +#include "frontend.h" +#include "log.h" + +#include "automatic.h" + + +static struct param_elem * automatic_params; +static char * value_not_bound = ""; + +void grab_automatic_params(char * line) +{ + int i, p; + struct param_elem tmp_params[50]; + + i = 0; p = 0; + while (line[i] != '\0') { + char *name, *value; + int k; + int j = i; + while (line[i] != ':' && line[i] != '\0') + i++; + name = memdup(&line[j], i-j + 1); + name[i-j] = 0; + + k = i+1; + i++; + while (line[i] != ',' && line[i] != '\0') + i++; + value = memdup(&line[k], i-k + 1); + value[i-k] = 0; + + tmp_params[p].name = name; + tmp_params[p].value = value; + p++; + if (line[i] == '\0') + break; + i++; + } + + tmp_params[p++].name = NULL; + automatic_params = memdup(tmp_params, sizeof(struct param_elem) * p); + + log_message("AUTOMATIC MODE: got %d params", p-1); +} + + +char * get_auto_value(char * auto_param) +{ + struct param_elem * ptr = automatic_params; + + while (ptr->name) { + if (!strcmp(ptr->name, auto_param)) + return ptr->value; + ptr++; + } + + return value_not_bound; +} + + +enum return_type ask_from_list_auto(char *msg, char ** elems, char ** choice, char * auto_param, char ** elems_auto) +{ +#ifndef AUTO_METHOD + if (!IS_AUTOMATIC) + return ask_from_list(msg, elems, choice); + else +#endif + { + char ** sav_elems = elems; +#ifdef AUTO_METHOD + char * tmp = AUTO_METHOD; +#else + char * tmp = get_auto_value(auto_param); +#endif + while (elems && *elems) { + if (!strcmp(tmp, *elems_auto)) { + *choice = *elems; + log_message("AUTOMATIC: parameter %s for %s means returning %s", tmp, auto_param, *elems); + return RETURN_OK; + } + elems++; + elems_auto++; + } + unset_param(MODE_AUTOMATIC); /* we are in a fallback mode */ + return ask_from_list(msg, sav_elems, choice); + } +} + +enum return_type ask_from_list_comments_auto(char *msg, char ** elems, char ** elems_comments, char ** choice, char * auto_param, char ** elems_auto) +{ +#ifndef AUTO_METHOD + if (!IS_AUTOMATIC) + return ask_from_list_comments(msg, elems, elems_comments, choice); + else +#endif + { + char ** sav_elems = elems; +#ifdef AUTO_METHOD + char * tmp = AUTO_METHOD; +#else + char * tmp = get_auto_value(auto_param); +#endif + while (elems && *elems) { + if (!strcmp(tmp, *elems_auto)) { + *choice = *elems; + log_message("AUTOMATIC: parameter %s for %s means returning %s", tmp, auto_param, *elems); + return RETURN_OK; + } + elems++; + elems_auto++; + } + unset_param(MODE_AUTOMATIC); /* we are in a fallback mode */ + return ask_from_list_comments(msg, sav_elems, elems_comments, choice); + } +} + + +enum return_type ask_from_entries_auto(char *msg, char ** questions, char *** answers, int entry_size, char ** questions_auto, void (*callback_func)(char ** strings)) +{ + if (!IS_AUTOMATIC) + return ask_from_entries(msg, questions, answers, entry_size, callback_func); + else { + char * tmp_answers[50]; + int i = 0; + while (questions && *questions) { + tmp_answers[i] = get_auto_value(*questions_auto); + log_message("AUTOMATIC: question %s answers %s because of param %s", *questions, tmp_answers[i], *questions_auto); + i++; + questions++; + questions_auto++; + + } + *answers = memdup(tmp_answers, sizeof(char *) * i); + return RETURN_OK; + } +} diff --git a/automatic.h b/automatic.h new file mode 100644 index 0000000..c2ac0a7 --- /dev/null +++ b/automatic.h @@ -0,0 +1,32 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * This is supposed to replace the redhat "kickstart", by name but + * also by design (no code pollution). + * + */ + +#ifndef _AUTOMATIC_H_ +#define _AUTOMATIC_H_ + +#include "stage1.h" + +void grab_automatic_params(char * line); + +enum return_type ask_from_list_auto(char *msg, char ** elems, char ** choice, char * auto_param, char ** elems_auto); +enum return_type ask_from_list_comments_auto(char *msg, char ** elems, char ** elems_comments, char ** choice, char * auto_param, char ** elems_auto); +enum return_type ask_from_entries_auto(char *msg, char ** questions, char *** answers, int entry_size, char ** questions_auto, void (*callback_func)(char ** strings)); + +#endif diff --git a/cdrom.c b/cdrom.c new file mode 100644 index 0000000..9646ef3 --- /dev/null +++ b/cdrom.c @@ -0,0 +1,184 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#include +#include +#include +#include +#include +#include "stage1.h" +#include "frontend.h" +#include "modules.h" +#include "probing.h" +#include "log.h" +#include "mount.h" + +#include "cdrom.h" + + +static int mount_that_cd_device(char * dev_name) +{ + char device_fullname[50]; + + strcpy(device_fullname, "/dev/"); + strcat(device_fullname, dev_name); + + return my_mount(device_fullname, IMAGE_LOCATION, "iso9660", 0); +} + + +static int test_that_cd() +{ + return access(IMAGE_LOCATION LIVE_LOCATION, R_OK); +} + + +static enum return_type try_with_device(char * dev_name, char * dev_model); + +static enum return_type do_with_device(char * dev_name, char * dev_model) +{ + if (test_that_cd()) { + enum return_type results; + umount(IMAGE_LOCATION); + results = ask_yes_no("That CDROM disc does not seem to be a " DISTRIB_NAME " Installation CDROM.\nRetry with another disc?"); + if (results == RETURN_OK) + return try_with_device(dev_name, dev_model); + return results; + } + + log_message("found a " DISTRIB_NAME " CDROM, good news!"); + + //if (!IS_SPECIAL_STAGE2 && ramdisk_possible()) + if (!IS_LOWMEM && ramdisk_possible()) + load_ramdisk(); /* we don't care about return code, we'll do it live if we failed */ + + if (IS_RESCUE) { + load_ramdisk(); + umount(IMAGE_LOCATION); + } + + method_name = strdup("cdrom"); + return RETURN_OK; +} + +static enum return_type try_with_device(char * dev_name, char * dev_model) +{ + wait_message("Trying to access a CDROM disc (drive %s)", dev_model); + + if (mount_that_cd_device(dev_name) == -1) { + enum return_type results; + char msg[500]; + unset_param(MODE_AUTOMATIC); /* we are in a fallback mode */ + remove_wait_message(); + + snprintf(msg, sizeof(msg), "I can't access a " DISTRIB_NAME " Installation disc in your CDROM drive (%s).\nRetry?", dev_model); + results = ask_yes_no(msg); + if (results == RETURN_OK) + return try_with_device(dev_name, dev_model); + return results; + } + remove_wait_message(); + + return do_with_device(dev_name, dev_model); +} + +enum return_type cdrom_prepare(void) +{ + char ** medias, ** ptr, ** medias_models; + char * choice; + int i, count = 0; + enum return_type results; + + my_insmod("ide-cd", ANY_DRIVER_TYPE, NULL); + my_insmod("sr_mod", ANY_DRIVER_TYPE, NULL); + + get_medias(CDROM, &medias, &medias_models); + + ptr = medias; + while (ptr && *ptr) { + count++; + ptr++; + } + + if (count == 0) { + stg1_error_message("No CDROM device found."); + i = ask_insmod(SCSI_ADAPTERS); + if (i == RETURN_BACK) + return RETURN_BACK; + return cdrom_prepare(); + } + + if (count == 1) { + results = try_with_device(*medias, *medias_models); + if (results == RETURN_OK) + return RETURN_OK; + i = ask_insmod(SCSI_ADAPTERS); + if (i == RETURN_BACK) + return RETURN_BACK; + return cdrom_prepare(); + } + + if (IS_AUTOMATIC) { + char ** model = medias_models; + ptr = medias; + while (ptr && *ptr) { + wait_message("Trying to access " DISTRIB_NAME " CDROM disc (drive %s)", *model); + if (mount_that_cd_device(*ptr) != -1) { + if (!test_that_cd()) { + remove_wait_message(); + return do_with_device(*ptr, *model); + } + else + umount(IMAGE_LOCATION); + } + remove_wait_message(); + ptr++; + model++; + } + unset_param(MODE_AUTOMATIC); + return cdrom_prepare(); + } + else { + results = ask_from_list_comments("Please choose the CDROM drive to use for the installation.", medias, medias_models, &choice); + if (results == RETURN_OK) { + char ** model = medias_models; + ptr = medias; + while (ptr && *ptr && model && *model) { + if (!strcmp(*ptr, choice)) + break; + ptr++; + model++; + } + results = try_with_device(choice, *model); + } else + return results; + } + + if (results == RETURN_OK) + return RETURN_OK; + if (results == RETURN_BACK) + return cdrom_prepare(); + + i = ask_insmod(SCSI_ADAPTERS); + if (i == RETURN_BACK) + return RETURN_BACK; + return cdrom_prepare(); +} diff --git a/cdrom.h b/cdrom.h new file mode 100644 index 0000000..639487e --- /dev/null +++ b/cdrom.h @@ -0,0 +1,29 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#ifndef _CDROM_H_ +#define _CDROM_H_ + +#include "stage1.h" + +enum return_type cdrom_prepare(void); + +#endif diff --git a/config-stage1.h b/config-stage1.h new file mode 100644 index 0000000..c10e579 --- /dev/null +++ b/config-stage1.h @@ -0,0 +1,48 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _CONFIG_STAGE1_H_ +#define _CONFIG_STAGE1_H_ + +#define _GNU_SOURCE 1 + + +/* If we have more than that amount of memory (in Mbytes), we assume we can load the second stage as a ramdisk */ +#define MEM_LIMIT_RAMDISK 80 + +/* If we have more than that amount of memory (in Mbytes), we assume we can load the rescue as a ramdisk */ +#define MEM_LIMIT_RESCUE 56 + +// #define DISTRIB_NAME "ALT Linux Junior 2.2" + +#define RAMDISK_COMPRESSION_RATIO 1.95 + +#define LIVE_LOCATION "/ALTLinux/mdkinst/" +#define RAMDISK_LOCATION "/ALTLinux/base/" +#define IMAGE_LOCATION "/tmp/image" +#define STAGE2_LOCATION "/tmp/stage2" + +/* user-definable (in Makefile): DISABLE_NETWORK, DISABLE_DISK, DISABLE_CDROM, DISABLE_PCMCIA */ + + +/* some factorizing for disabling more features */ + +#ifdef DISABLE_DISK +#ifdef DISABLE_CDROM +#define DISABLE_MEDIAS +#endif +#endif + + +#endif diff --git a/config-stage1.h-master b/config-stage1.h-master new file mode 100644 index 0000000..0c5d375 --- /dev/null +++ b/config-stage1.h-master @@ -0,0 +1,48 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _CONFIG_STAGE1_H_ +#define _CONFIG_STAGE1_H_ + +#define _GNU_SOURCE 1 + + +/* If we have more than that amount of memory (in Mbytes), we assume we can load the second stage as a ramdisk */ +#define MEM_LIMIT_RAMDISK 52 + +/* If we have more than that amount of memory (in Mbytes), we assume we can load the rescue as a ramdisk */ +#define MEM_LIMIT_RESCUE 40 + +#define DISTRIB_NAME "ALT Linux Junior" + +#define RAMDISK_COMPRESSION_RATIO 1.95 + +#define LIVE_LOCATION "/Mandrake/mdkinst/" +#define RAMDISK_LOCATION "/Mandrake/base/" +#define IMAGE_LOCATION "/tmp/image" +#define STAGE2_LOCATION "/tmp/stage2" + +/* user-definable (in Makefile): DISABLE_NETWORK, DISABLE_DISK, DISABLE_CDROM, DISABLE_PCMCIA */ + + +/* some factorizing for disabling more features */ + +#ifdef DISABLE_DISK +#ifdef DISABLE_CDROM +#define DISABLE_MEDIAS +#endif +#endif + + +#endif diff --git a/dhcp.c b/dhcp.c new file mode 100644 index 0000000..006e633 --- /dev/null +++ b/dhcp.c @@ -0,0 +1,615 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +/* + * Portions from GRUB -- GRand Unified Bootloader + * Copyright (C) 2000 Free Software Foundation, Inc. + */ + + +#include +#include +#include +#include +// #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stage1.h" +#include "log.h" +#include "network.h" +#include "frontend.h" + +#include "dhcp.h" + + +typedef int bp_int32; +typedef short bp_int16; + +#define BOOTP_OPTION_NETMASK 1 +#define BOOTP_OPTION_GATEWAY 3 +#define BOOTP_OPTION_DNS 6 +#define BOOTP_OPTION_HOSTNAME 12 +#define BOOTP_OPTION_DOMAIN 15 +#define BOOTP_OPTION_BROADCAST 28 + +#define DHCP_OPTION_REQADDR 50 +#define DHCP_OPTION_LEASE 51 +#define DHCP_OPTION_TYPE 53 +#define DHCP_OPTION_SERVER 54 +#define DHCP_OPTION_OPTIONREQ 55 +#define DHCP_OPTION_MAXSIZE 57 + +#define BOOTP_CLIENT_PORT 68 +#define BOOTP_SERVER_PORT 67 + +#define BOOTP_OPCODE_REQUEST 1 +#define BOOTP_OPCODE_REPLY 2 + +#define DHCP_TYPE_DISCOVER 1 +#define DHCP_TYPE_OFFER 2 +#define DHCP_TYPE_REQUEST 3 +#define DHCP_TYPE_ACK 5 +#define DHCP_TYPE_RELEASE 7 + +#define BOOTP_VENDOR_LENGTH 64 +#define DHCP_VENDOR_LENGTH 340 + +struct bootp_request { + char opcode; + char hw; + char hwlength; + char hopcount; + bp_int32 id; + bp_int16 secs; + bp_int16 flags; + bp_int32 ciaddr, yiaddr, server_ip, bootp_gw_ip; + char hwaddr[16]; + char servername[64]; + char bootfile[128]; + char vendor[DHCP_VENDOR_LENGTH]; +} ; + +static const char vendor_cookie[] = { 99, 130, 83, 99, 255 }; + + +static unsigned int verify_checksum(void * buf2, int length2) +{ + unsigned int csum = 0; + unsigned short * sp; + + for (sp = (unsigned short *) buf2; length2 > 0; (length2 -= 2), sp++) + csum += *sp; + + while (csum >> 16) + csum = (csum & 0xffff) + (csum >> 16); + + return (csum == 0xffff); +} + + +static int initial_setup_interface(char * device, int s) { + struct sockaddr_in * addrp; + struct ifreq req; + struct rtentry route; + int true = 1; + + addrp = (struct sockaddr_in *) &req.ifr_addr; + + strcpy(req.ifr_name, device); + addrp->sin_family = AF_INET; + addrp->sin_port = 0; + memset(&addrp->sin_addr, 0, sizeof(addrp->sin_addr)); + + req.ifr_flags = 0; /* take it down */ + if (ioctl(s, SIOCSIFFLAGS, &req)) { + log_perror("SIOCSIFFLAGS (downing)"); + return -1; + } + + addrp->sin_family = AF_INET; + addrp->sin_addr.s_addr = htonl(0); + if (ioctl(s, SIOCSIFADDR, &req)) { + log_perror("SIOCSIFADDR"); + return -1; + } + + req.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING; + if (ioctl(s, SIOCSIFFLAGS, &req)) { + log_perror("SIOCSIFFLAGS (upping)"); + return -1; + } + + memset(&route, 0, sizeof(route)); + memcpy(&route.rt_gateway, addrp, sizeof(*addrp)); + + addrp->sin_family = AF_INET; + addrp->sin_port = 0; + addrp->sin_addr.s_addr = INADDR_ANY; + memcpy(&route.rt_dst, addrp, sizeof(*addrp)); + memcpy(&route.rt_genmask, addrp, sizeof(*addrp)); + + route.rt_dev = device; + route.rt_flags = RTF_UP; + route.rt_metric = 0; + + if (ioctl(s, SIOCADDRT, &route)) { + if (errno != EEXIST) { + close(s); + log_perror("SIOCADDRT"); + return -1; + } + } + + if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &true, sizeof(true))) { + close(s); + log_perror("setsockopt"); + return -1; + } + + /* I need to sleep a bit in order for kernel to finish init of the + network device; this would allow to not send further multiple + dhcp requests when only one is needed. */ + wait_message("Bringing up networking..."); + sleep(2); + remove_wait_message(); + + return 0; +} + + +void set_missing_ip_info(struct interface_info * intf) +{ + bp_int32 ipNum = *((bp_int32 *) &intf->ip); + bp_int32 nmNum; + + if (intf->netmask.s_addr == 0) + inet_aton(guess_netmask(inet_ntoa(intf->ip)), &intf->netmask); + + nmNum = *((bp_int32 *) &intf->netmask); + + if (intf->broadcast.s_addr == 0) + *((bp_int32 *) &intf->broadcast) = (ipNum & nmNum) | ~(nmNum); + + if (intf->network.s_addr == 0) + *((bp_int32 *) &intf->network) = ipNum & nmNum; +} + +static void parse_reply(struct bootp_request * breq, struct interface_info * intf) +{ + unsigned char * chptr; + unsigned char option, length; + + memcpy(&intf->ip, &breq->yiaddr, 4); + + chptr = breq->vendor; + chptr += 4; + while (*chptr != 0xFF && (void *) chptr < (void *) breq->vendor + DHCP_VENDOR_LENGTH) { + char tmp_str[500]; + option = *chptr++; + if (!option) + continue; + length = *chptr++; + + switch (option) { + case BOOTP_OPTION_DNS: + memcpy(&dns_server, chptr, sizeof(dns_server)); + log_message("got dns %s", inet_ntoa(dns_server)); + if (length >= sizeof(dns_server)*2) { + memcpy(&dns_server2, chptr+sizeof(dns_server), sizeof(dns_server2)); + log_message("got dns2 %s", inet_ntoa(dns_server2)); + } + break; + + case BOOTP_OPTION_NETMASK: + memcpy(&intf->netmask, chptr, sizeof(intf->netmask)); + log_message("got netmask %s", inet_ntoa(intf->netmask)); + break; + + case BOOTP_OPTION_DOMAIN: + memcpy(tmp_str, chptr, length); + tmp_str[length] = '\0'; + domain = strdup(tmp_str); + log_message("got domain %s", domain); + break; + + case BOOTP_OPTION_BROADCAST: + memcpy(&intf->broadcast, chptr, sizeof(intf->broadcast)); + log_message("got broadcast %s", inet_ntoa(intf->broadcast)); + break; + + case BOOTP_OPTION_GATEWAY: + memcpy(&gateway, chptr, sizeof(gateway)); + log_message("got gateway %s", inet_ntoa(gateway)); + break; + + case BOOTP_OPTION_HOSTNAME: + memcpy(tmp_str, chptr, length); + tmp_str[length] = '\0'; + hostname = strdup(tmp_str); + log_message("got hostname %s", hostname); + break; + + } + + chptr += length; + } + + set_missing_ip_info(intf); +} + + +static void init_vendor_codes(struct bootp_request * breq) { + memcpy(breq->vendor, vendor_cookie, sizeof(vendor_cookie)); +} + +static char gen_hwaddr[16]; + +static int prepare_request(struct bootp_request * breq, int sock, char * device) +{ + struct ifreq req; + + memset(breq, 0, sizeof(*breq)); + + breq->opcode = BOOTP_OPCODE_REQUEST; + + strcpy(req.ifr_name, device); + if (ioctl(sock, SIOCGIFHWADDR, &req)) { + log_perror("SIOCSIFHWADDR"); + return -1; + } + + breq->hw = 1; /* ethernet */ + breq->hwlength = IFHWADDRLEN; + memcpy(breq->hwaddr, req.ifr_hwaddr.sa_data, IFHWADDRLEN); + memcpy(gen_hwaddr, req.ifr_hwaddr.sa_data, IFHWADDRLEN); + + breq->hopcount = 0; + + init_vendor_codes(breq); + + return 0; +} + +static int get_vendor_code(struct bootp_request * bresp, unsigned char option, void * data) +{ + unsigned char * chptr; + unsigned int length, theOption; + + chptr = bresp->vendor + 4; + while (*chptr != 0xFF && *chptr != option) { + theOption = *chptr++; + if (!theOption) + continue; + length = *chptr++; + chptr += length; + } + + if (*chptr++ == 0xff) + return 1; + + length = *chptr++; + memcpy(data, chptr, length); + + return 0; +} + + +static int currticks(void) +{ + struct timeval tv; + long csecs; + int ticks_per_csec, ticks_per_usec; + + /* Note: 18.2 ticks/sec. */ + + gettimeofday (&tv, 0); + csecs = tv.tv_sec / 10; + ticks_per_csec = csecs * 182; + ticks_per_usec = (((tv.tv_sec - csecs * 10) * 1000000 + tv.tv_usec) * 182 / 10000000); + return ticks_per_csec + ticks_per_usec; +} + + +#define BACKOFF_LIMIT 7 +#define TICKS_PER_SEC 18 +#define MAX_ARP_RETRIES 4 + +static void rfc951_sleep(int exp) +{ + static long seed = 0; + long q; + unsigned long tmo; + + if (exp > BACKOFF_LIMIT) + exp = BACKOFF_LIMIT; + + if (!seed) + /* Initialize linear congruential generator. */ + seed = (currticks () + *(long *) &gen_hwaddr + ((short *) gen_hwaddr)[2]); + + /* Simplified version of the LCG given in Bruce Scheier's + "Applied Cryptography". */ + q = seed / 53668; + if ((seed = 40014 * (seed - 53668 * q) - 12211 * q) < 0) + seed += 2147483563l; + + /* Compute mask. */ + for (tmo = 63; tmo <= 60 * TICKS_PER_SEC && --exp > 0; tmo = 2 * tmo + 1) + ; + + /* Sleep. */ + log_message(""); + + for (tmo = (tmo & seed) + currticks (); currticks () < tmo;); +} + + +static int handle_transaction(int s, struct bootp_request * breq, struct bootp_request * bresp, + struct sockaddr_in * server_addr, int dhcp_type) +{ + struct pollfd polls; + int i, j; + int retry = 1; + int sin; + char eth_packet[ETH_FRAME_LEN]; + struct iphdr * ip_hdr; + struct udphdr * udp_hdr; + unsigned char type; + unsigned long starttime; + int timeout = 1; + + breq->id = starttime = currticks(); + breq->secs = 0; + + sin = socket(AF_PACKET, SOCK_DGRAM, ntohs(ETH_P_IP)); + if (sin < 0) { + log_perror("af_packet socket"); + return -1; + } + + while (retry <= MAX_ARP_RETRIES) { + i = sizeof(*breq); + + if (sendto(s, breq, i, 0, (struct sockaddr *) server_addr, sizeof(*server_addr)) != i) { + close(s); + log_perror("sendto"); + return -1; + } + + polls.fd = sin; + polls.events = POLLIN; + + while (poll(&polls, 1, timeout*1000) == 1) { + + if ((j = recv(sin, eth_packet, sizeof(eth_packet), 0)) == -1) { + log_perror("recv"); + continue; + } + + /* We need to do some basic sanity checking of the header */ + if (j < (sizeof(*ip_hdr) + sizeof(*udp_hdr))) + continue; + + ip_hdr = (void *) eth_packet; + if (!verify_checksum(ip_hdr, sizeof(*ip_hdr))) + continue; + + if (ntohs(ip_hdr->tot_len) > j) + continue; + + j = ntohs(ip_hdr->tot_len); + + if (ip_hdr->protocol != IPPROTO_UDP) + continue; + + udp_hdr = (void *) (eth_packet + sizeof(*ip_hdr)); + + if (ntohs(udp_hdr->source) != BOOTP_SERVER_PORT) + continue; + + if (ntohs(udp_hdr->dest) != BOOTP_CLIENT_PORT) + continue; + /* Go on with this packet; it looks sane */ + + /* Originally copied sizeof (*bresp) - this is a security + problem due to a potential underflow of the source + buffer. Also, it trusted that the packet was properly + 0xFF terminated, which is not true in the case of the + DHCP server on Cisco 800 series ISDN router. */ + + memset (bresp, 0xFF, sizeof (*bresp)); + memcpy (bresp, (char *) udp_hdr + sizeof (*udp_hdr), j - sizeof (*ip_hdr) - sizeof (*udp_hdr)); + + /* sanity checks */ + if (bresp->id != breq->id) + continue; + if (bresp->opcode != BOOTP_OPCODE_REPLY) + continue; + if (bresp->hwlength != breq->hwlength) + continue; + if (memcmp(bresp->hwaddr, breq->hwaddr, bresp->hwlength)) + continue; + if (get_vendor_code(bresp, DHCP_OPTION_TYPE, &type) || type != dhcp_type) + continue; + if (memcmp(bresp->vendor, vendor_cookie, 4)) + continue; + return 0; + } + rfc951_sleep(retry); + breq->secs = htons ((currticks () - starttime) / 20); + retry++; + timeout *= 2; + if (timeout > 5) + timeout = 5; + } + + return -1; +} + +static void add_vendor_code(struct bootp_request * breq, unsigned char option, unsigned char length, void * data) +{ + unsigned char * chptr; + int theOption, theLength; + + chptr = breq->vendor; + chptr += 4; + while (*chptr != 0xFF && *chptr != option) { + theOption = *chptr++; + if (!theOption) continue; + theLength = *chptr++; + chptr += theLength; + } + + *chptr++ = option; + *chptr++ = length; + memcpy(chptr, data, length); + chptr[length] = 0xff; +} + + + +enum return_type perform_dhcp(struct interface_info * intf) +{ + int s, i; + struct sockaddr_in server_addr; + struct sockaddr_in client_addr; + struct sockaddr_in broadcast_addr; + struct bootp_request breq, bresp; + unsigned char messageType; + unsigned int lease; + short aShort; + int num_options; + char requested_options[50]; + + if (strncmp(intf->device, "eth", 3)) { + stg1_error_message("DHCP available only for Ethernet networking."); + return RETURN_ERROR; + } + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + log_perror("socket"); + return RETURN_ERROR; + } + + if (initial_setup_interface(intf->device, s) != 0) { + close(s); + return RETURN_ERROR; + } + + if (prepare_request(&breq, s, intf->device) != 0) { + close(s); + return RETURN_ERROR; + } + + messageType = DHCP_TYPE_DISCOVER; + add_vendor_code(&breq, DHCP_OPTION_TYPE, 1, &messageType); + + memset(&client_addr.sin_addr, 0, sizeof(&client_addr.sin_addr)); + client_addr.sin_family = AF_INET; + client_addr.sin_port = htons(BOOTP_CLIENT_PORT); /* bootp client */ + + if (bind(s, (struct sockaddr *) &client_addr, sizeof(client_addr))) { + log_perror("bind"); + return RETURN_ERROR; + } + + broadcast_addr.sin_family = AF_INET; + broadcast_addr.sin_port = htons(BOOTP_SERVER_PORT); /* bootp server */ + memset(&broadcast_addr.sin_addr, 0xff, sizeof(broadcast_addr.sin_addr)); /* broadcast */ + + log_message("DHCP: sending DISCOVER"); + + wait_message("Sending DHCP request..."); + i = handle_transaction(s, &breq, &bresp, &broadcast_addr, DHCP_TYPE_OFFER); + remove_wait_message(); + + if (i != 0) { + stg1_error_message("No DHCP reply received."); + close(s); + return RETURN_ERROR; + } + + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(BOOTP_SERVER_PORT); /* bootp server */ + if (get_vendor_code(&bresp, DHCP_OPTION_SERVER, &server_addr.sin_addr)) { + close(s); + log_message("DHCPOFFER didn't include server address"); + return RETURN_ERROR; + } + + init_vendor_codes(&breq); + messageType = DHCP_TYPE_REQUEST; + add_vendor_code(&breq, DHCP_OPTION_TYPE, 1, &messageType); + add_vendor_code(&breq, DHCP_OPTION_SERVER, 4, &server_addr.sin_addr); + add_vendor_code(&breq, DHCP_OPTION_REQADDR, 4, &bresp.yiaddr); + + aShort = ntohs(sizeof(struct bootp_request)); + add_vendor_code(&breq, DHCP_OPTION_MAXSIZE, 2, &aShort); + + num_options = 0; + requested_options[num_options++] = BOOTP_OPTION_NETMASK; + requested_options[num_options++] = BOOTP_OPTION_GATEWAY; + requested_options[num_options++] = BOOTP_OPTION_DNS; + requested_options[num_options++] = BOOTP_OPTION_DOMAIN; + requested_options[num_options++] = BOOTP_OPTION_BROADCAST; + add_vendor_code(&breq, DHCP_OPTION_OPTIONREQ, num_options, requested_options); + + /* request a lease of 1 hour */ + i = htonl(60 * 60); + add_vendor_code(&breq, DHCP_OPTION_LEASE, 4, &i); + + log_message("DHCP: sending REQUEST"); + + i = handle_transaction(s, &breq, &bresp, &broadcast_addr, DHCP_TYPE_ACK); + + if (i != 0) { + close(s); + return RETURN_ERROR; + } + + if (get_vendor_code(&bresp, DHCP_OPTION_LEASE, &lease)) { + log_message("failed to get lease time\n"); + return RETURN_ERROR; + } + lease = ntohl(lease); + + close(s); + + intf->netmask.s_addr = 0; + intf->broadcast.s_addr = 0; + intf->network.s_addr = 0; + + parse_reply(&bresp, intf); + + return RETURN_OK; +} diff --git a/dhcp.h b/dhcp.h new file mode 100644 index 0000000..6fb121e --- /dev/null +++ b/dhcp.h @@ -0,0 +1,34 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * View the homepage: http://us.mandrakesoft.com/~gc/html/stage1.html + * + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from GRUB -- GRand Unified Bootloader + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * Itself based on etherboot-4.6.4 by Martin Renters. + * + */ + +#ifndef _DHCP_H_ +#define _DHCP_H_ + +#include "stage1.h" +#include "network.h" + +enum return_type perform_dhcp(struct interface_info * intf); + +#endif diff --git a/disk.c b/disk.c new file mode 100644 index 0000000..515b953 --- /dev/null +++ b/disk.c @@ -0,0 +1,342 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "stage1.h" +#include "frontend.h" +#include "modules.h" +#include "probing.h" +#include "log.h" +#include "mount.h" +#include "lomount.h" +#include "automatic.h" + +#include "disk.h" + +struct partition_detection_anchor { + off_t offset; + const char * anchor; +}; + +static int seek_and_compare(int fd, struct partition_detection_anchor anch) +{ + char buf[500]; + int count; + if (lseek(fd, anch.offset, SEEK_SET) == (off_t)-1) { + log_perror("seek failed"); + return -1; + } + count = read(fd, buf, strlen(anch.anchor)); + if (count != strlen(anch.anchor)) { + log_perror("read failed"); + return -1; + } + buf[count] = '\0'; + if (strcmp(anch.anchor, buf)) + return 1; + return 0; +} + +static const char * detect_partition_type(char * dev) +{ + struct partition_detection_info { + const char * name; + struct partition_detection_anchor anchor0; + struct partition_detection_anchor anchor1; + struct partition_detection_anchor anchor2; + }; + struct partition_detection_info partitions_signatures[] = { + { "Linux Swap", { 4086, "SWAP-SPACE" }, { 0, NULL } }, + { "Linux Swap", { 4086, "SWAPSPACE2" }, { 0, NULL } }, + { "Ext2", { 0x438, "\x53\xEF" }, { 0, NULL } }, + { "ReiserFS", { 0x10034, "ReIsErFs" }, { 0, NULL } }, + { "ReiserFS", { 0x10034, "ReIsEr2Fs" }, { 0, NULL } }, + { "XFS", { 0, "XFSB" }, { 0x200, "XAGF" }, { 0x400, "XAGI" } }, + { "JFS", { 0x8000, "JFS1" }, { 0, NULL } }, + { "NTFS", { 0x1FE, "\x55\xAA" }, { 0x3, "NTFS" }, { 0, NULL } }, + { "FAT32", { 0x1FE, "\x55\xAA" }, { 0x52, "FAT32" }, { 0, NULL } }, + { "FAT", { 0x1FE, "\x55\xAA" }, { 0x36, "FAT" }, { 0, NULL } }, + { "Linux LVM", { 0, "HM\1\0" }, { 0, NULL }, { 0, NULL } } + }; + int partitions_signatures_nb = sizeof(partitions_signatures) / sizeof(struct partition_detection_info); + int i; + int fd; + + char device_fullname[50]; + strcpy(device_fullname, "/dev/"); + strcat(device_fullname, dev); + + if (ensure_dev_exists(device_fullname)) + return NULL; + log_message("guessing type of %s", device_fullname); + + if ((fd = open(device_fullname, O_RDONLY, 0)) < 0) { + log_perror("open"); + return NULL; + } + + for (i=0; i 1) && (name[strlen(dev_name)] != '\0')) { + const char * partition_type = detect_partition_type(name); + parts[i] = strdup(name); + parts_comments[i] = (char *) malloc(sizeof(char) * 100); + sprintf(parts_comments[i], "size: %d Mbytes", blocks >> 10); + if (partition_type) { + strcat(parts_comments[i], ", type: "); + strcat(parts_comments[i], partition_type); + } + i++; + } + } + parts[i] = NULL; + fclose(f); + + if (parts[0] == NULL) { + stg1_error_message("No partitions found."); + return RETURN_ERROR; + } + + results = ask_from_list_comments_auto("Please choose the partition where is copied the " DISTRIB_NAME " Distribution.", + parts, parts_comments, &choice, "partition", parts); + if (results != RETURN_OK) + return results; + + strcpy(device_fullname, "/dev/"); + strcat(device_fullname, choice); + + if (my_mount(device_fullname, disk_own_mount, "ext2", 0) == -1 && + my_mount(device_fullname, disk_own_mount, "vfat", 0) == -1 && + my_mount(device_fullname, disk_own_mount, "reiserfs", 0) == -1) { + stg1_error_message("I can't find a valid filesystem (tried: ext2, vfat, reiserfs)."); + return try_with_device(dev_name); + } + + if (ask_from_entries_auto("Please enter the directory (or ISO image file) containing the " DISTRIB_NAME " Distribution.", + questions_location, &answers_location, 24, questions_location_auto, NULL) != RETURN_OK) { + umount(disk_own_mount); + return try_with_device(dev_name); + } + + strcpy(location_full, disk_own_mount); + strcat(location_full, "/"); + strcat(location_full, answers_location[0]); + + if (access(location_full, R_OK)) { + stg1_error_message("Directory or ISO image file could not be found on partition.\n" + "Here's a short extract of the files in the root of the partition:\n" + "%s", disk_extract_list_directory(disk_own_mount)); + umount(disk_own_mount); + return try_with_device(dev_name); + } + + unlink(IMAGE_LOCATION); + + if (!stat(location_full, &statbuf) && !S_ISDIR(statbuf.st_mode)) { + log_message("%s exists and is not a directory, assuming this is an ISO image", location_full); + if (lomount(location_full, IMAGE_LOCATION)) { + stg1_error_message("Could not mount file %s as an ISO image of the " DISTRIB_NAME " Distribution.", answers_location[0]); + umount(disk_own_mount); + return try_with_device(dev_name); + } + } else + symlink(location_full, IMAGE_LOCATION); + + if (IS_SPECIAL_STAGE2 || ramdisk_possible()) { + /* RAMDISK install */ + if (access(IMAGE_LOCATION RAMDISK_LOCATION, R_OK)) { + stg1_error_message("I can't find the " DISTRIB_NAME " Distribution in the specified directory. " + "(I need the subdirectory " RAMDISK_LOCATION ")\n" + "Here's a short extract of the files in the directory:\n" + "%s", disk_extract_list_directory(IMAGE_LOCATION)); + loumount(); + umount(disk_own_mount); + return try_with_device(dev_name); + } + if (load_ramdisk() != RETURN_OK) { + stg1_error_message("Could not load program into memory."); + loumount(); + umount(disk_own_mount); + return try_with_device(dev_name); + } + } else { + /* LIVE install */ + char p; + if (access(IMAGE_LOCATION LIVE_LOCATION, R_OK)) { + stg1_error_message("I can't find the " DISTRIB_NAME " Distribution in the specified directory. " + "(I need the subdirectory " LIVE_LOCATION ")\n" + "Here's a short extract of the files in the directory:\n" + "%s", disk_extract_list_directory(IMAGE_LOCATION)); + loumount(); + umount(disk_own_mount); + return try_with_device(dev_name); + } + if (readlink(IMAGE_LOCATION LIVE_LOCATION "/usr/bin/runinstall2", &p, 1) != 1) { + stg1_error_message("The " DISTRIB_NAME " Distribution seems to be copied on a Windows partition. " + "You need more memory to perform an installation from a Windows partition. " + "Another solution if to copy the " DISTRIB_NAME " Distribution on a Linux partition."); + loumount(); + umount(disk_own_mount); + return try_with_device(dev_name); + } + log_message("found the " DISTRIB_NAME " Installation, good news!"); + } + + if (IS_RESCUE) { + loumount(); + umount(disk_own_mount); + } + + method_name = strdup("disk"); + return RETURN_OK; +} + +enum return_type disk_prepare(void) +{ + char ** medias, ** ptr, ** medias_models; + char * choice; + int i, count = 0; + enum return_type results; + + my_insmod("sd_mod", ANY_DRIVER_TYPE, NULL); + + get_medias(DISK, &medias, &medias_models); + + ptr = medias; + while (ptr && *ptr) { + count++; + ptr++; + } + + if (count == 0) { + stg1_error_message("No DISK drive found."); + i = ask_insmod(SCSI_ADAPTERS); + if (i == RETURN_BACK) + return RETURN_BACK; + return disk_prepare(); + } + + if (count == 1) { + results = try_with_device(*medias); + if (results == RETURN_OK) + return RETURN_OK; + i = ask_insmod(SCSI_ADAPTERS); + if (i == RETURN_BACK) + return RETURN_BACK; + return disk_prepare(); + } + + results = ask_from_list_comments_auto("Please choose the DISK drive on which you copied the " DISTRIB_NAME " Distribution.", + medias, medias_models, &choice, "disk", medias); + + if (results != RETURN_OK) + return results; + + results = try_with_device(choice); + if (results == RETURN_OK) + return RETURN_OK; + i = ask_insmod(SCSI_ADAPTERS); + if (i == RETURN_BACK) + return RETURN_BACK; + return disk_prepare(); +} diff --git a/disk.h b/disk.h new file mode 100644 index 0000000..54213cf --- /dev/null +++ b/disk.h @@ -0,0 +1,27 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#ifndef _DISK_H_ +#define _DISK_H_ + +enum return_type disk_prepare(void); + +#endif diff --git a/dns.c b/dns.c new file mode 100644 index 0000000..151d071 --- /dev/null +++ b/dns.c @@ -0,0 +1,213 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#include + +// dietlibc can do hostname lookup, whereas glibc can't when linked statically :-( + +#ifdef __LIBC_DIETLIBC__ + +#include +#include +#include +#include +// #include + +#include "network.h" +#include "log.h" + +#include "dns.h" + +int mygethostbyname(char * name, struct in_addr * addr) +{ + struct hostent * h = gethostbyname(name); + if (!h) { + if (domain) { + // gethostbyname from dietlibc doesn't support domain handling + char fully_qualified[500]; + sprintf(fully_qualified, "%s.%s", name, domain); + h = gethostbyname(fully_qualified); + if (!h) { + log_message("unknown host %s", name); + return -1; + } + } else + return -1; + } + + if (h->h_addr_list && (h->h_addr_list)[0]) { + memcpy(addr, (h->h_addr_list)[0], sizeof(*addr)); + log_message("is-at: %s", inet_ntoa(*addr)); + return 0; + } + return -1; +} + +char * mygethostbyaddr(char * ipnum) +{ + struct in_addr in; + struct hostent * host; + if (!inet_aton(ipnum, &in)) + return NULL; + host = gethostbyaddr(&in, strlen((void *) &in), AF_INET); + if (host && host->h_name) + return host->h_name; + return NULL; +} + + +#else // __LIBC_DIETLIBC__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" + +#include "dns.h" + +/* This is dumb, but glibc doesn't like to do hostname lookups w/o libc.so */ + +union dns_response { + HEADER hdr; + u_char buf[PACKETSZ]; +} ; + +static int do_query(char * query, int queryType, char ** domainName, struct in_addr * ipNum) +{ + int len, ancount, type; + u_char * data, * end; + char name[MAXDNAME]; + union dns_response response; + +#ifdef __sparc__ + /* from jj: */ + /* We have to wait till ethernet negotiation is done */ + _res.retry = 3; +#else + _res.retry = 2; +#endif + + + len = res_search(query, C_IN, queryType, (void *) &response, sizeof(response)); + if (len <= 0) + return -1; + + if (ntohs(response.hdr.rcode) != NOERROR) + return -1; + + ancount = ntohs(response.hdr.ancount); + if (ancount < 1) + return -1; + + data = response.buf + sizeof(HEADER); + end = response.buf + len; + + /* skip the question */ + data += dn_skipname(data, end) + QFIXEDSZ; + + /* parse the answer(s) */ + while (--ancount >= 0 && data < end) { + + /* skip the domain name portion of the RR record */ + data += dn_skipname(data, end); + + /* get RR information */ + GETSHORT(type, data); + data += INT16SZ; /* skipp class */ + data += INT32SZ; /* skipp TTL */ + GETSHORT(len, data); + + if (type == T_PTR) { + /* we got a pointer */ + len = dn_expand(response.buf, end, data, name, sizeof(name)); + if (len <= 0) return -1; + if (queryType == T_PTR && domainName) { + /* we wanted a pointer */ + *domainName = malloc(strlen(name) + 1); + strcpy(*domainName, name); + return 0; + } + } else if (type == T_A) { + /* we got an address */ + if (queryType == T_A && ipNum) { + /* we wanted an address */ + memcpy(ipNum, data, sizeof(*ipNum)); + return 0; + } + } + + /* move ahead to next RR */ + data += len; + } + + return -1; +} + +char * mygethostbyaddr(char * ipnum) { + int rc; + char * result; + char * strbuf; + char * chptr; + char * splits[4]; + int i; + + _res.retry = 1; + + strbuf = alloca(strlen(ipnum) + 1); + strcpy(strbuf, ipnum); + + ipnum = alloca(strlen(strbuf) + 20); + + for (i = 0; i < 4; i++) { + chptr = strbuf; + while (*chptr && *chptr != '.') + chptr++; + *chptr = '\0'; + + if (chptr - strbuf > 3) return NULL; + splits[i] = strbuf; + strbuf = chptr + 1; + } + + sprintf(ipnum, "%s.%s.%s.%s.in-addr.arpa", splits[3], splits[2], splits[1], splits[0]); + + rc = do_query(ipnum, T_PTR, &result, NULL); + + if (rc) + return NULL; + else + return result; +} + +int mygethostbyname(char * name, struct in_addr * addr) { + int rc = do_query(name, T_A, NULL, addr); + if (!rc) + log_message("is-at %s", inet_ntoa(*addr)); + return rc; +} + +#endif diff --git a/dns.h b/dns.h new file mode 100644 index 0000000..97af9c0 --- /dev/null +++ b/dns.h @@ -0,0 +1,30 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#ifndef H_DNS +#define H_DNS + +#include + +int mygethostbyname(char * name, struct in_addr * addr); +char * mygethostbyaddr(char * ipnum); + +#endif diff --git a/doc/HACKING b/doc/HACKING new file mode 100644 index 0000000..d196c80 --- /dev/null +++ b/doc/HACKING @@ -0,0 +1,31 @@ +If you have to boot pretty often, you'll appreciate to speed the things up +a little. + +Here's what we use: the GRUB feature to boot from the network using the +DHCP protocol and the TFTP protocol. + +Here's the "menu.lst" to do that: + +-=-=-- + +timeout 0 + +title linux +dhcp +tftpserver 192.168.1.17 +kernel (nd)/tftpboot/gc/vmlinuz ramdisk=32000 vga=788 +initrd (nd)/tftpboot/gc/network.rdz + +-=-=-- + + +The option "tftpserver" is used to override the tftpserver address given +as an answer by the DHCP server. That way, you'll not need to bother your +system administrator to modify his dhcp server configuration. + +The directory /tftpboot seems to be the only one defaultly accepted by the +server, and its subdirs. + + +Of course, your GRUB needs to be compiled with the specific code for your +network card; use ./configure --help in the GRUB build dir for more infos. diff --git a/doc/README b/doc/README new file mode 100644 index 0000000..09edce6 --- /dev/null +++ b/doc/README @@ -0,0 +1,185 @@ +------------------------------------------------------- +* Stage1 of the Mandrake Linux installation program * +------------------------------------------------------- + + +[ Author ] + + Guillaume Cottenceau (gc@mandrakesoft.com) + + +[ Copyright ] + + Copyright 2000 MandrakeSoft + + Partially inspired by Redhat stuff (install from 5.x and 7.x) copyright + Red Hat Software, and Debian stuff (boot-floppies) copyright by their + respective holders. + + +[ Licence ] + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + *** WARNING! *** + + This General Public License does not permit incorporating any part + of this program as a library into proprietary programs. + + +[ Online ] + + http://us.mandrakesoft.com/~gc/html/stage1.html + + +[ Purpose ] + + This code will take the control of the computer after that Linux + kernel booted properly, and will try to run the main installer + (also known as "stage 2") from a series of different media + including harddrive, cdrom, and network. + + Use the source, Luke. + + + + + -=-=-- Okay, now, more details --=-=- + + + [ Installing Mandrake Linux ] + +Per default, just insert your Mandrake Linux Installation CD into your +CDROM tray, be sure your system BIOS is configured to boot on your CDROM, +and that's all. + +If you have multiple CDROM drives and the installer can't autodetect in +which CDROM drive is the disc, it may ask you to choose the correct drive, +between your CDROM drives. + +Also, if you want to install from an SCSI CDROM, the installer should +detect your SCSI adapter; if it fails you may have to select the right +driver and/or supply additional parameters. + + + [ Position of the problem ] + +The need for alternate installation methods come with more specific +hardware configuration and/or need for frequent updates of the Installer +software. + +All of these methods will require to use a special boot disk. The method +is to download it and then to copy it "physically" to a floppy with the +command: + +# dd if= of=/dev/fd0 + +Our boot disks are called "cdrom.img", "network.img", etc. + + + [ Installation from CDROM ] + +The first situation you may encounter is an old BIOS which does not permit +you to boot from your CDROM drive. + +In that case, you'll need to use the "cdrom.img" image file. The steps are +the same as with CDROM boot, and everything should be automatic. + + + [ Installation from DISK ] + +If you like trying occasionnally our development version, the Cooker, one +of the easiest way is to grab a local copy of the Distribution on one of +your local hard drives, and to install from that location. + +At present time, you can install from IDE or SCSI drives, from Linux +(ext2), Windows (vfat) or Reiserfs partition. + +In that case, you'll need to use the "hd.img" image file. The dialogs will +ask you to choose the DISK drive to use to install from, then the +partition on which you copied the Distribution, then the location +(directory) in which you copied the Distribution. + + + [ Installation from NETWORK ] + +For convenience, you can also install from a NFS volume, from a FTP +server, or from a HTTP server. NFS installs are maybe the fastest +and most convenient possible, so if you need to do frequent and/or +multiple installs, you may like this option. + +In that case, you'll need to use the "network.img" image file. If you have +PCI network card(s), you'll probably have to only setup your network +options. If not, you'll have to choose the appropriate driver(s) and/or +optional parameters. Supported network configurations include static IP +allocation and DHCP automatic configuration. + + + [ Installation from PCMCIA ] + +If you want to perform an installation on your laptop that is not based on +local IDE CDROM or DISK, nor on built-in network card, but on PCMCIA +extension (probably a network adapter or CDROM drive), you'll need the +"pcmcia.img" image file. + +PCMCIA services should automatically start and be transparent to you. +Then, you'll follow the instructions according to your preferred +installation method. + + + [ Monitoring a stage1 session ] + +Linux supports virtual consoles. You can switch between them by issueing +Ctrl+Alt+Fx key, in which 'x' is the number of the console. Here's console +occupancy during stage1. + +(#1) The user-interface of the stage1 is on the first console. In case of +newt interaction, it's provided with a neat blue and black color scheme, +and nice widgets. In case of stdio interaction (cdrom and disk installs), +it's more basic but still usable :-). + +(#2) A shell is provided on second console in some cases (you need to +compile it with -DSPAWN_SHELL and you need to provide a valid shell in the +initrd) and of course it's not in, in image files of Mandrake Linux +releases because it's too much diskspace. + +(#3) The log is printed out on the third console. This is the location +where you can find most valuable information, prefixed by a '*'. See +"log.h" for calls that print things out to the log. + +(#4) The kernel messages are printed on the fourth console. There is a +process forked very early in the init (the program before the stage1) +which monitors /proc/kmsg for new kernel messages. Also, syslog stuff (the +logs commited by the programs) should appear on the /dev/log Unix socket, +this is also printed on this console. + +(#5) Former place for the stderr of insmod calls. It's not used anymore. + +(#6) Place where a trivial interactive communication with the stage1 is +set up if the parameter -DSPAWN_INTERACTIVE is compiled in. Basically, you +can set switches such as "expert" and "rescue" on the fly with this +feature. It's implemented with a fork and a Unix pipe. + + + [ Rescueing a system ] + +Since Mandrake Linux 7.1, we provide a rescue system through each of the +previously described methods. You don't need a special "rescue.img" file. +Just hit "F1" at boot time, type in "rescue", and follow the first steps +of the installation according to the method you chose (choose +disks/partitions for disk method, network parameters for network method, +etc). Then, you'll end up with a workable system, very useful to rescue a +damaged system, or do other basic actions. diff --git a/doc/TECH-INFOS b/doc/TECH-INFOS new file mode 100644 index 0000000..f86809f --- /dev/null +++ b/doc/TECH-INFOS @@ -0,0 +1,80 @@ + +| (*) Automatic install +\---------------------- + +This feature is used to replace redhat kickstart. It uses the kernel +parameter "automatic" with keywords separated with commas and colons, on +the following genres: + + automatic=method:nfs,network:static,ip:192.168.1.24,server:192.168.1.7,directory:/stable/i586 + + automatic=method:ftp,network:dhcp,server:ftp.ciril.fr,directory:/pub/linux/mandrake-devel/cooker + + automatic=method:ftp,network:dhcp,server:companyserver,directory:/mdkinst,user:XXX,pass:XXX + + automatic=method:ftp,interface:eth1,network:dhcp,... + + automatic=method:ftp,network:adsl,adsluser:XXX,adslpass:XXX,... + + automatic=method:cdrom + + automatic=method:disk,disk:hdb,partition:hdb7 + + +The keywords correspond to each "virtual" question answered automatically, +either from a list or from a free field. + + +Keywords are: + + +`method' <- (nfs,ftp,http,cdrom,disk) + +if nfs/ftp/http: + + `network' <- (static,dhcp,adsl) + + if multiple interfaces detected: + + `interface' <- (list-of-detected-interfaces) + + fi + + if static: + + `ip', `dns', `gateway', `netmask' (free fields) + + elsif adsl: + + `adsluser', `adslpass' (free field) + + fi + + if resolving fails: + + `hostname', `domain' (free fields) + + fi + + `server', `directory' (free fields) + + if ftp: + + `user', `pass' (free fields) + + fi + +fi + +if disk: + + `disk' <- (list-of-detected-disks) + + `partition' <- (list-of-detected-partitions) + + `directory' (free fields) + +fi + + + diff --git a/doc/UPDATEMODULES b/doc/UPDATEMODULES new file mode 100644 index 0000000..a20266e --- /dev/null +++ b/doc/UPDATEMODULES @@ -0,0 +1,71 @@ +This is the documentation for the "Update Modules" (Update Drivers) +feature. + +This feature aims to propose new modules or replacement modules for the +install. This is useful when there is a firmware update for a given +driver, an additional driver needed for something, etc. + + +You must use a floppy disk with e2fs filesystem (NOT vfat/windows +formatted). Use "mke2fs /dev/fd0" on your own box to format a floppy with +e2fs filesystem. + +This disk may contain a number of kernel modules on the root (e.g. not in +a subdirectory); some of them may replace existing modules, some of them +may be added. This disk must contain a special file, named "to_load", on +the root (not in a subdirectory). This file will contain a series of +module names, with optional module options; the program will try to load +all these modules one after another, using file on the floppy if present, +else using file within standard module repository ("marfile" on the boot +floppy). It can contain comments, these are strictly defined by the +presence of a hash (#) character on row 0 of any line. Beware, on the +first line of the line, a comment is mandatory (there is a bug somewhere). + + +Here's a typical scenario: + + +1. Boot the floppy (or cdrom) with the option "updatemodules" + + (you may do that by pressing F1 then entering "linux updatemodules") + + +2. At the very beginning of the User Interface, you are asked to insert + the Update Modules disk. Insert the Update Modules disk and press + Enter. + +--=----=----=----=----=----=----=----=----=-- +Our example disk contains: + +[root@obiwan mnt]# ll floppy/ +total 77 +drwxr-xr-x 2 root root 12288 Jul 26 12:02 lost+found/ +-rw-r--r-- 1 root root 9051 Jul 26 12:43 msdos.o +-rw-r--r-- 1 root root 13660 Jul 26 12:04 ppa.o +-rw-r--r-- 1 root root 54 Jul 26 12:46 to_load +-rw-r--r-- 1 root root 32108 Jul 26 12:04 uhci.o +-rw-r--r-- 1 root root 6572 Jul 26 12:04 wacom.o +[root@obiwan mnt]# cat floppy/to_load +# Update Drivers description file +3c59x +# fat is a dep for msdos +fat +# updated msdos (handling of 9+4 filenames) +msdos +ppa +[root@obiwan mnt]# +--=----=----=----=----=----=----=----=----=-- + + +3. The program reads the special file "to_load" and processes the files. + + a- 3c59x loaded from the marfile on the boot floppy + b- fat loaded from the marfile on the boot floppy + c- msdos loaded from the update modules floppy + d- ppa loaded from the update modules floppy + + + +Beware, the dependencies are not handled automatically in the case of load +from the update modules floppy, that's why on our example we need to load +"fat" from the standard modules before "msdos" from the update floppy. diff --git a/doc/WHY-DIETLIBC b/doc/WHY-DIETLIBC new file mode 100644 index 0000000..e7c526b --- /dev/null +++ b/doc/WHY-DIETLIBC @@ -0,0 +1,50 @@ +(the dietlibc is a replacement for the glibc, which aim is to produce +smaller statically linked binaries) + + +The use for dietlibc in the stage1 was clear because currently used +install process on x86 is from a 1.44 Mbytes floppy. On this floppy we +need to fit the kernel, modules (scsi and network access), and the code to +do the basic things to load the stage2. The only part on which we could +progress was the code. + +As always, figures demonstrate evidences. Here are the size of the +binaries used for the cdrom, disk, network and full floppy installs, using +newt as the UI library: + + - with glibc + +-rwxr-xr-x 1 gc gc 569448 May 15 15:29 stage1-cdrom +-rwxr-xr-x 1 gc gc 572264 May 15 15:29 stage1-disk +-rwxr-xr-x 1 gc gc 624712 May 15 15:30 stage1-network +-rwxr-xr-x 1 gc gc 720360 May 15 15:29 stage1-full + + - with dietlibc + +-rwxr-xr-x 1 gc gc 169332 May 15 14:26 stage1-cdrom +-rwxr-xr-x 1 gc gc 172180 May 15 14:26 stage1-disk +-rwxr-xr-x 1 gc gc 198612 May 15 14:26 stage1-network +-rwxr-xr-x 1 gc gc 251764 May 15 14:26 stage1-full + + +The `stage1-full' binary has code for many things, most notably: data +decrunching (bzlib), archive extraction (in-house format), module loading +(insmod from busybox), PCI detection, ide and scsi handling, +cdrom/disk/loopback mounting, DHCP client negociation (redhat+grub), NFS +mounting (util-linux), FTP and HTTP transmission (redhat), pcmcia +initializing (pcmcia-cs), UI interaction (slang/newt); with use of the +dietlibc, the binary is only 250 kbytes! + + +Due to the modular coding, it is also possible to choose to not use +slang/newt as the UI, but a stdio-only UI. In that case, the binaries get +even smaller: + +-rwxr-xr-x 1 gc gc 104500 May 15 15:46 stage1-cdrom* +-rwxr-xr-x 1 gc gc 107348 May 15 15:46 stage1-disk* +-rwxr-xr-x 1 gc gc 133972 May 15 15:47 stage1-network* +-rwxr-xr-x 1 gc gc 187348 May 15 15:46 stage1-full* + + + +gc [Tue May 15 15:58:34 2001] \ No newline at end of file diff --git a/doc/documented..frontend.h b/doc/documented..frontend.h new file mode 100644 index 0000000..10417ef --- /dev/null +++ b/doc/documented..frontend.h @@ -0,0 +1,69 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Using high-level UI. + * + * These functions are frontend-independant: your program won't know each + * `frontend' (e.g. each way to grab user input) will be used. + * + * Then you may link your binary against any `frontend' that implement all + * these functions (and possibly necessary libraries). + */ + + +#ifndef _FRONTEND_H_ +#define _FRONTEND_H_ + +/* this must be called before anything else */ +void init_frontend(void); + +/* this must be called before exit of program */ +void finish_frontend(void); + + +void info_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); /* (blocks program) */ + +void error_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); /* (blocks program) */ + +/* (doesn't block program) + * (this is not necessarily stackable, e.g. only one wait_message at a time) */ +void wait_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); + +/* call this to finish the wait on wait_message */ +void remove_wait_message(void); + +/* monitor progression of something (downloading a file, etc) + * if size of progression is unknown, use `0' */ +void init_progression(char *msg, int size); +void update_progression(int current_size); +void end_progression(void); + +enum frontend_return { RETURN_OK, RETURN_BACK, RETURN_ERROR }; + +/* Yes == RETURN_OK No == RETURN_ERROR Back == RETURN_BACK */ +enum frontend_return ask_yes_no(char *msg); + +/* [elems] NULL terminated array of char* + * [choice] address of a (unitialized) char* */ +enum frontend_return ask_from_list(char *msg, char ** elems, char ** choice); + +enum frontend_return ask_from_list_comments(char *msg, char ** elems, char ** elems_comments, char ** choice); + +/* [questions] NULL terminated array of char* + * [answers] address of a (unitialized) char**, will contain a non-NULL terminated array of char* + * [callback_func] function called at most when the answers change; it can examine the array of char* and assign some new char* */ +enum frontend_return ask_from_entries(char *msg, char ** questions, char *** answers, int entry_size, void (*callback_func)(char ** strings)); + +#endif diff --git a/frontend-common.c b/frontend-common.c new file mode 100644 index 0000000..caddeb7 --- /dev/null +++ b/frontend-common.c @@ -0,0 +1,43 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include + +#include "frontend.h" + + +void info_message(char *msg, ...) +{ + va_list args; + va_start(args, msg); + vinfo_message(msg, args); + va_end(args); +} + +void wait_message(char *msg, ...) +{ + va_list args; + va_start(args, msg); + vwait_message(msg, args); + va_end(args); +} + +void error_message(char *msg, ...) +{ + va_list args; + va_start(args, msg); + verror_message(msg, args); + va_end(args); +} diff --git a/frontend.h b/frontend.h new file mode 100644 index 0000000..1672917 --- /dev/null +++ b/frontend.h @@ -0,0 +1,50 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * For doc please read doc/documented..frontend.h + */ + +#ifndef _FRONTEND_H_ +#define _FRONTEND_H_ + +#include + + +enum return_type { RETURN_OK, RETURN_BACK, RETURN_ERROR }; + +void init_frontend(char * welcome_msg); +void finish_frontend(void); + +void error_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); /* blocking */ +void info_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); /* blocking */ +void wait_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); /* non-blocking */ +void remove_wait_message(void); + +void init_progression(char *msg, int size); +void update_progression(int current_size); +void end_progression(void); + +enum return_type ask_yes_no(char *msg); +enum return_type ask_from_list(char *msg, char ** elems, char ** choice); +enum return_type ask_from_list_comments(char *msg, char ** elems, char ** elems_comments, char ** choice); +enum return_type ask_from_entries(char *msg, char ** questions, char *** answers, int entry_size, void (*callback_func)(char ** strings)); + + +void verror_message(char *msg, va_list ap); +void vinfo_message(char *msg, va_list ap); +void vwait_message(char *msg, va_list ap); + + +#endif diff --git a/init-libc-headers.h b/init-libc-headers.h new file mode 100644 index 0000000..01761e8 --- /dev/null +++ b/init-libc-headers.h @@ -0,0 +1,44 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef SOCK_STREAM +#define SOCK_STREAM 1 +#endif + +static inline _syscall3(int, syslog, int, type, char *, bufp, int, len); +static inline _syscall3(int, reboot, int, magic, int, magic2, int, flag); diff --git a/init.c b/init.c new file mode 100644 index 0000000..37ad1dc --- /dev/null +++ b/init.c @@ -0,0 +1,497 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#ifndef INIT_HEADERS +#include "init-libc-headers.h" +#else +#include INIT_HEADERS +#endif + +#include "config-stage1.h" + +#if defined(__powerpc__) +#define TIOCSCTTY 0x540 +#endif + +char * env[] = { + "PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:/mnt/bin:/mnt/usr/bin", + "LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib:/usr/X11R6/lib:/mnt/usr/X11R6/lib", + "HOME=/", + "TERM=linux", + "TERMINFO=/etc/terminfo", + NULL +}; + + +/* + * this needs to handle the following cases: + * + * 1) run from a CD root filesystem + * 2) run from a read only nfs rooted filesystem + * 3) run from a floppy + * 4) run from a floppy that's been loaded into a ramdisk + * + */ + +int testing; +int klog_pid; + + +void fatal_error(char *msg) +{ + printf("FATAL ERROR IN INIT: %s\n\nI can't recover from this, please reboot manually and send bugreport.\n", msg); + while (1); +} + +void print_error(char *msg) +{ + printf("E: %s\n", msg); +} + +void print_warning(char *msg) +{ + printf("W: %s\n", msg); +} + +void print_int_init(int fd, int i) +{ + char buf[10]; + char * chptr = buf + 9; + int j = 0; + + if (i < 0) + { + write(1, "-", 1); + i = -1 * i; + } + + while (i) + { + *chptr-- = '0' + (i % 10); + j++; + i = i / 10; + } + + write(fd, chptr + 1, j); +} + +void print_str_init(int fd, char * string) +{ + write(fd, string, strlen(string)); +} + + +/* fork to: + * (1) watch /proc/kmsg and copy the stuff to /dev/tty4 + * (2) listens to /dev/log and copy also this stuff (log from programs) + */ +void doklog() +{ + fd_set readset, unixs; + int in, out, i; + int log; + int s; + int sock = -1; + struct sockaddr_un sockaddr; + char buf[1024]; + int readfd; + + /* open kernel message logger */ + in = open("/proc/kmsg", O_RDONLY,0); + if (in < 0) { + print_error("could not open /proc/kmsg"); + return; + } + + if ((log = open("/tmp/syslog", O_WRONLY | O_CREAT, 0644)) < 0) { + print_error("error opening /tmp/syslog"); + sleep(5); + return; + } + + if ((klog_pid = fork())) { + close(in); + close(log); + return; + } else { + close(0); + close(1); + close(2); + } + + out = open("/dev/tty4", O_WRONLY, 0); + if (out < 0) + print_warning("couldn't open tty for syslog -- still using /tmp/syslog\n"); + + /* now open the syslog socket */ +// ############# LINUX 2.4 /dev/log IS BUGGED! --> apparently the syslogs can't reach me, and it's full up after a while +// sockaddr.sun_family = AF_UNIX; +// strncpy(sockaddr.sun_path, "/dev/log", UNIX_PATH_MAX); +// sock = socket(AF_UNIX, SOCK_STREAM, 0); +// if (sock < 0) { +// printf("error creating socket: %d\n", errno); +// sleep(5); +// } +// +// print_str_init(log, "] got socket\n"); +// if (bind(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr.sun_family) + strlen(sockaddr.sun_path))) { +// print_str_init(log, "] bind error: "); +// print_int_init(log, errno); +// print_str_init(log, "\n"); +// sleep(// } +// +// print_str_init(log, "] bound socket\n"); +// chmod("/dev/log", 0666); +// if (listen(sock, 5)) { +// print_str_init(log, "] listen error: "); +// print_int_init(log, errno); +// print_str_init(log, "\n"); +// sleep(5); +// } + + /* disable on-console syslog output */ + syslog(8, NULL, 1); + + print_str_init(log, "] kernel/system logger ok\n"); + FD_ZERO(&unixs); + while (1) { + memcpy(&readset, &unixs, sizeof(unixs)); + + if (sock >= 0) + FD_SET(sock, &readset); + FD_SET(in, &readset); + + i = select(20, &readset, NULL, NULL, NULL); + if (i <= 0) + continue; + + /* has /proc/kmsg things to tell us? */ + if (FD_ISSET(in, &readset)) { + i = read(in, buf, sizeof(buf)); + if (i > 0) { + if (out >= 0) + write(out, buf, i); + write(log, buf, i); + } + } + + /* examine some fd's in the hope to find some syslog outputs from programs */ + for (readfd = 0; readfd < 20; ++readfd) { + if (FD_ISSET(readfd, &readset) && FD_ISSET(readfd, &unixs)) { + i = read(readfd, buf, sizeof(buf)); + if (i > 0) { + /* grep out the output of RPM telling that it installed/removed some packages */ + if (!strstr(buf, "mdk installed") && !strstr(buf, "mdk removed")) { + if (out >= 0) + write(out, buf, i); + write(log, buf, i); + } + } else if (i == 0) { + /* socket closed */ + close(readfd); + FD_CLR(readfd, &unixs); + } + } + } + + /* the socket has moved, new stuff to do */ + if (sock >= 0 && FD_ISSET(sock, &readset)) { + s = sizeof(sockaddr); + readfd = accept(sock, (struct sockaddr *) &sockaddr, &s); + if (readfd < 0) { + char * msg_error = "] error in accept\n"; + if (out >= 0) + write(out, msg_error, strlen(msg_error)); + write(log, msg_error, strlen(msg_error)); + close(sock); + sock = -1; + } + else + FD_SET(readfd, &unixs); + } + } +} + + +#define LOOP_CLR_FD 0x4C01 + +void del_loop(char *device) +{ + int fd; + if ((fd = open(device, O_RDONLY, 0)) < 0) { + printf("del_loop open failed\n"); + return; + } + + if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { + printf("del_loop ioctl failed"); + return; + } + + close(fd); +} + +struct filesystem +{ + char * dev; + char * name; + char * fs; + int mounted; +}; + +/* attempt to unmount all filesystems in /proc/mounts */ +void unmount_filesystems(void) +{ + int fd, size; + char buf[65535]; /* this should be big enough */ + char *p; + struct filesystem fs[500]; + int numfs = 0; + int i, nb; + + printf("unmounting filesystems...\n"); + + fd = open("/proc/mounts", O_RDONLY, 0); + if (fd < 1) { + print_error("failed to open /proc/mounts"); + sleep(2); + return; + } + + size = read(fd, buf, sizeof(buf) - 1); + buf[size] = '\0'; + + close(fd); + + p = buf; + while (*p) { + fs[numfs].mounted = 1; + fs[numfs].dev = p; + while (*p != ' ') p++; + *p++ = '\0'; + fs[numfs].name = p; + while (*p != ' ') p++; + *p++ = '\0'; + fs[numfs].fs = p; + while (*p != ' ') p++; + *p++ = '\0'; + while (*p != '\n') p++; + p++; + if (strcmp(fs[numfs].name, "/") != 0) numfs++; /* skip if root, no need to take initrd root in account */ + } + + /* Pixel's ultra-optimized sorting algorithm: + multiple passes trying to umount everything until nothing moves + anymore (a.k.a holy shotgun method) */ + do { + nb = 0; + for (i = 0; i < numfs; i++) { + /*printf("trying with %s\n", fs[i].name);*/ + if (fs[i].mounted && umount(fs[i].name) == 0) { + if (strncmp(fs[i].dev + sizeof("/dev/") - 1, "loop", + sizeof("loop") - 1) == 0) + del_loop(fs[i].dev); + + printf("\t%s\n", fs[i].name); + fs[i].mounted = 0; + nb++; + } + } + } while (nb); + + for (i = nb = 0; i < numfs; i++) + if (fs[i].mounted) { + printf("\t%s umount failed\n", fs[i].name); + if (strcmp(fs[i].fs, "ext2") == 0) nb++; /* don't count not-ext2 umount failed */ + } + + if (nb) { + printf("failed to umount some filesystems\n"); + while (1); + } +} + +int exit_value_rescue = 66; + +#define DEV_PERM 00400|00200|00040|00020 +#define CHR_DEV 0020000|DEV_PERM +#define BLK_DEV 0060000|DEV_PERM +static _syscall3(int,mknod,char *,a1,mode_t,a2,dev_t,a3) + +int main(int argc, char **argv) +{ + pid_t installpid, childpid; + int wait_status; + int fd; + int abnormal_termination = 0; + int end_stage2 = 0; + //char *argv2[4] = {"ls","-l","/dev/",0}; + + /* getpid() != 1 should work, by linuxrc tends to get a larger pid */ + testing = (getpid() > 50); +/* + mknod("/dev/ram3", BLK_DEV, MKDEV(1,3)); + mknod("/dev/fd0", BLK_DEV, MKDEV(2,0)); + mknod("/dev/loop3", BLK_DEV, MKDEV(7,3)); + + mknod("/dev/mem", CHR_DEV, MKDEV(1,1)); + mknod("/dev/null", CHR_DEV, MKDEV(1,3)); + mknod("/dev/ptyp0", CHR_DEV, MKDEV(2,0)); + mknod("/dev/ttyp0", CHR_DEV, MKDEV(3,0)); + mknod("/dev/tty0", CHR_DEV, MKDEV(4,0)); + mknod("/dev/tty1", CHR_DEV, MKDEV(4,1)); + mknod("/dev/tty2", CHR_DEV, MKDEV(4,2)); + mknod("/dev/tty3", CHR_DEV, MKDEV(4,3)); + mknod("/dev/tty4", CHR_DEV, MKDEV(4,4)); + mknod("/dev/tty5", CHR_DEV, MKDEV(4,5)); + mknod("/dev/tty6", CHR_DEV, MKDEV(4,6)); + mknod("/dev/tty7", CHR_DEV, MKDEV(4,7)); + mknod("/dev/ttyS0", CHR_DEV, MKDEV(4,64)); + mknod("/dev/console", CHR_DEV, MKDEV(5,1)); + mknod("/dev/fb0", CHR_DEV, MKDEV(29,0)); + mknod("/dev/ppp", CHR_DEV, MKDEV(108,0)); +*/ + //execve("/bin/ls",argv2,0); + + if (!testing) { + /* turn off screen blanking */ + printf("\033[9;0]"); + printf("\033[8]"); + } + else + printf("*** TESTING MODE ***\n"); + + + printf("\n\t\t\t\033[1;40mWelcome to \033[1;36mALT Linux\033[0;39m\n\n"); + + if (!testing) { + if (mount("/proc", "/proc", "proc", 0, NULL)) + fatal_error("Unable to mount proc filesystem"); + } + + + /* ignore Control-C and keyboard stop signals */ + signal(SIGINT, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + + + if (!testing) { + fd = open("/dev/tty1", O_RDWR, 0); + if (fd < 0) + /* try with devfs */ + fd = open("/dev/vc/1", O_RDWR, 0); + + if (fd < 0) + fatal_error("failed to open /dev/tty1 and /dev/vc/1"); + + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + close(fd); + } + + + /* I set me up as session leader (probably not necessary?) */ + setsid(); + if (ioctl(0, TIOCSCTTY, NULL)) + print_error("could not set new controlling tty"); + + if (!testing) { + char my_hostname[] = "localhost.localdomain"; + sethostname(my_hostname, sizeof(my_hostname)); + /* the default domainname (as of 2.0.35) is "(none)", which confuses + glibc */ + setdomainname("", 0); + } + + if (!testing) + doklog(); + + /* Go into normal init mode - keep going, and then do a orderly shutdown + when: + + 1) install exits + 2) we receive a SIGHUP + */ + + printf("If more people were to meet doing raklets, this planet\n"); + printf("would be a safer place.\n"); + printf("\n"); + printf("Running install...\n"); + + if (!(installpid = fork())) { + /* child */ + char * child_argv[2]; + child_argv[0] = "/sbin/stage1"; + child_argv[1] = NULL; + + execve(child_argv[0], child_argv, env); + printf("error in exec of stage1 :-(\n"); + return 0; + } + + while (!end_stage2) { + childpid = wait4(-1, &wait_status, 0, NULL); + if (childpid == installpid) + end_stage2 = 1; + } + + if (!WIFEXITED(wait_status) || (WEXITSTATUS(wait_status) != 0 && WEXITSTATUS(wait_status) != exit_value_rescue)) { + printf("wait_status: %i, install exited abnormally :-( ", wait_status); + if (WIFSIGNALED(wait_status)) + printf("-- received signal %d", WTERMSIG(wait_status)); + printf("\n"); + abnormal_termination = 1; + } else if (WIFEXITED(wait_status) && WEXITSTATUS(wait_status) == exit_value_rescue) { + kill(klog_pid, 9); + printf("exiting init -- giving hand to rescue\n"); + return 0; + } else + printf("install succeeded\n"); + + if (testing) + return 0; + + sync(); sync(); + + printf("sending termination signals..."); + kill(-1, 15); + sleep(2); + printf("done\n"); + + printf("sending kill signals..."); + kill(-1, 9); + sleep(2); + printf("done\n"); + + unmount_filesystems(); + + if (!abnormal_termination) { + printf("rebooting system\n"); + sleep(2); + reboot(0xfee1dead, 672274793, 0x01234567); + } else { + printf("you may safely reboot your system\n"); + while (1); + } + + return 0; +} diff --git a/insmod.h b/insmod.h new file mode 100644 index 0000000..d91f239 --- /dev/null +++ b/insmod.h @@ -0,0 +1,20 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _INSMOD_INTERFACE_H_ +#define _INSMOD_INTERFACE_H_ + +int insmod_call(char * full_filename, char * params); + +#endif diff --git a/log b/log new file mode 100644 index 0000000..3afcf04 --- /dev/null +++ b/log @@ -0,0 +1,143 @@ +rm -rf ./tmp_rpm +mkdir ./tmp_rpm +pushd ./tmp_rpm; \ +for f in `cat ./../req`; do \ + rpm2cpio /user/ALT/Sisyphus/files/i586/RPMS/$f-*.rpm | cpio -id; \ +done +/mouse/installer/mdk-stage1/tmp_rpm /mouse/installer/mdk-stage1 +80 blocks +132 blocks +2518 blocks +make[1]: Entering directory `/mouse/installer/mdk-stage1/mar' +make[1]: ãÅÌØ `all' ÎÅ ÔÒÅÂÕÅÔ ×ÙÐÏÌÎÅÎÉÑ ËÏÍÁÎÄ. +make[1]: Leaving directory `/mouse/installer/mdk-stage1/mar' +make[1]: Entering directory `/mouse/installer/mdk-stage1/pci-resource' +perl update-pci-ids.pl > pci-ids.h || rm -f pci-ids.h +Can't locate /usr/bin/merge2pcitable.pl in @INC (@INC contains: /etc/perl5 /usr/lib/perl5/i386-linux /usr/lib/perl5 /usr/local/lib/perl5/site_perl/5.8.1/i386-linux /usr/local/lib/perl5/site_perl/5.8.1 /usr/local/lib/perl5/site_perl /usr/lib/perl5/vendor_perl/i386-linux /usr/lib/perl5/vendor_perl /usr/lib/perl5/vendor_perl .) at update-pci-ids.pl line 7. +make[1]: Leaving directory `/mouse/installer/mdk-stage1/pci-resource' +make[1]: Entering directory `/mouse/installer/mdk-stage1/usb-resource' +perl update-usb-ids.pl > usb-ids.h || rm -f usb-ids.h +Can't locate /usr/bin/merge2pcitable.pl in @INC (@INC contains: /etc/perl5 /usr/lib/perl5/i386-linux /usr/lib/perl5 /usr/local/lib/perl5/site_perl/5.8.1/i386-linux /usr/local/lib/perl5/site_perl/5.8.1 /usr/local/lib/perl5/site_perl /usr/lib/perl5/vendor_perl/i386-linux /usr/lib/perl5/vendor_perl /usr/lib/perl5/vendor_perl .) at update-usb-ids.pl line 33. +make[1]: Leaving directory `/mouse/installer/mdk-stage1/usb-resource' +make[1]: Entering directory `/mouse/installer/mdk-stage1/insmod-busybox' +make[1]: ãÅÌØ `all' ÎÅ ÔÒÅÂÕÅÔ ×ÙÐÏÌÎÅÎÉÑ ËÏÍÁÎÄ. +make[1]: Leaving directory `/mouse/installer/mdk-stage1/insmod-busybox' +make[1]: Entering directory `/mouse/installer/mdk-stage1/slang' +make[1]: ãÅÌØ `all' ÎÅ ÔÒÅÂÕÅÔ ×ÙÐÏÌÎÅÎÉÑ ËÏÍÁÎÄ. +make[1]: Leaving directory `/mouse/installer/mdk-stage1/slang' +make[1]: Entering directory `/mouse/installer/mdk-stage1/newt' +make[1]: ãÅÌØ `all' ÎÅ ÔÒÅÂÕÅÔ ×ÙÐÏÌÎÅÎÉÑ ËÏÍÁÎÄ. +make[1]: Leaving directory `/mouse/installer/mdk-stage1/newt' +make[1]: Entering directory `/mouse/installer/mdk-stage1/ppp/pppd' +gcc -D_linux_=1 -DHAVE_PATHS_H -DIPX_CHANGE -DHAVE_MULTILINK -DHAVE_MMAP -I../include -DCHAPMS=1 -DUSE_CRYPT=1 -DHAVE_CRYPT_H=1 -DMPPE=1 -DHAS_SHADOW -DUSE_PAM -DPLUGIN -c -o auth.o auth.c +auth.c:58:31: security/pam_appl.h: No such file or directory +auth.c:1056: syntax error before '*' token +auth.c:1056: warning: data definition has no type or storage class +auth.c:1064: warning: `struct pam_response' declared inside parameter list +auth.c:1064: warning: its scope is only this definition or declaration, which is probably not what you want +auth.c:1064: warning: `struct pam_message' declared inside parameter list +auth.c: In function `PAM_conv': +auth.c:1071: sizeof applied to an incomplete type +auth.c:1072: `PAM_CONV_ERR' undeclared (first use in this function) +auth.c:1072: (Each undeclared identifier is reported only once +auth.c:1072: for each function it appears in.) +auth.c:1075: dereferencing pointer to incomplete type +auth.c:1076: `PAM_PROMPT_ECHO_ON' undeclared (first use in this function) +auth.c:1077: invalid use of undefined type `struct pam_response' +auth.c:1077: dereferencing pointer to incomplete type +auth.c:1077: `PAM_SUCCESS' undeclared (first use in this function) +auth.c:1078: invalid use of undefined type `struct pam_response' +auth.c:1078: dereferencing pointer to incomplete type +auth.c:1081: `PAM_PROMPT_ECHO_OFF' undeclared (first use in this function) +auth.c:1082: invalid use of undefined type `struct pam_response' +auth.c:1082: dereferencing pointer to incomplete type +auth.c:1083: invalid use of undefined type `struct pam_response' +auth.c:1083: dereferencing pointer to incomplete type +auth.c:1086: `PAM_TEXT_INFO' undeclared (first use in this function) +auth.c:1088: `PAM_ERROR_MSG' undeclared (first use in this function) +auth.c:1090: invalid use of undefined type `struct pam_response' +auth.c:1090: dereferencing pointer to incomplete type +auth.c:1091: invalid use of undefined type `struct pam_response' +auth.c:1091: dereferencing pointer to incomplete type +auth.c: At top level: +auth.c:1104: variable `PAM_conversation' has initializer but incomplete type +auth.c:1105: warning: excess elements in struct initializer +auth.c:1105: warning: (near initialization for `PAM_conversation') +auth.c:1107: warning: excess elements in struct initializer +auth.c:1107: warning: (near initialization for `PAM_conversation') +auth.c: In function `plogin': +auth.c:1132: `PAM_SUCCESS' undeclared (first use in this function) +auth.c:1144: `PAM_TTY' undeclared (first use in this function) +auth.c:1149: `PAM_SILENT' undeclared (first use in this function) +auth.c: In function `plogout': +auth.c:1250: `PAM_SILENT' undeclared (first use in this function) +auth.c: At top level: +auth.c:1104: storage size of `PAM_conversation' isn't known +make[1]: *** [auth.o] ïÛÉÂËÁ 1 +make[1]: Leaving directory `/mouse/installer/mdk-stage1/ppp/pppd' +make[1]: Entering directory `/mouse/installer/mdk-stage1/rp-pppoe/src' +gcc -Wall -Os -fomit-frame-pointer '-DPPPOE_PATH="/sbin/pppoe"' '-DPPPD_PATH="/sbin/pppd"' '-DVERSION="3.0-stg1"' -I. -I../../tmp_rpm/usr/lib/dietlibc/include -I../../tmp_rpm/usr/include -c if.c -o if.o +In file included from if.c:32: +/usr/include/net/ethernet.h:35: syntax error before "u_int8_t" +/usr/include/net/ethernet.h:41: syntax error before "u_int8_t" +/usr/include/net/ethernet.h:43: syntax error before "ether_type" +if.c: In function `openInterface': +if.c:456: warning: implicit declaration of function `strncpy' +make[1]: *** [if.o] ïÛÉÂËÁ 1 +make[1]: Leaving directory `/mouse/installer/mdk-stage1/rp-pppoe/src' +make[1]: Entering directory `/mouse/installer/mdk-stage1/pcmcia' +gcc -Wall -Os -fomit-frame-pointer -pipe -c -I.. -D_BSD_SOURCE -I. -I../tmp_rpm/usr/lib/dietlibc/include -I../tmp_rpm/usr/include -c pcmcia_probe.c -o pcmcia_probe.o +gcc -Wall -Os -fomit-frame-pointer -pipe -c -I.. -D_BSD_SOURCE -I. -I../tmp_rpm/usr/lib/dietlibc/include -I../tmp_rpm/usr/include -c cardmgr.c -o cardmgr.o +cardmgr.c: In function `lookup_card': +cardmgr.c:478: warning: implicit declaration of function `strncmp' +cardmgr.c: In function `adjust_resources': +cardmgr.c:1224: warning: long unsigned int format, u_long arg (arg 3) +cardmgr.c:1224: warning: long unsigned int format, u_long arg (arg 4) +cardmgr.c:1224: warning: long unsigned int format, u_long arg (arg 3) +cardmgr.c:1224: warning: long unsigned int format, u_long arg (arg 4) +gcc -Wall -Os -fomit-frame-pointer -pipe -c -I.. -D_BSD_SOURCE -I. -I../tmp_rpm/usr/lib/dietlibc/include -I../tmp_rpm/usr/include -c lex_config.c -o lex_config.o +lex_config.l: In function `lex_string': +lex_config.l:146: warning: implicit declaration of function `strncpy' +lex_config.l: In function `parse_configfile': +lex_config.l:265: warning: implicit declaration of function `yyparse' +lex_config.l: At top level: +lex_config.l:468: warning: `yyunput' defined but not used +gcc -Wall -Os -fomit-frame-pointer -pipe -c -I.. -D_BSD_SOURCE -I. -I../tmp_rpm/usr/lib/dietlibc/include -I../tmp_rpm/usr/include -c yacc_config.c -o yacc_config.o +y.tab.c: In function `yyparse': +y.tab.c:556: warning: implicit declaration of function `yylex' +ar -cru libpcmcia.a pcmcia_probe.o cardmgr.o lex_config.o yacc_config.o +ranlib libpcmcia.a +gcc -Wall -Os -fomit-frame-pointer -pipe -c -I.. -D_BSD_SOURCE -I../tmp_rpm/usr/lib/dietlibc/include -I. -I../tmp_rpm/usr/include -c pcmcia_probe.c -o pcmcia_probe-DIET.o +gcc -Wall -Os -fomit-frame-pointer -pipe -c -I.. -D_BSD_SOURCE -I../tmp_rpm/usr/lib/dietlibc/include -I. -I../tmp_rpm/usr/include -c cardmgr.c -o cardmgr-DIET.o +cardmgr.c: In function `lookup_card': +cardmgr.c:478: warning: implicit declaration of function `strncmp' +cardmgr.c: In function `adjust_resources': +cardmgr.c:1224: warning: long unsigned int format, u_long arg (arg 3) +cardmgr.c:1224: warning: long unsigned int format, u_long arg (arg 4) +cardmgr.c:1224: warning: long unsigned int format, u_long arg (arg 3) +cardmgr.c:1224: warning: long unsigned int format, u_long arg (arg 4) +gcc -Wall -Os -fomit-frame-pointer -pipe -c -I.. -D_BSD_SOURCE -I../tmp_rpm/usr/lib/dietlibc/include -I. -I../tmp_rpm/usr/include -c lex_config.c -o lex_config-DIET.o +lex_config.l: In function `lex_string': +lex_config.l:146: warning: implicit declaration of function `strncpy' +lex_config.l: In function `parse_configfile': +lex_config.l:265: warning: implicit declaration of function `yyparse' +lex_config.l: At top level: +lex_config.l:468: warning: `yyunput' defined but not used +gcc -Wall -Os -fomit-frame-pointer -pipe -c -I.. -D_BSD_SOURCE -I../tmp_rpm/usr/lib/dietlibc/include -I. -I../tmp_rpm/usr/include -c yacc_config.c -o yacc_config-DIET.o +y.tab.c: In function `yyparse': +y.tab.c:556: warning: implicit declaration of function `yylex' +ar -cru libpcmcia-DIET.a pcmcia_probe-DIET.o cardmgr-DIET.o lex_config-DIET.o yacc_config-DIET.o +ranlib libpcmcia-DIET.a +make[1]: Leaving directory `/mouse/installer/mdk-stage1/pcmcia' +cc -DVERSION=\""strawberry"\" -DSPAWN_SHELL -DDISTRIB_NAME=\""ALT Linux"\" -Os -pipe -Wall -fomit-frame-pointer -DINIT_HEADERS=\"minilibc.h\" -c minilibc.c +In file included from /usr/include/linux/config.h:4, + from /usr/include/linux/net.h:21, + from minilibc.h:53, + from minilibc.c:25: +/usr/include/linux/autoconf.h:1:2: #error Invalid kernel header included in userspace +In file included from minilibc.c:25: +minilibc.h:135: warning: conflicting types for built-in function `strncmp' +minilibc.h:137: warning: conflicting types for built-in function `strstr' +minilibc.h:138: warning: conflicting types for built-in function `strncpy' +minilibc.h:143: warning: conflicting types for built-in function `printf' +make: *** [minilibc.o] ïÛÉÂËÁ 1 diff --git a/log.c b/log.c new file mode 100644 index 0000000..5379c96 --- /dev/null +++ b/log.c @@ -0,0 +1,85 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "stage1.h" + +#include "log.h" + +static FILE * logfile = NULL; + + +void vlog_message(const char * s, va_list args) +{ + fprintf(logfile, "* "); + vfprintf(logfile, s, args); + fprintf(logfile, "\n"); + fflush(logfile); +} + + +void log_message(const char * s, ...) +{ + va_list args; + + if (!logfile) { + fprintf(stderr, "Log is not open!\n"); + return; + } + + va_start(args, s); + vlog_message(s, args); + va_end(args); + + return; +} + +void log_perror(char *msg) +{ + log_message("%s: %s", msg, strerror(errno)); +} + + +void open_log(void) +{ + if (!IS_TESTING) { + logfile = fopen("/dev/tty3", "w"); + if (!logfile) + logfile = fopen("/tmp/install.log", "a"); + } + else + logfile = fopen("debug.log", "w"); +} + +void close_log(void) +{ + if (logfile) { + log_message("stage1: disconnecting life support systems"); + fclose(logfile); + } +} diff --git a/log.h b/log.h new file mode 100644 index 0000000..90aa3f6 --- /dev/null +++ b/log.h @@ -0,0 +1,34 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + + +#ifndef _LOG_H_ +#define _LOG_H_ + +#include + +void log_message(const char * s, ...) __attribute__ ((format (printf, 1, 2))); +void vlog_message(const char * s, va_list args); +void log_perror(char *msg); +void open_log(void); +void close_log(void); + +#endif diff --git a/lomount.c b/lomount.c new file mode 100644 index 0000000..991a862 --- /dev/null +++ b/lomount.c @@ -0,0 +1,171 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* This code comes from util-linux-2.10n (mount/lomount.c) + * (this is a simplified version of this code) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stage1.h" +#include "frontend.h" +#include "log.h" +#include "mount.h" +#include "modules.h" + +#include "lomount.h" + + +#define LO_NAME_SIZE 64 +#define LO_KEY_SIZE 32 + +struct loop_info +{ + int lo_number; /* ioctl r/o */ + dev_t lo_device; /* ioctl r/o */ + unsigned long lo_inode; /* ioctl r/o */ + dev_t lo_rdevice; /* ioctl r/o */ + int lo_offset; + int lo_encrypt_type; + int lo_encrypt_key_size; /* ioctl w/o */ + int lo_flags; /* ioctl r/o */ + char lo_name[LO_NAME_SIZE]; + unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ + unsigned long lo_init[2]; + char reserved[4]; +}; + +#define LOOP_SET_FD 0x4C00 +#define LOOP_CLR_FD 0x4C01 +#define LOOP_SET_STATUS 0x4C02 +#define LOOP_GET_STATUS 0x4C03 + +int +set_loop (const char *device, const char *file) +{ + struct loop_info loopinfo; + int fd, ffd, mode; + + mode = O_RDONLY; + + if ((ffd = open (file, mode)) < 0) + return 1; + + if ((fd = open (device, mode)) < 0) { + close(ffd); + return 1; + } + + memset(&loopinfo, 0, sizeof (loopinfo)); + strncpy(loopinfo.lo_name, file, LO_NAME_SIZE); + loopinfo.lo_name[LO_NAME_SIZE - 1] = 0; + loopinfo.lo_offset = 0; + +#ifdef MCL_FUTURE + /* + * Oh-oh, sensitive data coming up. Better lock into memory to prevent + * passwd etc being swapped out and left somewhere on disk. + */ + + if(mlockall(MCL_CURRENT|MCL_FUTURE)) { + log_message("CRITICAL Couldn't lock into memory! %s (memlock)", strerror(errno)); + return 1; + } +#endif + + if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { + close(fd); + close(ffd); + return 1; + } + + if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) { + (void) ioctl (fd, LOOP_CLR_FD, 0); + close(fd); + close(ffd); + return 1; + } + + close(fd); + close(ffd); + return 0; +} + + +char * loopdev = "/dev/loop3"; /* Ugly. But do I care? */ + +void +del_loop(void) +{ + int fd; + + if ((fd = open (loopdev, O_RDONLY)) < 0) + return; + + if (ioctl (fd, LOOP_CLR_FD, 0) < 0) + return; + + close (fd); +} + + +static char * where_mounted = NULL; + +int +lomount(char *loopfile, char *where) +{ + + long int flag; + + flag = MS_MGC_VAL; + flag |= MS_RDONLY; + + my_insmod("loop", ANY_DRIVER_TYPE, NULL); + + if (set_loop(loopdev, loopfile)) { + log_message("set_loop failed on %s (%s)", loopdev, strerror(errno)); + return 1; + } + + if (my_mount(loopdev, where, "iso9660", 0)) { + del_loop(); + return 1; + } + + where_mounted = strdup(where); + log_message("lomount succeeded for %s on %s", loopfile, where); + return 0; +} + + +int +loumount() +{ + if (where_mounted) { + umount(where_mounted); + where_mounted = NULL; + } + del_loop(); + return 0; +} + + diff --git a/lomount.h b/lomount.h new file mode 100644 index 0000000..3b8a30a --- /dev/null +++ b/lomount.h @@ -0,0 +1,21 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef LOMOUNT_H +#define LOMOUNT_H + +int lomount(char *loopfile, char *where); +int loumount(void); + +#endif diff --git a/minilibc.c b/minilibc.c new file mode 100644 index 0000000..77b65ac --- /dev/null +++ b/minilibc.c @@ -0,0 +1,251 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + + +#define MINILIBC_INTERNAL + +#include "minilibc.h" + +int atexit (void (*__func) (void)) +{ + return 0; +} + +void exit() +{ + _do_exit(0); + for (;;); /* Shut up gcc */ +} + + +char ** _environ = NULL; +int errno = 0; + +void _init (int __status) +{ +} + +void __libc_init_first (int __status) +{ +} + +int __libc_start_main (int (*main) (int, char **, char **), int argc, + char **argv, void (*init) (void), void (*fini) (void), + void (*rtld_fini) (void), void *stack_end) +{ + exit ((*main) (argc, argv, NULL)); + /* never get here */ + return 0; +} + +void _fini (int __status) +{ +} + +inline int socket(int a, int b, int c) +{ + unsigned long args[] = { a, b, c }; + + return socketcall(SYS_SOCKET, args); +} + +inline int bind(int a, void * b, int c) +{ + unsigned long args[] = { a, (long) b, c }; + + return socketcall(SYS_BIND, args); +} + +inline int listen(int a, int b) +{ + unsigned long args[] = { a, b, 0 }; + + return socketcall(SYS_LISTEN, args); +} + +inline int accept(int a, void * addr, void * addr2) +{ + unsigned long args[] = { a, (long) addr, (long) addr2 }; + + return socketcall(SYS_ACCEPT, args); +} + + +void sleep(int secs) +{ + struct timeval tv; + + tv.tv_sec = secs; + tv.tv_usec = 0; + + select(0, NULL, NULL, NULL, &tv); +} + + +int strlen(const char * string) +{ + int i = 0; + + while (*string++) i++; + + return i; +} + +char * strncpy(char * dst, const char * src, int len) +{ + char * chptr = dst; + int i = 0; + + while (*src && i < len) *dst++ = *src++, i++; + if (i < len) *dst = '\0'; + + return chptr; +} + +char * strcpy(char * dst, const char * src) +{ + char * chptr = dst; + + while (*src) *dst++ = *src++; + *dst = '\0'; + + return chptr; +} + +void * memcpy(void * dst, const void * src, size_t count) +{ + char * a = dst; + const char * b = src; + + while (count--) + *a++ = *b++; + + return dst; +} + + +int strcmp(const char * a, const char * b) +{ + int i, j; + + i = strlen(a); j = strlen(b); + if (i < j) + return -1; + else if (j < i) + return 1; + + while (*a && (*a == *b)) a++, b++; + + if (!*a) return 0; + + if (*a < *b) + return -1; + else + return 1; +} + +int strncmp(const char * a, const char * b, int len) +{ + char buf1[1000], buf2[1000]; + + strncpy(buf1, a, len); + strncpy(buf2, b, len); + buf1[len] = '\0'; + buf2[len] = '\0'; + + return strcmp(buf1, buf2); +} + +char * strchr(char * str, int ch) +{ + char * chptr; + + chptr = str; + while (*chptr) + { + if (*chptr == ch) return chptr; + chptr++; + } + + return NULL; +} + + +char * strstr(char *haystack, char *needle) +{ + char * tmp = haystack; + while ((tmp = strchr(tmp, needle[0])) != NULL) { + int i = 1; + while (i < strlen(tmp) && i < strlen(needle) && tmp[i] == needle[i]) + i++; + if (needle[i] == '\0') + return tmp; + tmp++; + } + return NULL; +} + + +/* Minimum printf which handles only characters, %d's and %s's */ +void printf(char * fmt, ...) +{ + char buf[2048]; + char * start = buf; + char * chptr = buf; + va_list args; + char * strarg; + int numarg; + + strncpy(buf, fmt, sizeof(buf)); + va_start(args, fmt); + + while (start) + { + while (*chptr != '%' && *chptr) chptr++; + + if (*chptr == '%') + { + *chptr++ = '\0'; + print_str_init(1, start); + + switch (*chptr++) + { + case 's': + strarg = va_arg(args, char *); + print_str_init(1, strarg); + break; + + case 'd': + numarg = va_arg(args, int); + print_int_init(1, numarg); + break; + } + + start = chptr; + } + else + { + print_str_init(1, start); + start = NULL; + } + } +} + diff --git a/minilibc.h b/minilibc.h new file mode 100644 index 0000000..e0775e3 --- /dev/null +++ b/minilibc.h @@ -0,0 +1,144 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + + +#include + +#define _LOOSE_KERNEL_NAMES 1 + +#define NULL ((void *) 0) + +#define WIFSTOPPED(status) (((status) & 0xff) == 0x7f) +#define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status)) +#define WEXITSTATUS(status) (((status) & 0xff00) >> 8) +#define WTERMSIG(status) ((status) & 0x7f) +#define WSTOPSIG(status) WEXITSTATUS(status) +#define WIFEXITED(status) (WTERMSIG(status) == 0) + +#define MS_MGC_VAL 0xc0ed0000 + +#define isspace(a) (a == ' ' || a == '\t') + +extern char ** _environ; + +extern int errno; + +/* Aieee, gcc 2.95+ creates a stub for posix_types.h on i386 which brings + glibc headers in and thus makes __FD_SET etc. not defined with 2.3+ kernels. */ +#define _FEATURES_H 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef MINILIBC_INTERNAL +static inline _syscall5(int,mount,const char *,spec,const char *,dir,const char *,type,unsigned long,rwflag,const void *,data); +static inline _syscall5(int,_newselect,int,n,fd_set *,rd,fd_set *,wr,fd_set *,ex,struct timeval *,timeval); +static inline _syscall4(int,wait4,pid_t,pid,int *,status,int,opts,void *,rusage) +static inline _syscall3(int,write,int,fd,const char *,buf,unsigned long,count) +static inline _syscall3(int,reboot,int,magic,int,magic_too,int,flag) +static inline _syscall3(int,execve,const char *,fn,void *,argv,void *,envp) +static inline _syscall3(int,read,int,fd,const char *,buf,unsigned long,count) +static inline _syscall3(int,open,const char *,fn,int,flags,mode_t,mode) +static inline _syscall3(int,ioctl,int,fd,int,request,void *,argp) +static inline _syscall2(int,dup2,int,one,int,two) +static inline _syscall2(int,kill,pid_t,pid,int,sig) +static inline _syscall2(int,symlink,const char *,a,const char *,b) +static inline _syscall2(int,chmod,const char * ,path,mode_t,mode) +static inline _syscall2(int,sethostname,const char *,name,int,len) +static inline _syscall2(int,setdomainname,const char *,name,int,len) +static inline _syscall2(int,setpgid,int,name,int,len) +static inline _syscall2(int,signal,int,num,void *,len) +static inline _syscall1(int,umount,const char *,dir) +static inline _syscall1(int,unlink,const char *,fn) +static inline _syscall1(int,close,int,fd) +static inline _syscall1(int,swapoff,const char *,fn) +static inline _syscall0(int,getpid) +static inline _syscall0(int,sync) +#ifdef __sparc__ +/* Nonstandard fork calling convention :( */ +static inline int fork(void) { + int __res; + __asm__ __volatile__ ( + "mov %0, %%g1\n\t" + "t 0x10\n\t" + "bcc 1f\n\t" + "dec %%o1\n\t" + "sethi %%hi(%2), %%g1\n\t" + "st %%o0, [%%g1 + %%lo(%2)]\n\t" + "b 2f\n\t" + "mov -1, %0\n\t" + "1:\n\t" + "and %%o0, %%o1, %0\n\t" + "2:\n\t" + : "=r" (__res) + : "0" (__NR_fork), "i" (&errno) + : "g1", "o0", "cc"); + return __res; +} +#else +static inline _syscall0(int,fork) +#endif +static inline _syscall0(pid_t,setsid) +static inline _syscall3(int,syslog,int, type, char *, buf, int, len); +#else +static inline _syscall5(int,_newselect,int,n,fd_set *,rd,fd_set *,wr,fd_set *,ex,struct timeval *,timeval); +static inline _syscall3(int,write,int,fd,const char *,buf,unsigned long,count) +static inline _syscall2(int,socketcall,int,code,unsigned long *, args) +#define __NR__do_exit __NR_exit +extern inline _syscall1(int,_do_exit,int,exitcode) +#endif + +#define select _newselect + +extern int errno; + +inline int socket(int a, int b, int c); +inline int bind(int a, void * b, int c); +inline int listen(int a, int b); +inline int accept(int a, void * addr, void * addr2); + +void sleep(int secs); + +int strlen(const char * string); +char * strcpy(char * dst, const char * src); +void * memcpy(void * dst, const void * src, size_t count); +int strcmp(const char * a, const char * b); +int strncmp(const char * a, const char * b, int len); +char * strchr(char * str, int ch); +char * strstr(char *haystack, char *needle); +char * strncpy(char * dst, const char * src, int len); + +void print_str_init(int fd, char * string); +void print_int_init(int fd, int i); +/* Minimum printf which handles only characters, %d's and %s's */ +void printf(char * fmt, ...) __attribute__ ((format (printf, 1, 2))); + diff --git a/mkinitrd_helper/Makefile b/mkinitrd_helper/Makefile new file mode 100644 index 0000000..27b46d2 --- /dev/null +++ b/mkinitrd_helper/Makefile @@ -0,0 +1,46 @@ + #****************************************************************************** + # + # Guillaume Cottenceau (gc@mandrakesoft.com) + # + # Copyright 2000 MandrakeSoft + # + # This software may be freely redistributed under the terms of the GNU + # public license. + # + # You should have received a copy of the GNU General Public License + # along with this program; if not, write to the Free Software + # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + # + #***************************************************************************** + +top_dir = .. + +include $(top_dir)/Makefile.common + + +VERSION = 1.1.1 + +DEFS = -DVERSION=\"$(VERSION)\" + + +MKINITRD_HELPER_SRC = mkinitrd_helper.c +MKINITRD_HELPER_LIBS = ../insmod-busybox/libinsmod-DIET.a + +MKINITRD_HELPER_OBJS = $(subst .c,.o,$(MKINITRD_HELPER_SRC)) + +BIN = mkinitrd_helper + +all: $(BIN) + +clean: + rm -f *.o $(BIN) + +FLAGS = -Wall -Os -fomit-frame-pointer -c + + +$(MKINITRD_HELPER_OBJS): %.o: %.c + $(CC) $(DEFS) $(DIETLIBC_INCLUDES) -I.. -c $< -o $@ + +mkinitrd_helper: $(MKINITRD_HELPER_OBJS) $(MKINITRD_HELPER_LIBS) $(DIETLIBC_LIBC) + $(CC) $(DIETLIBC_LDFLAGS_STAGE1) -o $@ $^ + $(STRIPCMD) $@ diff --git a/mkinitrd_helper/mkinitrd_helper.c b/mkinitrd_helper/mkinitrd_helper.c new file mode 100644 index 0000000..67be7c3 --- /dev/null +++ b/mkinitrd_helper/mkinitrd_helper.c @@ -0,0 +1,308 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2001 MandrakeSoft + * + * This software is covered by the GPL license. + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * This little program replaces usual sash and insmod.static based script + * from mkinitrd (that insmod modules, plus possibly mount a partition and + * losetup a loopback-based / on the partition). + * + * + * On my machine: + * gzipped sash + insmod.static 502491 bytes + * gzipped 14243 bytes + * + * There will be room for linux-2.4 and many modules, now. Cool. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "insmod.h" + +int quiet = 0; + +void vlog_message(const char * s, va_list args) +{ + vprintf(s, args); + printf("\n"); +} + +void log_perror(char *msg) +{ + perror(msg); +} + + +static void fatal_error(char *msg) +{ + printf("[] E: %s\n[] giving hand to kernel.\n", msg); + exit(-1); +} + +static void warning(char *msg) +{ + printf("[] W: %s\n", msg); +} + +static void parse_parms(const char * parm, char ** parm1, char ** parm2, char ** parm3) +{ + char * ptr; + + ptr = strchr(parm, '\n'); + if (!ptr) + fatal_error("bad config file: no newline after parms"); + + *parm1 = malloc(ptr-parm+1); /* yup, never freed :-) */ + memcpy(*parm1, parm, ptr-parm); + (*parm1)[ptr-parm] = '\0'; + + if (!parm2) + return; + + *parm2 = strchr(*parm1, ' '); + if (!*parm2) + return; + **parm2 = '\0'; + (*parm2)++; + + if (!parm3) + return; + + *parm3 = strchr(*parm2, ' '); + if (!*parm3) + return; + **parm3 = '\0'; + (*parm3)++; +} + + +static void insmod_(const char * parm) +{ + char * mod_name, * options; + + parse_parms(parm, &mod_name, &options, NULL); + +#ifdef DEBUG + printf("insmod %s options %s\n", mod_name, options); +#endif + if (!quiet) + printf("[] Loading module %s\n", mod_name); + + if (insmod_call(mod_name, options)) + perror("insmod failed"); +} + + +static void mount_(const char * parm) +{ + char * dev, * location, * fs; + unsigned long flags; + char * opts = NULL; + + parse_parms(parm, &dev, &location, &fs); + +#ifdef DEBUG + printf("mounting %s on %s as type %s\n", dev, location, fs); +#endif + if (!quiet) + printf("[] Mounting device containing loopback root filesystem\n"); + + flags = MS_MGC_VAL; + + if (!strcmp(fs, "vfat")) + opts = "check=relaxed"; + + if (mount(dev, location, fs, flags, opts)) + perror("mount failed"); +} + + +#define LO_NAME_SIZE 64 +#define LO_KEY_SIZE 32 + +struct loop_info +{ + int lo_number; /* ioctl r/o */ + dev_t lo_device; /* ioctl r/o */ + unsigned long lo_inode; /* ioctl r/o */ + dev_t lo_rdevice; /* ioctl r/o */ + int lo_offset; + int lo_encrypt_type; + int lo_encrypt_key_size; /* ioctl w/o */ + int lo_flags; /* ioctl r/o */ + char lo_name[LO_NAME_SIZE]; + unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ + unsigned long lo_init[2]; + char reserved[4]; +}; + +#define LOOP_SET_FD 0x4C00 +#define LOOP_CLR_FD 0x4C01 +#define LOOP_SET_STATUS 0x4C02 + +static void set_loop_(const char * parm) +{ + struct loop_info loopinfo; + int fd, ffd; + char * device, * file; + + parse_parms(parm, &device, &file, NULL); + +#ifdef DEBUG + printf("set_looping %s with %s\n", device, file); +#endif + if (!quiet) + printf("[] Setting up loopback file %s\n", file); + + if ((ffd = open(file, O_RDWR)) < 0) { + perror("set_loop, opening file in rw"); + exit(-1); + } + + if ((fd = open(device, O_RDWR)) < 0) { + perror("set_loop, opening loop device in rw"); + close(ffd); + exit(-1); + } + + memset(&loopinfo, 0, sizeof (loopinfo)); + strncpy(loopinfo.lo_name, file, LO_NAME_SIZE); + loopinfo.lo_name[LO_NAME_SIZE - 1] = 0; + loopinfo.lo_offset = 0; + + if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { + close(fd); + close(ffd); + perror("LOOP_SET_FD"); + exit(-1); + } + + if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) { + (void) ioctl (fd, LOOP_CLR_FD, 0); + close(fd); + close(ffd); + perror("LOOP_SET_STATUS"); + exit(-1); + } + + close(fd); + close(ffd); +} + + +#define MD_MAJOR 9 +#define RAID_AUTORUN _IO (MD_MAJOR, 0x14) +#include + +static void raidautorun_(const char * parm) +{ + char * device; + int fd; + + parse_parms(parm, &device, NULL, NULL); + + if (!quiet) + printf("[] Calling raid autorun for %s\n", device); + + fd = open(device, O_RDWR, 0); + if (fd < 0) { + printf("raidautorun: failed to open %s: %d\n", device, errno); + return; + } + + if (ioctl(fd, RAID_AUTORUN, 0)) { + printf("raidautorun: RAID_AUTORUN failed: %d\n", errno); + } + + close(fd); +} + +static int handle_command(char ** ptr, char * cmd_name, void (*cmd_func)(const char * parm)) +{ + if (!strncmp(*ptr, cmd_name, strlen(cmd_name))) { + *ptr = strchr(*ptr, '\n'); + if (!*ptr) + fatal_error("Bad config file: no newline after command"); + (*ptr)++; + cmd_func(*ptr); + *ptr = strchr(*ptr, '\n'); + if (!*ptr) + exit(0); + (*ptr)++; + return 1; + } + return 0; +} + + +int main(int argc, char **argv) +{ + int fd_conf, i; + char buf[5000]; + char * ptr; + + if (strstr(argv[0], "modprobe")) + exit(0); + + if (mount("/proc", "/loopfs", "proc", 0, NULL)) + printf("[] couldn't mount proc filesystem\n"); + else { + int fd_cmdline = open("/loopfs/cmdline", O_RDONLY); + if (fd_cmdline > 0) { + i = read(fd_cmdline, buf, sizeof(buf)); + if (i == -1) + warning("could not read cmdline"); + else { + buf[i] = '\0'; + if (strstr(buf, "quiet")) + quiet = 1; + } + close(fd_cmdline); + } + umount("/loopfs"); + } + + if (!quiet) + printf("[] initrd_helper v" VERSION "\n"); + + if ((fd_conf = open("/mkinitrd_helper.conf", O_RDONLY)) < 0) + fatal_error("could not open mkinitrd_helper config file"); + + i = read(fd_conf, buf, sizeof(buf)); + if (i == -1) + fatal_error("could not read mkinitrd_helper config file"); + buf[i] = '\0'; + close(fd_conf); + + ptr = buf; + + while (*ptr) + if (!(handle_command(&ptr, "insmod", insmod_) + + handle_command(&ptr, "mount", mount_) + + handle_command(&ptr, "raidautorun", raidautorun_) + + handle_command(&ptr, "set_loop", set_loop_))) + warning("unkown command (trying to continue)"); + + return 0; +} diff --git a/modules.c b/modules.c new file mode 100644 index 0000000..f76e5c1 --- /dev/null +++ b/modules.c @@ -0,0 +1,446 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * (1) calculate dependencies + * (2) unarchive relevant modules + * (3) insmod them + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "insmod.h" +#include "stage1.h" +#include "log.h" +#include "mar/mar-extract-only.h" +#include "frontend.h" +#include "mount.h" +#include "modules_descr.h" + +#include "modules.h" + +static struct module_deps_elem * modules_deps = NULL; + +static char * archive_name = "/modules/modules.mar"; +int disable_modules = 0; + + +/* unarchive and insmod given module + * WARNING: module must not contain the trailing ".o" + */ +static enum insmod_return insmod_archived_file(const char * mod_name, char * options) +{ + char module_name[50]; + char final_name[50] = "/tmp/"; + int i, rc; + + strncpy(module_name, mod_name, sizeof(module_name)); + strcat(module_name, ".ko"); + i = mar_extract_file(archive_name, module_name, "/tmp/"); + if (i == 1) { + log_message("file-not-found-in-archive %s", module_name); + return INSMOD_FAILED_FILE_NOT_FOUND; + } + if (i != 0) + return INSMOD_FAILED; + + strcat(final_name, mod_name); + strcat(final_name, ".ko"); + + rc = insmod_call(final_name, options); + unlink(final_name); /* sucking no space left on device */ + if (rc) { + log_message("\tfailed"); + return INSMOD_FAILED; + } + return INSMOD_OK; +} + + + +static int load_modules_dependencies(void) +{ + char * deps_file = "/modules/modules.dep"; + char * buf, * ptr, * start, * end; + struct stat s; + int fd, line, i; + + log_message("loading modules dependencies"); + + if (IS_TESTING) + return 0; + + fd = open(deps_file, O_RDONLY); + if (fd == -1) { + log_perror(deps_file); + return -1; + } + + fstat(fd, &s); + buf = alloca(s.st_size + 1); + if (read(fd, buf, s.st_size) != s.st_size) { + log_perror(deps_file); + return -1; + } + buf[s.st_size] = '\0'; + close(fd); + + ptr = buf; + line = 0; + while (ptr) { + line++; + ptr = strchr(ptr + 1, '\n'); + } + + modules_deps = malloc(sizeof(*modules_deps) * (line+1)); + + start = buf; + line = 0; + while (start < (buf+s.st_size) && *start) { + char * tmp_deps[50]; + + end = strchr(start, '\n'); + *end = '\0'; + + ptr = strchr(start, ':'); + if (!ptr) { + start = end + 1; + continue; + } + *ptr = '\0'; + ptr++; + + while (*ptr && (*ptr == ' ')) ptr++; + if (!*ptr) { + start = end + 1; + continue; + } + + /* sort of a good line */ + modules_deps[line].name = strdup(start); + + start = ptr; + i = 0; + while (start && *start) { + ptr = strchr(start, ' '); + if (ptr) *ptr = '\0'; + tmp_deps[i++] = strdup(start); + if (ptr) + start = ptr + 1; + else + start = NULL; + while (start && *start && *start == ' ') + start++; + } + tmp_deps[i++] = NULL; + + modules_deps[line].deps = memdup(tmp_deps, sizeof(char *) * i); + + line++; + start = end + 1; + } + modules_deps[line].name = NULL; + + return 0; +} + + +void init_modules_insmoding(void) +{ + if (load_modules_dependencies()) { + log_message("warning, error initing modules stuff, modules loading disabled"); + disable_modules = 1; + } +} + + +static void add_modules_conf(char * str) +{ + static char data[500] = ""; + char * target = "/etc/modules.conf"; + int fd; + + if (strlen(data) + strlen(str) >= sizeof(data)) + return; + + strcat(data, str); + strcat(data, "\n"); + + fd = open(target, O_CREAT|O_WRONLY|O_TRUNC, 00660); + + if (fd == -1) { + log_perror(str); + return; + } + + if (write(fd, data, strlen(data) + 1) != strlen(data) + 1) + log_perror(str); + + close(fd); +} + + +static int module_already_present(const char * name) +{ + FILE * f; + int answ = 0; + f = fopen("/proc/modules", "rb"); + while (1) { + char buf[500]; + if (!fgets(buf, sizeof(buf), f)) break; + if (!strncmp(name, buf, strlen(name)) && buf[strlen(name)] == ' ') + answ = 1; + } + fclose(f); + return answ; +} + + +static enum insmod_return insmod_with_deps(const char * mod_name, char * options) +{ + struct module_deps_elem * dep; + + dep = modules_deps; + while (dep && dep->name && strcmp(dep->name, mod_name)) dep++; + + if (dep && dep->name && dep->deps) { + char ** one_dep; + one_dep = dep->deps; + while (*one_dep) { + /* here, we can fail but we don't care, if the error is + * important, the desired module will fail also */ + insmod_with_deps(*one_dep, NULL); + one_dep++; + } + } + + if (module_already_present(mod_name)) + return INSMOD_OK; + + log_message("needs %s", mod_name); + return insmod_archived_file(mod_name, options); +} + + +enum insmod_return my_insmod(const char * mod_name, enum driver_type type, char * options) +{ + char alias[500]; + int i; +#ifndef DISABLE_MEDIAS + static int number_scsi = 0; +#endif +#ifndef DISABLE_NETWORK + char ** net_devices = NULL; /* fucking compiler */ +#endif + + log_message("have to insmod %s", mod_name); + + if (disable_modules) { + log_message("\tdisabled"); + return INSMOD_OK; + } + +#ifndef DISABLE_NETWORK + if (type == NETWORK_DEVICES) + net_devices = get_net_devices(); +#endif + + if (IS_TESTING) + return INSMOD_OK; + + i = insmod_with_deps(mod_name, options); + if (i == 0) { + log_message("\tsucceeded %s", mod_name); +#ifndef DISABLE_MEDIAS + if (type == SCSI_ADAPTERS) { + if (number_scsi > 0) + sprintf(alias, "alias scsi_hostadapter%d %s", number_scsi, mod_name); + else + sprintf(alias, "alias scsi_hostadapter %s", mod_name); + number_scsi++; + add_modules_conf(alias); + log_message("SCSI: %s", alias); + } +#endif +#ifndef DISABLE_NETWORK + if (type == NETWORK_DEVICES) { + char ** new_net_devices = get_net_devices(); + while (new_net_devices && *new_net_devices) { + char ** ptr = net_devices; + while (ptr && *ptr) { + if (!strcmp(*new_net_devices, *ptr)) + goto already_present; + ptr++; + } + sprintf(alias, "alias %s %s", *new_net_devices, mod_name); + add_modules_conf(alias); + log_message("NET: %s", alias); + net_discovered_interface(*new_net_devices); + + already_present: + new_net_devices++; + } + } +#endif + } else + log_message("warning, insmod failed (%s %s) (%d)", mod_name, options, i); + + return i; + +} + +static enum return_type insmod_with_options(char * mod, enum driver_type type) +{ + char * questions[] = { "Options", NULL }; + static char ** answers = NULL; + enum return_type results; + char options[500] = "options "; + + results = ask_from_entries("Please enter the parameters to give to the kernel:", questions, &answers, 24, NULL); + if (results != RETURN_OK) + return results; + + strcat(options, mod); + strcat(options, " "); + strcat(options, answers[0]); // because my_insmod will eventually modify the string + + if (my_insmod(mod, type, answers[0]) != INSMOD_OK) { + stg1_error_message("Insmod failed."); + return RETURN_ERROR; + } + + add_modules_conf(options); + + return RETURN_OK; +} + +enum return_type ask_insmod(enum driver_type type) +{ + char * mytype; + char msg[200]; + enum return_type results; + char * choice; + + unset_param(MODE_AUTOMATIC); /* we are in a fallback mode */ + + if (type == SCSI_ADAPTERS) + mytype = "SCSI"; + else if (type == NETWORK_DEVICES) + mytype = "NET"; + else + return RETURN_ERROR; + + if (disable_modules) + return RETURN_BACK; + + snprintf(msg, sizeof(msg), "Which driver should I try to gain %s access?", mytype); + + { + char ** drivers = mar_list_contents(archive_name); + char ** descrs = malloc(sizeof(char *) * string_array_length(drivers)); + char ** p_drivers = drivers; + char ** p_descrs = descrs; + while (p_drivers && *p_drivers) { + int i; + *p_descrs = NULL; + for (i = 0 ; i < modules_descriptions_num ; i++) { + if (!strncmp(*p_drivers, modules_descriptions[i].module, strlen(modules_descriptions[i].module)) + && (*p_drivers)[strlen(modules_descriptions[i].module)] == '.') /* one contains '.o' not the other */ + *p_descrs = modules_descriptions[i].descr; + } + p_drivers++; + p_descrs++; + } + results = ask_from_list_comments(msg, drivers, descrs, &choice); + } + + if (results == RETURN_OK) { + choice[strlen(choice)-3] = '\0'; /* remove trailing .ko */ + return insmod_with_options(choice, type); + } else + return results; +} + + +void update_modules(void) +{ + FILE * f; + char ** disk_contents; + char final_name[500]; + char floppy_mount_location[] = "/tmp/floppy"; + + stg1_info_message("Please insert the Update Modules floppy.");; + + my_insmod("floppy", ANY_DRIVER_TYPE, NULL); + + if (my_mount("/dev/fd0", floppy_mount_location, "ext2", 0) == -1) { + enum return_type results = ask_yes_no("I can't find a Linux ext2 floppy in first floppy drive.\n" + "Retry?"); + if (results == RETURN_OK) + return update_modules(); + return; + } + + disk_contents = list_directory(floppy_mount_location); + + if (!(f = fopen("/tmp/floppy/to_load", "rb"))) { + stg1_error_message("I can't find \"to_load\" file."); + umount(floppy_mount_location); + return update_modules(); + } + while (1) { + char module[500]; + char * options; + char ** entry = disk_contents; + + if (!fgets(module, sizeof(module), f)) break; + if (module[0] == '#' || strlen(module) == 0) + continue; + + while (module[strlen(module)-1] == '\n') + module[strlen(module)-1] = '\0'; + options = strchr(module, ' '); + if (options) { + options[0] = '\0'; + options++; + } + + log_message("updatemodules: (%s) (%s)", module, options); + while (entry && *entry) { + if (!strncmp(*entry, module, strlen(module)) && (*entry)[strlen(module)] == '.') { + sprintf(final_name, "%s/%s", floppy_mount_location, *entry); + if (insmod_call(final_name, options)) { + log_message("\t%s (floppy): failed", *entry); + stg1_error_message("Insmod %s (floppy) failed.", *entry); + } + break; + } + entry++; + } + if (!entry || !*entry) { + enum insmod_return ret = my_insmod(module, ANY_DRIVER_TYPE, options); + if (ret != INSMOD_OK) { + log_message("\t%s (marfile): failed", module); + stg1_error_message("Insmod %s (marfile) failed.", module); + } + } + } + fclose(f); +} diff --git a/modules.h b/modules.h new file mode 100644 index 0000000..a5fccb6 --- /dev/null +++ b/modules.h @@ -0,0 +1,35 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _MODULES_H_ +#define _MODULES_H_ + +#include "stage1.h" +#include "probing.h" + +enum insmod_return { INSMOD_OK, INSMOD_FAILED, INSMOD_FAILED_FILE_NOT_FOUND }; + +void init_modules_insmoding(void); +enum insmod_return my_insmod(const char * mod_name, enum driver_type type, char * options); +enum return_type ask_insmod(enum driver_type); +void update_modules(void); + +struct module_deps_elem { + char * name; + char ** deps; +}; + +extern int disable_modules; + +#endif diff --git a/modules_descr.h b/modules_descr.h new file mode 100644 index 0000000..d38f437 --- /dev/null +++ b/modules_descr.h @@ -0,0 +1,66 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2001 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _MODULES_DESCR_H_ +#define _MODULES_DESCR_H_ + +struct module_descr { + const char * module; + char * descr; +}; + +struct module_descr modules_descriptions[] = { +#ifndef DISABLE_NETWORK + /* description of network drivers that have not very explicit names */ + { "ne", "NE1000/NE2000/clones" }, + { "ne2k-pci", "PCI NE2000" }, + { "depca", "DEC DEPCA/DE100/DE101/DE200/DE201/DE202/DE210/DE422" }, + { "dgrs", "Digi RightSwitch SE-X" }, + { "ewrk3", "DEC DE203/DE204/DE205" }, + { "lance", "Allied Telesis AT1500, HP J2405A, NE2100/NE2500" }, + { "sis900", "SiS 900/7016/630E, Am79c901, RTL8201" }, + { "via-rhine", "VIA VT86c100A Rhine-II, 3043 Rhine-I" }, + { "tulip", "DEC 21040-family based cards" }, + { "wd", "WD8003/WD8013" }, + { "bmac", "Macintosh integrated ethernet (G3)" }, + { "gmac", "Macintosh integrated ethernet (G4/iBook)" }, + { "mace", "Macintosh integrated ethernet (PowerMac)" }, +#endif + +#ifndef DISABLE_MEDIAS + /* description of scsi drivers that have not very explicit names */ + { "53c7,8xx", "NCR53c810/700" }, + { "sim710", "NCR53c710" }, + { "aic7xxx", "Adaptec 7xxx family (AIC/AHA/etc)" }, + { "atp870u", "ACARD/ARTOP AEC-6710/6712" }, + { "ncr53c8xx", "Symbios 53c family" }, + { "sym53c8xx", "Symbios 53c family" }, + { "sim710", "NCR53C710 family" }, + { "mesh", "Macintosh integrated SCSI (NewWorld or internal SCSI)" }, + { "mac53c94", "Macintosh integrated SCSI (OldWorld or external SCSI)" }, +#endif + +#ifdef ENABLE_USB + /* description of usb drivers that have not very explicit names */ + { "usbnet", "Netchip or Prolific USB-USB Bridge" }, + { "pegasus", "ADMtek AN986 (USB Ethernet chipset)" }, + { "kaweth", "KL5KUSB101 (USB Ethernet chipset)" }, + { "catc", "CATC EL1210A NetMate USB Ethernet" }, +#endif +}; + +int modules_descriptions_num = sizeof(modules_descriptions) / sizeof(struct module_descr); + + +#endif diff --git a/mount.c b/mount.c new file mode 100644 index 0000000..90b0ada --- /dev/null +++ b/mount.c @@ -0,0 +1,188 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#include +#include +#include +#include +#include +#include +#include "log.h" +#include "modules.h" + +#include "mount.h" + + + +#ifndef DISABLE_MEDIAS +/* WARNING: this won't work if the argument is not /dev/ based */ +int ensure_dev_exists(char *dev) +{ + int major, minor; + int type = S_IFBLK; /* my default type is block. don't forget to change for chars */ + char * name; + struct stat buf; + char * ptr; + + name = &dev[5]; /* we really need that dev be passed as /dev/something.. */ + + if (!stat(dev, &buf)) + return 0; /* if the file already exists, we assume it's correct */ + + if (name[0] == 's' && name[1] == 'd') { + /* SCSI disks */ + major = 8; + minor = (name[2] - 'a') << 4; + if (name[3] && name[4]) + minor += 10 + (name[4] - '0'); + else if (name[3]) + minor += (name[3] - '0'); + } else if (name[0] == 'h' && name[1] == 'd') { + /* IDE disks/cd's */ + if (name[2] == 'a') + major = 3, minor = 0; + else if (name[2] == 'b') + major = 3, minor = 64; + else if (name[2] == 'c') + major = 22, minor = 0; + else if (name[2] == 'd') + major = 22, minor = 64; + else if (name[2] == 'e') + major = 33, minor = 0; + else if (name[2] == 'f') + major = 33, minor = 64; + else if (name[2] == 'g') + major = 34, minor = 0; + else if (name[2] == 'h') + major = 34, minor = 64; + else + return -1; + + if (name[3] && name[4]) + minor += 10 + (name[4] - '0'); + else if (name[3]) + minor += (name[3] - '0'); + } else if (name[0] == 's' && name[1] == 'r') { + /* SCSI cd's */ + major = 11; + minor = name[2] - '0'; + } else if (ptr_begins_static_str(name, "ida/") || + ptr_begins_static_str(name, "cciss/")) { + /* Compaq Smart Array "ida/c0d0{p1}" */ + ptr = strchr(name, '/'); + mkdir("/dev/ida", 0755); + mkdir("/dev/cciss", 0755); + major = ptr_begins_static_str(name, "ida/") ? 72 : 104 + charstar_to_int(ptr+2); + ptr = strchr(ptr, 'd'); + minor = 16 * charstar_to_int(ptr+1); + ptr = strchr(ptr, 'p'); + minor += charstar_to_int(ptr+1); + } else if (ptr_begins_static_str(name, "rd/")) { + /* DAC960 "rd/cXdXXpX" */ + mkdir("/dev/rd", 0755); + major = 48 + charstar_to_int(name+4); + ptr = strchr(name+4, 'd'); + minor = 8 * charstar_to_int(ptr+1); + ptr = strchr(ptr, 'p'); + minor += charstar_to_int(ptr+1); + } else { + log_message("I don't know how to create device %s, please post bugreport to me!", dev); + return -1; + } + + if (mknod(dev, type | 0600, makedev(major, minor))) { + log_perror(dev); + return -1; + } + + return 0; +} +#endif /* DISABLE_MEDIAS */ + + +/* mounts, creating the device if needed+possible */ +int my_mount(char *dev, char *location, char *fs, int force_rw) +{ + unsigned long flags = MS_MGC_VAL | (force_rw ? 0 : MS_RDONLY); + char * opts = NULL; + struct stat buf; + int rc; + +#ifndef DISABLE_MEDIAS + if (strcmp(fs, "nfs")) { + rc = ensure_dev_exists(dev); + if (rc != 0) { + log_message("could not create required device file"); + return -1; + } + } +#endif + + log_message("mounting %s on %s as type %s", dev, location, fs); + + if (stat(location, &buf)) { + if (mkdir(location, 0755)) { + log_perror("could not create location dir"); + return -1; + } + } else if (!S_ISDIR(buf.st_mode)) { + log_message("not a dir %s, will unlink and mkdir", location); + if (unlink(location)) { + log_perror("could not unlink"); + return -1; + } + if (mkdir(location, 0755)) { + log_perror("could not create location dir"); + return -1; + } + } + +#ifndef DISABLE_MEDIAS + if (!strcmp(fs, "vfat")) { + my_insmod("vfat", ANY_DRIVER_TYPE, NULL); + opts = "check=relaxed"; + } + + if (!strcmp(fs, "reiserfs")) + my_insmod("reiserfs", ANY_DRIVER_TYPE, NULL); + + if (!strcmp(fs, "iso9660")) + my_insmod("isofs", ANY_DRIVER_TYPE, NULL); +#endif + +#ifndef DISABLE_NETWORK + if (!strcmp(fs, "nfs")) { + my_insmod("nfs", ANY_DRIVER_TYPE, NULL); + log_message("preparing nfsmount for %s", dev); + rc = nfsmount_prepare(dev, &opts); + if (rc != 0) + return rc; + } +#endif + + rc = mount(dev, location, fs, flags, opts); + if (rc != 0) { + log_perror("mount failed"); + rmdir(location); + } + + return rc; +} diff --git a/mount.h b/mount.h new file mode 100644 index 0000000..8279546 --- /dev/null +++ b/mount.h @@ -0,0 +1,35 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#ifndef _MOUNT_H_ +#define _MOUNT_H_ + +#ifndef DISABLE_NETWORK +#include "nfsmount.h" +#endif + +int my_mount(char *dev, char *location, char *fs, int force_rw); + +#ifndef DISABLE_MEDIAS +int ensure_dev_exists(char *dev); +#endif + +#endif diff --git a/mount_rpcgen.h b/mount_rpcgen.h new file mode 100644 index 0000000..d70ccaf --- /dev/null +++ b/mount_rpcgen.h @@ -0,0 +1,208 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _MOUNT_H_RPCGEN +#define _MOUNT_H_RPCGEN + +#include + +#define MNTPATHLEN 1024 +#define MNTNAMLEN 255 +#define FHSIZE 32 + +typedef char fhandle[FHSIZE]; +#ifdef __cplusplus +extern "C" bool_t xdr_fhandle(XDR *, fhandle); +#elif __STDC__ +extern bool_t xdr_fhandle(XDR *, fhandle); +#else /* Old Style C */ +bool_t xdr_fhandle(); +#endif /* Old Style C */ + + +struct fhstatus { + u_int fhs_status; + union { + fhandle fhs_fhandle; + } fhstatus_u; +}; +typedef struct fhstatus fhstatus; +#ifdef __cplusplus +extern "C" bool_t xdr_fhstatus(XDR *, fhstatus*); +#elif __STDC__ +extern bool_t xdr_fhstatus(XDR *, fhstatus*); +#else /* Old Style C */ +bool_t xdr_fhstatus(); +#endif /* Old Style C */ + + +typedef char *dirpath; +#ifdef __cplusplus +extern "C" bool_t xdr_dirpath(XDR *, dirpath*); +#elif __STDC__ +extern bool_t xdr_dirpath(XDR *, dirpath*); +#else /* Old Style C */ +bool_t xdr_dirpath(); +#endif /* Old Style C */ + + +typedef char *name; +#ifdef __cplusplus +extern "C" bool_t xdr_name(XDR *, name*); +#elif __STDC__ +extern bool_t xdr_name(XDR *, name*); +#else /* Old Style C */ +bool_t xdr_name(); +#endif /* Old Style C */ + + +typedef struct mountbody *mountlist; +#ifdef __cplusplus +extern "C" bool_t xdr_mountlist(XDR *, mountlist*); +#elif __STDC__ +extern bool_t xdr_mountlist(XDR *, mountlist*); +#else /* Old Style C */ +bool_t xdr_mountlist(); +#endif /* Old Style C */ + + +struct mountbody { + name ml_hostname; + dirpath ml_directory; + mountlist ml_next; +}; +typedef struct mountbody mountbody; +#ifdef __cplusplus +extern "C" bool_t xdr_mountbody(XDR *, mountbody*); +#elif __STDC__ +extern bool_t xdr_mountbody(XDR *, mountbody*); +#else /* Old Style C */ +bool_t xdr_mountbody(); +#endif /* Old Style C */ + + +typedef struct groupnode *groups; +#ifdef __cplusplus +extern "C" bool_t xdr_groups(XDR *, groups*); +#elif __STDC__ +extern bool_t xdr_groups(XDR *, groups*); +#else /* Old Style C */ +bool_t xdr_groups(); +#endif /* Old Style C */ + + +struct groupnode { + name gr_name; + groups gr_next; +}; +typedef struct groupnode groupnode; +#ifdef __cplusplus +extern "C" bool_t xdr_groupnode(XDR *, groupnode*); +#elif __STDC__ +extern bool_t xdr_groupnode(XDR *, groupnode*); +#else /* Old Style C */ +bool_t xdr_groupnode(); +#endif /* Old Style C */ + + +typedef struct exportnode *exports; +#ifdef __cplusplus +extern "C" bool_t xdr_exports(XDR *, exports*); +#elif __STDC__ +extern bool_t xdr_exports(XDR *, exports*); +#else /* Old Style C */ +bool_t xdr_exports(); +#endif /* Old Style C */ + + +struct exportnode { + dirpath ex_dir; + groups ex_groups; + exports ex_next; +}; +typedef struct exportnode exportnode; +#ifdef __cplusplus +extern "C" bool_t xdr_exportnode(XDR *, exportnode*); +#elif __STDC__ +extern bool_t xdr_exportnode(XDR *, exportnode*); +#else /* Old Style C */ +bool_t xdr_exportnode(); +#endif /* Old Style C */ + + +#define MOUNTPROG ((u_long)100005) +#define MOUNTVERS ((u_long)1) + +#ifdef __cplusplus +#define MOUNTPROC_NULL ((u_long)0) +extern "C" void * mountproc_null_1(void *, CLIENT *); +extern "C" void * mountproc_null_1_svc(void *, struct svc_req *); +#define MOUNTPROC_MNT ((u_long)1) +extern "C" fhstatus * mountproc_mnt_1(dirpath *, CLIENT *); +extern "C" fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *); +#define MOUNTPROC_DUMP ((u_long)2) +extern "C" mountlist * mountproc_dump_1(void *, CLIENT *); +extern "C" mountlist * mountproc_dump_1_svc(void *, struct svc_req *); +#define MOUNTPROC_UMNT ((u_long)3) +extern "C" void * mountproc_umnt_1(dirpath *, CLIENT *); +extern "C" void * mountproc_umnt_1_svc(dirpath *, struct svc_req *); +#define MOUNTPROC_UMNTALL ((u_long)4) +extern "C" void * mountproc_umntall_1(void *, CLIENT *); +extern "C" void * mountproc_umntall_1_svc(void *, struct svc_req *); +#define MOUNTPROC_EXPORT ((u_long)5) +extern "C" exports * mountproc_export_1(void *, CLIENT *); +extern "C" exports * mountproc_export_1_svc(void *, struct svc_req *); +#define MOUNTPROC_EXPORTALL ((u_long)6) +extern "C" exports * mountproc_exportall_1(void *, CLIENT *); +extern "C" exports * mountproc_exportall_1_svc(void *, struct svc_req *); + +#elif __STDC__ +#define MOUNTPROC_NULL ((u_long)0) +extern void * mountproc_null_1(void *, CLIENT *); +extern void * mountproc_null_1_svc(void *, struct svc_req *); +#define MOUNTPROC_MNT ((u_long)1) +extern fhstatus * mountproc_mnt_1(dirpath *, CLIENT *); +extern fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *); +#define MOUNTPROC_DUMP ((u_long)2) +extern mountlist * mountproc_dump_1(void *, CLIENT *); +extern mountlist * mountproc_dump_1_svc(void *, struct svc_req *); +#define MOUNTPROC_UMNT ((u_long)3) +extern void * mountproc_umnt_1(dirpath *, CLIENT *); +extern void * mountproc_umnt_1_svc(dirpath *, struct svc_req *); +#define MOUNTPROC_UMNTALL ((u_long)4) +extern void * mountproc_umntall_1(void *, CLIENT *); +extern void * mountproc_umntall_1_svc(void *, struct svc_req *); +#define MOUNTPROC_EXPORT ((u_long)5) +extern exports * mountproc_export_1(void *, CLIENT *); +extern exports * mountproc_export_1_svc(void *, struct svc_req *); +#define MOUNTPROC_EXPORTALL ((u_long)6) +extern exports * mountproc_exportall_1(void *, CLIENT *); +extern exports * mountproc_exportall_1_svc(void *, struct svc_req *); + +#else /* Old Style C */ +#define MOUNTPROC_NULL ((u_long)0) +extern void * mountproc_null_1(); +extern void * mountproc_null_1_svc(); +#define MOUNTPROC_MNT ((u_long)1) +extern fhstatus * mountproc_mnt_1(); +extern fhstatus * mountproc_mnt_1_svc(); +#define MOUNTPROC_DUMP ((u_long)2) +extern mountlist * mountproc_dump_1(); +extern mountlist * mountproc_dump_1_svc(); +#define MOUNTPROC_UMNT ((u_long)3) +extern void * mountproc_umnt_1(); +extern void * mountproc_umnt_1_svc(); +#define MOUNTPROC_UMNTALL ((u_long)4) +extern void * mountproc_umntall_1(); +extern void * mountproc_umntall_1_svc(); +#define MOUNTPROC_EXPORT ((u_long)5) +extern exports * mountproc_export_1(); +extern exports * mountproc_export_1_svc(); +#define MOUNTPROC_EXPORTALL ((u_long)6) +extern exports * mountproc_exportall_1(); +extern exports * mountproc_exportall_1_svc(); +#endif /* Old Style C */ + +#endif /* !_MOUNT_H_RPCGEN */ diff --git a/network.c b/network.c new file mode 100644 index 0000000..e3313b3 --- /dev/null +++ b/network.c @@ -0,0 +1,830 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#include +#include +#include +// #include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stage1.h" +#include "frontend.h" +#include "modules.h" +#include "probing.h" +#include "log.h" +#include "mount.h" +#include "automatic.h" +#include "dhcp.h" +#include "adsl.h" +#include "url.h" +#include "dns.h" + +#include "network.h" + + +static void error_message_net(void) /* reduce code size */ +{ + stg1_error_message("Could not configure network."); +} + + +int configure_net_device(struct interface_info * intf) +{ + struct ifreq req; + struct rtentry route; + int s; + struct sockaddr_in addr; + struct in_addr ia; + char ip[20], nm[20], nw[20], bc[20]; + + addr.sin_family = AF_INET; + addr.sin_port = 0; + + memcpy(&ia, &intf->ip, sizeof(intf->ip)); + strcpy(ip, inet_ntoa(ia)); + + memcpy(&ia, &intf->netmask, sizeof(intf->netmask)); + strcpy(nm, inet_ntoa(ia)); + + memcpy(&ia, &intf->broadcast, sizeof(intf->broadcast)); + strcpy(bc, inet_ntoa(ia)); + + memcpy(&ia, &intf->network, sizeof(intf->network)); + strcpy(nw, inet_ntoa(ia)); + + log_message("configuring device %s ip: %s nm: %s nw: %s bc: %s", intf->device, ip, nm, nw, bc); + + if (IS_TESTING) + return 0; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + log_perror("socket"); + error_message_net(); + return 1; + } + + strcpy(req.ifr_name, intf->device); + + if (intf->is_up == 1) { + log_message("interface already up, downing before reconfigure"); + + req.ifr_flags = 0; + if (ioctl(s, SIOCSIFFLAGS, &req)) { + close(s); + log_perror("SIOCSIFFLAGS (downing)"); + error_message_net(); + return 1; + } + } + + /* sets IP address */ + addr.sin_port = 0; + memcpy(&addr.sin_addr, &intf->ip, sizeof(intf->ip)); + memcpy(&req.ifr_addr, &addr, sizeof(addr)); + if (ioctl(s, SIOCSIFADDR, &req)) { + close(s); + log_perror("SIOCSIFADDR"); + error_message_net(); + return 1; + } + + /* sets broadcast */ + memcpy(&addr.sin_addr, &intf->broadcast, sizeof(intf->broadcast)); + memcpy(&req.ifr_broadaddr, &addr, sizeof(addr)); + if (ioctl(s, SIOCSIFBRDADDR, &req)) { + close(s); + log_perror("SIOCSIFBRDADDR"); + error_message_net(); + return 1; + } + + /* sets netmask */ + memcpy(&addr.sin_addr, &intf->netmask, sizeof(intf->netmask)); + memcpy(&req.ifr_netmask, &addr, sizeof(addr)); + if (ioctl(s, SIOCSIFNETMASK, &req)) { + close(s); + log_perror("SIOCSIFNETMASK"); + error_message_net(); + return 1; + } + + if (intf->is_ptp) + req.ifr_flags = IFF_UP | IFF_RUNNING | IFF_POINTOPOINT | IFF_NOARP; + else + req.ifr_flags = IFF_UP | IFF_RUNNING | IFF_BROADCAST; + + /* brings up networking! */ + if (ioctl(s, SIOCSIFFLAGS, &req)) { + close(s); + log_perror("SIOCSIFFLAGS (upping)"); + error_message_net(); + return 1; + } + + memset(&route, 0, sizeof(route)); + route.rt_dev = intf->device; + route.rt_flags = RTF_UP; + + memcpy(&addr.sin_addr, &intf->network, sizeof(intf->network)); + memcpy(&route.rt_dst, &addr, sizeof(addr)); + + memcpy(&addr.sin_addr, &intf->netmask, sizeof(intf->netmask)); + memcpy(&route.rt_genmask, &addr, sizeof(addr)); + + /* adds route */ + if (ioctl(s, SIOCADDRT, &route)) { + close(s); + log_perror("SIOCADDRT"); + error_message_net(); + return 1; + } + + close(s); + + intf->is_up = 1; + + if (intf->boot_proto != BOOTPROTO_DHCP && !streq(intf->device, "lo")) { + /* I need to sleep a bit in order for kernel to finish + init of the network device; if not, first sendto() for + gethostbyaddr will get an EINVAL. */ + wait_message("Bringing up networking..."); + sleep(2); + remove_wait_message(); + } + + return 0; +} + +/* host network informations */ +char * hostname = NULL; +char * domain = NULL; +struct in_addr gateway = { 0 }; +struct in_addr dns_server = { 0 }; +struct in_addr dns_server2 = { 0 }; + +static int add_default_route(void) +{ + int s; + struct rtentry route; + struct sockaddr_in addr; + + if (IS_TESTING) + return 0; + + if (gateway.s_addr == 0) { + log_message("no gateway provided, can't add default route"); + return 0; + } + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + close(s); + log_perror("socket"); + error_message_net(); + return 1; + } + + memset(&route, 0, sizeof(route)); + + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr = gateway; + memcpy(&route.rt_gateway, &addr, sizeof(addr)); + + addr.sin_addr.s_addr = INADDR_ANY; + memcpy(&route.rt_dst, &addr, sizeof(addr)); + memcpy(&route.rt_genmask, &addr, sizeof(addr)); + + route.rt_flags = RTF_UP | RTF_GATEWAY; + route.rt_metric = 0; + + if (ioctl(s, SIOCADDRT, &route)) { + close(s); + log_perror("SIOCADDRT"); + error_message_net(); + return 1; + } + + close(s); + + return 0; +} + + +static int write_resolvconf(void) { + char * filename = "/etc/resolv.conf"; + FILE * f; + + if (dns_server.s_addr == 0) { + log_message("resolvconf needs a dns server"); + return -1; + } + + f = fopen(filename, "w"); + if (!f) { + log_perror(filename); + return -1; + } + + if (domain) + fprintf(f, "search %s\n", domain); /* we can live without the domain search (user will have to enter fully-qualified names) */ + fprintf(f, "nameserver %s\n", inet_ntoa(dns_server)); + if (dns_server2.s_addr != 0) + fprintf(f, "nameserver %s\n", inet_ntoa(dns_server2)); + + fclose(f); + res_init(); /* reinit the resolver so DNS changes take affect */ + + return 0; +} + + +static int save_netinfo(struct interface_info * intf) { + char * file_network = "/tmp/network"; + char file_intf[500]; + FILE * f; + + f = fopen(file_network, "w"); + if (!f) { + log_perror(file_network); + return -1; + } + + fprintf(f, "NETWORKING=yes\n"); + fprintf(f, "FORWARD_IPV4=false\n"); + + if (hostname) + fprintf(f, "HOSTNAME=%s\n", hostname); + if (domain) + fprintf(f, "DOMAINNAME=%s\n", domain); + + if (gateway.s_addr != 0) + fprintf(f, "GATEWAY=%s\n", inet_ntoa(gateway)); + + fclose(f); + + + strcpy(file_intf, "/tmp/ifcfg-"); + strcat(file_intf, intf->device); + + f = fopen(file_intf, "w"); + if (!f) { + log_perror(file_intf); + return -1; + } + + fprintf(f, "DEVICE=%s\n", intf->device); + + if (intf->boot_proto == BOOTPROTO_DHCP) + fprintf(f, "BOOTPROTO=dhcp\n"); + else if (intf->boot_proto == BOOTPROTO_STATIC) { + fprintf(f, "BOOTPROTO=static\n"); + fprintf(f, "IPADDR=%s\n", inet_ntoa(intf->ip)); + fprintf(f, "NETMASK=%s\n", inet_ntoa(intf->netmask)); + fprintf(f, "NETWORK=%s\n", inet_ntoa(intf->network)); + fprintf(f, "BROADCAST=%s\n", inet_ntoa(intf->broadcast)); + } else if (intf->boot_proto == BOOTPROTO_ADSL_PPPOE) { + fprintf(f, "BOOTPROTO=adsl_pppoe\n"); + fprintf(f, "USER=%s\n", intf->user); + fprintf(f, "PASS=%s\n", intf->pass); + } + + fclose(f); + + return 0; +} + + +char * guess_netmask(char * ip_addr) +{ + struct in_addr addr; + unsigned long int tmp; + + if (streq(ip_addr, "") || !inet_aton(ip_addr, &addr)) + return ""; + + log_message("guessing netmask"); + + tmp = ntohl(addr.s_addr); + + if (((tmp & 0xFF000000) >> 24) <= 127) + return "255.0.0.0"; + else if (((tmp & 0xFF000000) >> 24) <= 191) + return "255.255.0.0"; + else + return "255.255.255.0"; +} + + +static void static_ip_callback(char ** strings) +{ + struct in_addr addr; + + if (!inet_aton(strings[0], &addr)) + return; + + if (!strcmp(strings[1], "")) { + char * ptr; + strings[1] = strdup(strings[0]); + ptr = strrchr(strings[1], '.'); + if (ptr) + *(ptr+1) = '\0'; + } + + if (!strcmp(strings[2], "")) + strings[2] = strdup(strings[1]); + + if (!strcmp(strings[3], "")) + strings[3] = strdup(guess_netmask(strings[0])); +} + + +static enum return_type setup_network_interface(struct interface_info * intf) +{ + enum return_type results; + char * bootprotos[] = { "Static", "DHCP", "ADSL", NULL }; + char * bootprotos_auto[] = { "static", "dhcp", "adsl" }; + char * choice; + + results = ask_from_list_auto("Please choose the desired IP attribution.", bootprotos, &choice, "network", bootprotos_auto); + if (results != RETURN_OK) + return results; + + if (!strcmp(choice, "Static")) { + char * questions[] = { "IP of this machine", "IP of DNS", "IP of default gateway", "Netmask", NULL }; + char * questions_auto[] = { "ip", "dns", "gateway", "netmask" }; + static char ** answers = NULL; + struct in_addr addr; + + results = ask_from_entries_auto("Please enter the network information. (leave netmask void for Internet standard)", + questions, &answers, 16, questions_auto, static_ip_callback); + if (results != RETURN_OK) + return setup_network_interface(intf); + + if (streq(answers[0], "") || !inet_aton(answers[0], &addr)) { + stg1_error_message("Invalid IP address."); + return setup_network_interface(intf); + } + memcpy(&intf->ip, &addr, sizeof(addr)); + + if (!inet_aton(answers[1], &dns_server)) { + log_message("invalid DNS"); + dns_server.s_addr = 0; /* keep an understandable state */ + } + + if (!inet_aton(answers[2], &gateway)) { + log_message("invalid gateway"); + gateway.s_addr = 0; /* keep an understandable state */ + } + + if ((streq(answers[3], "") && inet_aton(guess_netmask(answers[0]), &addr)) + || inet_aton(answers[3], &addr)) + memcpy(&intf->netmask, &addr, sizeof(addr)); + else { + stg1_error_message("Invalid netmask."); + return setup_network_interface(intf); + } + + *((uint32_t *) &intf->broadcast) = (*((uint32_t *) &intf->ip) & + *((uint32_t *) &intf->netmask)) | ~(*((uint32_t *) &intf->netmask)); + + inet_aton("255.255.255.255", &addr); + if (!memcmp(&addr, &intf->netmask, sizeof(addr))) { + log_message("netmask is 255.255.255.255 -> point to point device"); + intf->network = gateway; + intf->is_ptp = 1; + } else { + *((uint32_t *) &intf->network) = *((uint32_t *) &intf->ip) & *((uint32_t *) &intf->netmask); + intf->is_ptp = 0; + } + intf->boot_proto = BOOTPROTO_STATIC; + + if (configure_net_device(intf)) + return RETURN_ERROR; + + } else if (streq(choice, "DHCP")) { + results = perform_dhcp(intf); + + if (results == RETURN_BACK) + return setup_network_interface(intf); + if (results == RETURN_ERROR) + return results; + intf->boot_proto = BOOTPROTO_DHCP; + + if (configure_net_device(intf)) + return RETURN_ERROR; + + } else if (streq(choice, "ADSL")) { + results = perform_adsl(intf); + + if (results == RETURN_BACK) + return setup_network_interface(intf); + if (results == RETURN_ERROR) + return results; + } else + return RETURN_ERROR; + + return add_default_route(); +} + + +static enum return_type configure_network(struct interface_info * intf) +{ + char * dnshostname; + + if (hostname && domain) + return RETURN_OK; + + dnshostname = mygethostbyaddr(inet_ntoa(intf->ip)); + + if (dnshostname) { + hostname = strdup(dnshostname); + domain = strchr(strdup(hostname), '.') + 1; + log_message("got hostname and domain from dns entry, %s and %s", hostname, domain); + return RETURN_OK; + } + + log_message("reverse name lookup on self failed"); + + if (domain) + return RETURN_OK; + + if (dns_server.s_addr != 0) { + wait_message("Trying to resolve dns..."); + dnshostname = mygethostbyaddr(inet_ntoa(dns_server)); + remove_wait_message(); + } + + if (dnshostname) { + domain = strchr(strdup(dnshostname), '.') + 1; + log_message("got domain from DNS fullname, %s", domain); + } else { + enum return_type results; + char * questions[] = { "Host name", "Domain name", NULL }; + char * questions_auto[] = { "hostname", "domain" }; + static char ** answers = NULL; + char * boulet; + + log_message("reverse name lookup on DNS failed"); + + results = ask_from_entries_auto("I could not guess hostname and domain name; please fill in this information. " + "Valid answers are for example: `mybox' for hostname and `mynetwork.com' for " + "domain name, for a machine called `mybox.mynetwork.com' on the Internet.", + questions, &answers, 32, questions_auto, NULL); + if (results != RETURN_OK) + return results; + + hostname = answers[0]; + if ((boulet = strchr(hostname, '.')) != NULL) + boulet[0] = '\0'; + domain = answers[1]; + } + + return RETURN_OK; +} + + +static enum return_type bringup_networking(struct interface_info * intf) +{ + static struct interface_info loopback; + enum return_type results = RETURN_ERROR; + + my_insmod("af_packet", ANY_DRIVER_TYPE, NULL); + + while (results != RETURN_OK) { + results = setup_network_interface(intf); + if (results != RETURN_OK) + return results; + write_resolvconf(); + results = configure_network(intf); + } + + write_resolvconf(); /* maybe we have now domain to write also */ + + if (loopback.is_up == 0) { + int rc; + strcpy(loopback.device, "lo"); + loopback.is_ptp = 0; + loopback.is_up = 0; + loopback.ip.s_addr = htonl(0x7f000001); + loopback.netmask.s_addr = htonl(0xff000000); + loopback.broadcast.s_addr = htonl(0x7fffffff); + loopback.network.s_addr = htonl(0x7f000000); + rc = configure_net_device(&loopback); + if (rc) + return RETURN_ERROR; + } + + return RETURN_OK; +} + + +static char * interface_select(void) +{ + char ** interfaces, ** ptr; + char * descriptions[50]; + char * choice; + int i, count = 0; + enum return_type results; + + interfaces = get_net_devices(); + + ptr = interfaces; + while (ptr && *ptr) { + count++; + ptr++; + } + + if (count == 0) { + stg1_error_message("No NET device found."); + i = ask_insmod(NETWORK_DEVICES); + if (i == RETURN_BACK) + return NULL; + return interface_select(); + } + + if (count == 1) + return *interfaces; + + i = 0; + while (interfaces[i]) { + descriptions[i] = get_net_intf_description(interfaces[i]); + i++; + } + + results = ask_from_list_comments_auto("Please choose the NET device to use for the installation.", + interfaces, descriptions, &choice, "interface", interfaces); + + if (results != RETURN_OK) + return NULL; + + return choice; +} + + + +/* -=-=-- */ + + +static enum return_type intf_select_and_up(void) +{ + static struct interface_info intf[20]; + static int num_interfaces = 0; + struct interface_info * sel_intf = NULL; + int i; + enum return_type results; + char * iface = interface_select(); + + if (iface == NULL) + return RETURN_BACK; + + for (i = 0; i < num_interfaces ; i++) + if (!strcmp(intf[i].device, iface)) + sel_intf = &(intf[i]); + + if (sel_intf == NULL) { + sel_intf = &(intf[num_interfaces]); + strcpy(sel_intf->device, iface); + sel_intf->is_up = 0; + num_interfaces++; + } + + results = bringup_networking(sel_intf); + + if (results == RETURN_OK) + save_netinfo(sel_intf); + + return results; +} + + + +enum return_type nfs_prepare(void) +{ + char * questions[] = { "NFS server name", DISTRIB_NAME " directory", NULL }; + char * questions_auto[] = { "server", "directory", NULL }; + static char ** answers = NULL; + char * nfsmount_location; + enum return_type results = intf_select_and_up(); + + if (results != RETURN_OK) + return results; + + do { + results = ask_from_entries_auto("Please enter the name or IP address of your NFS server, " + "and the directory containing the " DISTRIB_NAME " Distribution.", + questions, &answers, 40, questions_auto, NULL); + if (results != RETURN_OK || streq(answers[0], "")) { + unset_param(MODE_AUTOMATIC); /* we are in a fallback mode */ + return nfs_prepare(); + } + + nfsmount_location = malloc(strlen(answers[0]) + strlen(answers[1]) + 2); + strcpy(nfsmount_location, answers[0]); + strcat(nfsmount_location, ":"); + strcat(nfsmount_location, answers[1]); + + if (my_mount(nfsmount_location, IMAGE_LOCATION, "nfs", 0) == -1) { + stg1_error_message("I can't mount the directory from the NFS server."); + results = RETURN_BACK; + continue; + } + + if (access(IMAGE_LOCATION LIVE_LOCATION, R_OK)) { + stg1_error_message("That NFS volume does not seem to contain the " DISTRIB_NAME " Distribution."); + umount(IMAGE_LOCATION); + results = RETURN_BACK; + } + } + while (results == RETURN_BACK); + + log_message("found the " DISTRIB_NAME " Installation, good news!"); + + if (IS_SPECIAL_STAGE2) { + if (load_ramdisk() != RETURN_OK) { + stg1_error_message("Could not load program into memory."); + return nfs_prepare(); + } + } + + if (IS_RESCUE) + umount(IMAGE_LOCATION); + + method_name = strdup("nfs"); + return RETURN_OK; +} + + +enum return_type ftp_prepare(void) +{ + char * questions[] = { "FTP server", DISTRIB_NAME " directory", "Login", "Password", NULL }; + char * questions_auto[] = { "server", "directory", "user", "pass", NULL }; + static char ** answers = NULL; + enum return_type results; + + if (!ramdisk_possible()) { + stg1_error_message("FTP install needs more than %d Mbytes of memory (detected %d Mbytes).", + MEM_LIMIT_RAMDISK, total_memory()); + return RETURN_ERROR; + } + + results = intf_select_and_up(); + + if (results != RETURN_OK) + return results; + + do { + char location_full[500]; + int ftp_serv_response; + int fd, size; + + results = ask_from_entries_auto("Please enter the name or IP address of the FTP server, " + "the directory containing the " DISTRIB_NAME " Distribution, " + "and the login/pass if necessary (leave login blank for anonymous).", + questions, &answers, 40, questions_auto, NULL); + if (results != RETURN_OK || streq(answers[0], "")) { + unset_param(MODE_AUTOMATIC); /* we are in a fallback mode */ + return ftp_prepare(); + } + + log_message("FTP: trying to connect to %s", answers[0]); + + ftp_serv_response = ftp_open_connection(answers[0], answers[2], answers[3], ""); + if (ftp_serv_response < 0) { + log_message("FTP: error connect %d", ftp_serv_response); + if (ftp_serv_response == FTPERR_BAD_HOSTNAME) + stg1_error_message("Error: bad hostname."); + else if (ftp_serv_response == FTPERR_FAILED_CONNECT) + stg1_error_message("Error: failed to connect to remote host."); + else + stg1_error_message("Error: couldn't connect."); + results = RETURN_BACK; + continue; + } + strcpy(location_full, answers[1]); + strcat(location_full, get_ramdisk_realname()); + + log_message("FTP: trying to retrieve %s", location_full); + + fd = ftp_start_download(ftp_serv_response, location_full, &size); + if (fd < 0) { + log_message("FTP: error get %d", fd); + if (fd == FTPERR_PASSIVE_ERROR) + stg1_error_message("Error: error with passive connection."); + else if (fd == FTPERR_FILE_NOT_FOUND) + stg1_error_message("Error: file not found (%s).", location_full); + else if (fd == FTPERR_BAD_SERVER_RESPONSE) + stg1_error_message("Error: bad server response (server too busy?)."); + else + stg1_error_message("Error: couldn't retrieve Installation program."); + results = RETURN_BACK; + continue; + } + + log_message("FTP: size of download %d bytes", size); + + results = load_ramdisk_fd(fd, size); + if (results == RETURN_OK) + ftp_end_data_command(ftp_serv_response); + else + return results; + + method_name = strdup("ftp"); + add_to_env("HOST", answers[0]); + add_to_env("PREFIX", answers[1]); + if (strcmp(answers[2], "")) { + add_to_env("LOGIN", answers[2]); + add_to_env("PASSWORD", answers[3]); + } + } + while (results == RETURN_BACK); + + return RETURN_OK; +} + +enum return_type http_prepare(void) +{ + char * questions[] = { "HTTP server", DISTRIB_NAME " directory", NULL }; + char * questions_auto[] = { "server", "directory", NULL }; + static char ** answers = NULL; + enum return_type results; + + if (!ramdisk_possible()) { + stg1_error_message("HTTP install needs more than %d Mbytes of memory (detected %d Mbytes).", + MEM_LIMIT_RAMDISK, total_memory()); + return RETURN_ERROR; + } + + results = intf_select_and_up(); + + if (results != RETURN_OK) + return results; + + do { + char location_full[500]; + int fd, size; + + results = ask_from_entries_auto("Please enter the name or IP address of the HTTP server, " + "and the directory containing the " DISTRIB_NAME " Distribution.", + questions, &answers, 40, questions_auto, NULL); + if (results != RETURN_OK || streq(answers[0], "")) { + unset_param(MODE_AUTOMATIC); /* we are in a fallback mode */ + return http_prepare(); + } + + strcpy(location_full, answers[1]); + strcat(location_full, get_ramdisk_realname()); + + log_message("HTTP: trying to retrieve %s", location_full); + + fd = http_download_file(answers[0], location_full, &size); + if (fd < 0) { + log_message("HTTP: error %d", fd); + if (fd == FTPERR_FAILED_CONNECT) + stg1_error_message("Error: couldn't connect to server."); + else + stg1_error_message("Error: couldn't get file (%s).", location_full); + results = RETURN_BACK; + continue; + } + + log_message("HTTP: size of download %d bytes", size); + + if (load_ramdisk_fd(fd, size) != RETURN_OK) + return RETURN_ERROR; + + method_name = strdup("http"); + sprintf(location_full, "http://%s/%s", answers[0], answers[1]); + add_to_env("URLPREFIX", location_full); + } + while (results == RETURN_BACK); + + return RETURN_OK; + +} diff --git a/network.h b/network.h new file mode 100644 index 0000000..02eea45 --- /dev/null +++ b/network.h @@ -0,0 +1,61 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#ifndef _NETWORK_H_ +#define _NETWORK_H_ + +#include +#include +#include + + +enum return_type nfs_prepare(void); +enum return_type ftp_prepare(void); +enum return_type http_prepare(void); + + +enum boot_proto_type { BOOTPROTO_STATIC, BOOTPROTO_DHCP, BOOTPROTO_ADSL_PPPOE }; + +/* all of these in_addr things are in network byte order! */ +struct interface_info { + char device[10]; + int is_ptp, is_up; + struct in_addr ip, netmask, broadcast, network; + enum boot_proto_type boot_proto; + char *user, *pass; /* for ADSL connection */ +}; + + +/* these are to be used only by dhcp.c */ + +char * guess_netmask(char * ip_addr); + +int configure_net_device(struct interface_info * intf); + +extern char * hostname; +extern char * domain; +extern struct in_addr gateway; +extern struct in_addr dns_server; +extern struct in_addr dns_server2; + + + +#endif diff --git a/newt-frontend.c b/newt-frontend.c new file mode 100644 index 0000000..e0bc7c5 --- /dev/null +++ b/newt-frontend.c @@ -0,0 +1,392 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + + +/* + * Each different frontend must implement all functions defined in frontend.h + */ + + +#include +#include +#include +#include +#include +#include +#include "newt/newt.h" + +#include "frontend.h" + +void init_frontend(char * welcome_msg) +{ + int i; + for (i=0; i<38; i++) printf("\n"); + newtInit(); + newtCls(); + + newtDrawRootText(0, 0, welcome_msg); + + newtPushHelpLine(" for here, to see the logs, for kernel msg"); + newtRefresh(); +} + + +void finish_frontend(void) +{ + newtFinished(); +} + + +void verror_message(char *msg, va_list ap) +{ + newtWinMessagev("Error", "Ok", msg, ap); +} + +void vinfo_message(char *msg, va_list ap) +{ + newtWinMessagev("Notice", "Ok", msg, ap); +} + + +void vwait_message(char *msg, va_list ap) +{ + int width, height; + char * title = "Please wait..."; + newtComponent c, f; + newtGrid grid; + char * buf = NULL; + char * flowed; + int size = 0; + int i = 0; + + do { + size += 1000; + if (buf) free(buf); + buf = malloc(size); + i = vsnprintf(buf, size, msg, ap); + } while (i >= size || i == -1); + + flowed = newtReflowText(buf, 60, 5, 5, &width, &height); + + c = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP); + newtTextboxSetText(c, flowed); + + grid = newtCreateGrid(1, 1); + newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, c, 0, 0, 0, 0, 0, 0); + newtGridWrappedWindow(grid, title); + + free(flowed); + free(buf); + + f = newtForm(NULL, NULL, 0); + newtFormAddComponent(f, c); + + newtDrawForm(f); + newtRefresh(); + newtFormDestroy(f); +} + +void remove_wait_message(void) +{ + newtPopWindow(); +} + + +static newtComponent form = NULL, scale = NULL; +static int size_progress; +static int actually_drawn; +static char * msg_progress; + +void init_progression(char *msg, int size) +{ + size_progress = size; + if (size) { + actually_drawn = 0; + newtCenteredWindow(70, 5, "Please wait..."); + form = newtForm(NULL, NULL, 0); + newtFormAddComponent(form, newtLabel(1, 1, msg)); + scale = newtScale(1, 3, 68, size); + newtFormAddComponent(form, scale); + newtDrawForm(form); + newtRefresh(); + } + else { + wait_message(msg); + msg_progress = msg; + } +} + +void update_progression(int current_size) +{ + if (size_progress) { + if (current_size <= size_progress) + newtScaleSet(scale, current_size); + newtRefresh(); + } + else { + struct timeval t; + int time; + static int last_time = -1; + gettimeofday(&t, NULL); + time = t.tv_sec*3 + t.tv_usec/300000; + if (time != last_time) { + char msg_prog_final[500]; + sprintf(msg_prog_final, "%s (%d bytes read) ", msg_progress, current_size); + remove_wait_message(); + wait_message(msg_prog_final); + } + last_time = time; + } +} + +void end_progression(void) +{ + if (size_progress) { + newtPopWindow(); + newtFormDestroy(form); + } + else + remove_wait_message(); +} + + +enum return_type ask_from_list_comments(char *msg, char ** elems, char ** elems_comments, char ** choice) +{ + char * items[500]; + int answer = 0, rc; + char ** sav_elems = elems; + int i; + + i = 0; + while (elems && *elems) { + int j = (*elems_comments) ? strlen(*elems_comments) : 0; + items[i] = malloc(sizeof(char) * (strlen(*elems) + j + 4)); + strcpy(items[i], *elems); + if (*elems_comments) { + strcat(items[i], " ("); + strcat(items[i], *elems_comments); + strcat(items[i], ")"); + } + elems_comments++; + i++; + elems++; + } + items[i] = NULL; + + rc = newtWinMenu("Please choose...", msg, 52, 5, 5, 7, items, &answer, "Ok", "Cancel", NULL); + + if (rc == 2) + return RETURN_BACK; + + *choice = strdup(sav_elems[answer]); + + return RETURN_OK; +} + + +enum return_type ask_from_list(char *msg, char ** elems, char ** choice) +{ + int answer = 0, rc; + + rc = newtWinMenu("Please choose...", msg, 52, 5, 5, 7, elems, &answer, "Ok", "Cancel", NULL); + + if (rc == 2) + return RETURN_BACK; + + *choice = strdup(elems[answer]); + + return RETURN_OK; +} + + +enum return_type ask_yes_no(char *msg) +{ + int rc; + + rc = newtWinTernary("Please answer...", "Yes", "No", "Back", msg); + + if (rc == 1) + return RETURN_OK; + else if (rc == 3) + return RETURN_BACK; + else return RETURN_ERROR; +} + + +static void (*callback_real_function)(char ** strings) = NULL; + +static void default_callback(newtComponent co, void * data) +{ + newtComponent * entries = data; + char * strings[50], ** ptr; + + if (!callback_real_function) + return; + + ptr = strings; + while (entries && *entries) { + *ptr = newtEntryGetValue(*entries); + entries++; + ptr++; + } + + callback_real_function(strings); + + ptr = strings; + entries = data; + while (entries && *entries) { + newtEntrySet(*entries, strdup(*ptr), 1); + entries++; + ptr++; + } +} + +/* only supports up to 50 buttons and entries -- shucks! */ +static int mynewtWinEntries(char * title, char * text, int suggestedWidth, int flexDown, + int flexUp, int dataWidth, void (*callback_func)(char ** strings), + struct newtWinEntry * items, char * button1, ...) { + newtComponent buttons[50], result, form, textw; + newtGrid grid, buttonBar, subgrid; + int numItems; + int rc, i; + int numButtons; + char * buttonName; + newtComponent entries[50]; + + va_list args; + + textw = newtTextboxReflowed(-1, -1, text, suggestedWidth, flexDown, + flexUp, 0); + + for (numItems = 0; items[numItems].text; numItems++); + + buttonName = button1, numButtons = 0; + va_start(args, button1); + while (buttonName) { + buttons[numButtons] = newtButton(-1, -1, buttonName); + numButtons++; + buttonName = va_arg(args, char *); + } + + va_end(args); + + buttonBar = newtCreateGrid(numButtons, 1); + for (i = 0; i < numButtons; i++) { + newtGridSetField(buttonBar, i, 0, NEWT_GRID_COMPONENT, + buttons[i], + i ? 1 : 0, 0, 0, 0, 0, 0); + } + + if (callback_func) { + callback_real_function = callback_func; + entries[numItems] = NULL; + } + else + callback_real_function = NULL; + + subgrid = newtCreateGrid(2, numItems); + for (i = 0; i < numItems; i++) { + newtComponent entr = newtEntry(-1, -1, items[i].value ? + *items[i].value : NULL, dataWidth, + items[i].value, items[i].flags); + + newtGridSetField(subgrid, 0, i, NEWT_GRID_COMPONENT, + newtLabel(-1, -1, items[i].text), + 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); + newtGridSetField(subgrid, 1, i, NEWT_GRID_COMPONENT, + entr, + 1, 0, 0, 0, 0, 0); + if (callback_func) { + entries[i] = entr; + newtComponentAddCallback(entr, default_callback, entries); + } + } + + + grid = newtCreateGrid(1, 3); + form = newtForm(NULL, 0, 0); + newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, textw, + 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); + newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, subgrid, + 0, 1, 0, 0, 0, 0); + newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttonBar, + 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX); + newtGridAddComponentsToForm(grid, form, 1); + newtGridWrappedWindow(grid, title); + newtGridFree(grid, 1); + + result = newtRunForm(form); + + for (rc = 0; rc < numItems; rc++) + *items[rc].value = strdup(*items[rc].value); + + for (rc = 0; result != buttons[rc] && rc < numButtons; rc++); + if (rc == numButtons) + rc = 0; /* F12 */ + else + rc++; + + newtFormDestroy(form); + newtPopWindow(); + + return rc; +} + + +enum return_type ask_from_entries(char *msg, char ** questions, char *** answers, int entry_size, void (*callback_func)(char ** strings)) +{ + struct newtWinEntry entries[50]; + int j, i = 0; + int rc; + char ** already_answers = NULL; + + while (questions && *questions) { + entries[i].text = *questions; + entries[i].flags = NEWT_FLAG_SCROLL | (!strcmp(*questions, "Password") ? NEWT_FLAG_PASSWORD : 0); + i++; + questions++; + } + entries[i].text = NULL; + entries[i].value = NULL; + + if (*answers == NULL) + *answers = (char **) malloc(sizeof(char *) * i); + else + already_answers = *answers; + + for (j = 0 ; j < i ; j++) { + entries[j].value = &((*answers)[j]); + if (already_answers && *already_answers) { + *(entries[j].value) = *already_answers; + already_answers++; + } else + *(entries[j].value) = NULL; + } + + rc = mynewtWinEntries("Please fill entries...", msg, 52, 5, 5, entry_size, callback_func, entries, "Ok", "Cancel", NULL); + + if (rc == 3) + return RETURN_BACK; + if (rc != 1) + return RETURN_ERROR; + + return RETURN_OK; +} diff --git a/nfs_mount4.h b/nfs_mount4.h new file mode 100644 index 0000000..8565077 --- /dev/null +++ b/nfs_mount4.h @@ -0,0 +1,54 @@ +/* + * We want to be able to compile mount on old kernels in such a way + * that the binary will work well on more recent kernels. + * Thus, if necessary we teach nfsmount.c the structure of new fields + * that will come later. + * + * Moreover, the new kernel includes conflict with glibc includes + * so it is easiest to ignore the kernel altogether (at compile time). + */ + +#define NFS_MOUNT_VERSION 4 + +struct nfs2_fh { + char data[32]; +}; +struct nfs3_fh { + unsigned short size; + unsigned char data[64]; +}; + +struct nfs_mount_data { + int version; /* 1 */ + int fd; /* 1 */ + struct nfs2_fh old_root; /* 1 */ + int flags; /* 1 */ + int rsize; /* 1 */ + int wsize; /* 1 */ + int timeo; /* 1 */ + int retrans; /* 1 */ + int acregmin; /* 1 */ + int acregmax; /* 1 */ + int acdirmin; /* 1 */ + int acdirmax; /* 1 */ + struct sockaddr_in addr; /* 1 */ + char hostname[256]; /* 1 */ + int namlen; /* 2 */ + unsigned int bsize; /* 3 */ + struct nfs3_fh root; /* 4 */ +}; + +/* bits in the flags field */ + +#define NFS_MOUNT_SOFT 0x0001 /* 1 */ +#define NFS_MOUNT_INTR 0x0002 /* 1 */ +#define NFS_MOUNT_SECURE 0x0004 /* 1 */ +#define NFS_MOUNT_POSIX 0x0008 /* 1 */ +#define NFS_MOUNT_NOCTO 0x0010 /* 1 */ +#define NFS_MOUNT_NOAC 0x0020 /* 1 */ +#define NFS_MOUNT_TCP 0x0040 /* 2 */ +#define NFS_MOUNT_VER3 0x0080 /* 3 */ +#define NFS_MOUNT_KERBEROS 0x0100 /* 3 */ +#define NFS_MOUNT_NONLM 0x0200 /* 3 */ +#define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */ + diff --git a/nfsmount.c b/nfsmount.c new file mode 100644 index 0000000..bf26fb5 --- /dev/null +++ b/nfsmount.c @@ -0,0 +1,739 @@ + /* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2003 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * basing on nfsmount.c from util-linux-2.11z: + * - use our logging facilities + * - use our host resolving stuff + * - remove unneeded code + */ + +/* + * nfsmount.c -- Linux NFS mount + * Copyright (C) 1993 Rick Sladkey + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port + * numbers to be specified on the command line. + * + * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler : + * Omit the call to connect() for Linux version 1.3.11 or later. + * + * Wed Oct 1 23:55:28 1997: Dick Streefland + * Implemented the "bg", "fg" and "retry" mount options for NFS. + * + * 1999-02-22 Arkadiusz Mi¶kiewicz + * - added Native Language Support + * + * Modified by Olaf Kirch and Trond Myklebust for new NFS code, + * plus NFSv3 stuff. + * + * 2003-04-14 David Black + * - added support for multiple hostname NFS mounts + */ + +/* + * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp + */ + +#define HAVE_rpcsvc_nfs_prot_h +#define HAVE_inet_aton + +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +// #include + +#include "nfsmount.h" + +#ifdef HAVE_rpcsvc_nfs_prot_h +#include +#else +#include +#define nfsstat nfs_stat +#endif + +#include "nfs_mount4.h" + +#include "log.h" +#include "dns.h" + +#ifndef NFS_PORT +#define NFS_PORT 2049 +#endif +#ifndef NFS_FHSIZE +#define NFS_FHSIZE 32 +#endif + +static char *nfs_strerror(int stat); + +#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r)) + +#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2) + +bool_t +xdr_fhandle3 (XDR *xdrs, fhandle3 *objp) +{ + if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3)) + return FALSE; + return TRUE; +} + +bool_t +xdr_mountstat3 (XDR *xdrs, mountstat3 *objp) +{ + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp) +{ + if (!xdr_fhandle3 (xdrs, &objp->fhandle)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->auth_flavours.auth_flavours_len, ~0, + sizeof (int), (xdrproc_t) xdr_int)) + return FALSE; + return TRUE; +} + +bool_t +xdr_mountres3 (XDR *xdrs, mountres3 *objp) +{ + if (!xdr_mountstat3 (xdrs, &objp->fhs_status)) + return FALSE; + switch (objp->fhs_status) { + case MNT_OK: + if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_dirpath (XDR *xdrs, dirpath *objp) +{ + if (!xdr_string (xdrs, objp, MNTPATHLEN)) + return FALSE; + return TRUE; +} + +bool_t +xdr_fhandle (XDR *xdrs, fhandle objp) +{ + if (!xdr_opaque (xdrs, objp, FHSIZE)) + return FALSE; + return TRUE; +} + +bool_t +xdr_fhstatus (XDR *xdrs, fhstatus *objp) +{ + if (!xdr_u_int (xdrs, &objp->fhs_status)) + return FALSE; + switch (objp->fhs_status) { + case 0: + if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + + +static int +linux_version_code(void) { + struct utsname my_utsname; + int p, q, r; + + if (uname(&my_utsname) == 0) { + p = atoi(strtok(my_utsname.release, ".")); + q = atoi(strtok(NULL, ".")); + r = atoi(strtok(NULL, ".")); + return MAKE_VERSION(p,q,r); + } + return 0; +} + +/* + * Unfortunately, the kernel prints annoying console messages + * in case of an unexpected nfs mount version (instead of + * just returning some error). Therefore we'll have to try + * and figure out what version the kernel expects. + * + * Variables: + * NFS_MOUNT_VERSION: these nfsmount sources at compile time + * nfs_mount_version: version this source and running kernel can handle + */ +static int +find_kernel_nfs_mount_version(void) { + static int kernel_version = -1; + int nfs_mount_version = NFS_MOUNT_VERSION; + + if (kernel_version == -1) + kernel_version = linux_version_code(); + + if (kernel_version) { + if (kernel_version < MAKE_VERSION(2,1,32)) + nfs_mount_version = 1; + else if (kernel_version < MAKE_VERSION(2,2,18)) + nfs_mount_version = 3; + else if (kernel_version < MAKE_VERSION(2,3,0)) + nfs_mount_version = 4; /* since 2.2.18pre9 */ + else if (kernel_version < MAKE_VERSION(2,3,99)) + nfs_mount_version = 3; + else + nfs_mount_version = 4; /* since 2.3.99pre4 */ + } + if (nfs_mount_version > NFS_MOUNT_VERSION) + nfs_mount_version = NFS_MOUNT_VERSION; + log_message("nfsmount: kernel_nfs_mount_version: %d", nfs_mount_version); + return nfs_mount_version; +} + +static struct pmap * +get_mountport(struct sockaddr_in *server_addr, + long unsigned prog, + long unsigned version, + long unsigned proto, + long unsigned port, + int nfs_mount_version) +{ + struct pmaplist *pmap; + static struct pmap p = {0, 0, 0, 0}; + + if (version > MAX_NFSPROT) + version = MAX_NFSPROT; + if (!prog) + prog = MOUNTPROG; + p.pm_prog = prog; + p.pm_vers = version; + p.pm_prot = proto; + p.pm_port = port; + + server_addr->sin_port = PMAPPORT; + pmap = pmap_getmaps(server_addr); + + while (pmap) { + if (pmap->pml_map.pm_prog != prog) + goto next; + if (!version && p.pm_vers > pmap->pml_map.pm_vers) + goto next; + if (version > 2 && pmap->pml_map.pm_vers != version) + goto next; + if (version && version <= 2 && pmap->pml_map.pm_vers > 2) + goto next; + if (pmap->pml_map.pm_vers > MAX_NFSPROT || + (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) || + (port && pmap->pml_map.pm_port != port)) + goto next; + memcpy(&p, &pmap->pml_map, sizeof(p)); + next: + pmap = pmap->pml_next; + } + if (!p.pm_vers) + p.pm_vers = MOUNTVERS; + if (!p.pm_prot) + p.pm_prot = IPPROTO_TCP; + return &p; +} + + + +int nfsmount_prepare(const char *spec, char **mount_opts) +{ + char hostdir[1024]; + CLIENT *mclient; + char *hostname, *dirname, *mounthost = NULL; + struct timeval total_timeout; + enum clnt_stat clnt_stat; + static struct nfs_mount_data data; + int nfs_mount_version; + int val; + struct sockaddr_in server_addr; + struct sockaddr_in mount_server_addr; + struct pmap *pm_mnt; + int msock, fsock; + struct timeval retry_timeout; + union { + struct fhstatus nfsv2; + struct mountres3 nfsv3; + } status; + char *s; + int port, mountport, proto, soft, intr; + int posix, nocto, noac, broken_suid, nolock; + int retry, tcp; + int mountprog, mountvers, nfsprog, nfsvers; + int retval; + time_t t; + time_t prevt; + time_t timeout; + + nfs_mount_version = find_kernel_nfs_mount_version(); + + retval = -1; + msock = fsock = -1; + mclient = NULL; + if (strlen(spec) >= sizeof(hostdir)) { + log_message("nfsmount: excessively long host:dir argument"); + goto fail; + } + strcpy(hostdir, spec); + if ((s = strchr(hostdir, ':'))) { + hostname = hostdir; + dirname = s + 1; + *s = '\0'; + } else { + log_message("nfsmount: directory to mount not in host:dir format"); + goto fail; + } + + server_addr.sin_family = AF_INET; +#ifdef HAVE_inet_aton + if (!inet_aton(hostname, &server_addr.sin_addr)) +#endif + { + if (mygethostbyname(hostname, &server_addr.sin_addr)) { + log_message("nfsmount: can't get address for %s", hostname); + goto fail; + } + } + + memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr)); + + + + /* Set default options. + * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to + * let the kernel decide. + * timeo is filled in after we know whether it'll be TCP or UDP. */ + memset(&data, 0, sizeof(data)); + data.retrans = 3; + data.acregmin = 3; + data.acregmax = 60; + data.acdirmin = 30; + data.acdirmax = 60; +#if NFS_MOUNT_VERSION >= 2 + data.namlen = NAME_MAX; +#endif + + soft = 1; + intr = 0; + posix = 0; + nocto = 0; + nolock = 1; + broken_suid = 0; + noac = 0; + retry = 10000; /* 10000 minutes ~ 1 week */ + tcp = 0; + + mountprog = MOUNTPROG; + mountvers = 0; + port = 0; + mountport = 0; + nfsprog = NFS_PROGRAM; + nfsvers = 0; + + + +retry_mount: + proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP; + + data.flags = (soft ? NFS_MOUNT_SOFT : 0) + | (intr ? NFS_MOUNT_INTR : 0) + | (posix ? NFS_MOUNT_POSIX : 0) + | (nocto ? NFS_MOUNT_NOCTO : 0) + | (noac ? NFS_MOUNT_NOAC : 0); +#if NFS_MOUNT_VERSION >= 2 + if (nfs_mount_version >= 2) + data.flags |= (tcp ? NFS_MOUNT_TCP : 0); +#endif +#if NFS_MOUNT_VERSION >= 3 + if (nfs_mount_version >= 3) + data.flags |= (nolock ? NFS_MOUNT_NONLM : 0); +#endif +#if NFS_MOUNT_VERSION >= 4 + if (nfs_mount_version >= 4) + data.flags |= (broken_suid ? NFS_MOUNT_BROKEN_SUID : 0); +#endif + if (nfsvers > MAX_NFSPROT) { + log_message("NFSv%d not supported!", nfsvers); + return 0; + } + if (mountvers > MAX_NFSPROT) { + log_message("NFSv%d not supported!", nfsvers); + return 0; + } + if (nfsvers && !mountvers) + mountvers = (nfsvers < 3) ? 1 : nfsvers; + if (nfsvers && nfsvers < mountvers) + mountvers = nfsvers; + + /* Adjust options if none specified */ + if (!data.timeo) + data.timeo = tcp ? 70 : 7; + +#ifdef NFS_MOUNT_DEBUG + log_message("rsize = %d, wsize = %d, timeo = %d, retrans = %d", + data.rsize, data.wsize, data.timeo, data.retrans); + log_message("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)", + data.acregmin, data.acregmax, data.acdirmin, data.acdirmax); + log_message("port = %d, retry = %d, flags = %.8x", + port, retry, data.flags); + log_message("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d", + mountprog, mountvers, nfsprog, nfsvers); + log_message("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d", + (data.flags & NFS_MOUNT_SOFT) != 0, + (data.flags & NFS_MOUNT_INTR) != 0, + (data.flags & NFS_MOUNT_POSIX) != 0, + (data.flags & NFS_MOUNT_NOCTO) != 0, + (data.flags & NFS_MOUNT_NOAC) != 0); +#if NFS_MOUNT_VERSION >= 2 + log_message("tcp = %d", + (data.flags & NFS_MOUNT_TCP) != 0); +#endif +#endif + + data.version = nfs_mount_version; + *mount_opts = (char *) &data; + + + /* create mount deamon client */ + /* See if the nfs host = mount host. */ + if (mounthost) { + if (mounthost[0] >= '0' && mounthost[0] <= '9') { + mount_server_addr.sin_family = AF_INET; + mount_server_addr.sin_addr.s_addr = inet_addr(hostname); + } else { + if (mygethostbyname(mounthost, &mount_server_addr.sin_addr)) { + log_message("nfsmount: can't get address for %s", mounthost); + goto fail; + } + } + } + + /* + * The following loop implements the mount retries. On the first + * call, "running_bg" is 0. When the mount times out, and the + * "bg" option is set, the exit status EX_BG will be returned. + * For a backgrounded mount, there will be a second call by the + * child process with "running_bg" set to 1. + * + * The case where the mount point is not present and the "bg" + * option is set, is treated as a timeout. This is done to + * support nested mounts. + * + * The "retry" count specified by the user is the number of + * minutes to retry before giving up. + * + * Only the first error message will be displayed. + */ + retry_timeout.tv_sec = 3; + retry_timeout.tv_usec = 0; + total_timeout.tv_sec = 20; + total_timeout.tv_usec = 0; + timeout = time(NULL) + 60 * retry; + prevt = 0; + t = 30; + val = 1; + + + /* be careful not to use too many CPU cycles */ + if (t - prevt < 30) + sleep(30); + + pm_mnt = get_mountport(&mount_server_addr, + mountprog, + mountvers, + proto, + mountport, + nfs_mount_version); + + /* contact the mount daemon via TCP */ + mount_server_addr.sin_port = htons(pm_mnt->pm_port); + msock = RPC_ANYSOCK; + + switch (pm_mnt->pm_prot) { + case IPPROTO_UDP: + mclient = clntudp_create(&mount_server_addr, + pm_mnt->pm_prog, + pm_mnt->pm_vers, + retry_timeout, + &msock); + if (mclient) + break; + mount_server_addr.sin_port = + htons(pm_mnt->pm_port); + msock = RPC_ANYSOCK; + case IPPROTO_TCP: + mclient = clnttcp_create(&mount_server_addr, + pm_mnt->pm_prog, + pm_mnt->pm_vers, + &msock, 0, 0); + break; + default: + mclient = 0; + } + + if (mclient) { + /* try to mount hostname:dirname */ + mclient->cl_auth = authunix_create_default(); + + /* make pointers in xdr_mountres3 NULL so + * that xdr_array allocates memory for us + */ + memset(&status, 0, sizeof(status)); + + log_message("nfsmount: doing client call in nfs version: %ld", pm_mnt->pm_vers); + if (pm_mnt->pm_vers == 3) + clnt_stat = clnt_call(mclient, + MOUNTPROC3_MNT, + (xdrproc_t) xdr_dirpath, + (caddr_t) &dirname, + (xdrproc_t) xdr_mountres3, + (caddr_t) &status, + total_timeout); + else + clnt_stat = clnt_call(mclient, + MOUNTPROC_MNT, + (xdrproc_t) xdr_dirpath, + (caddr_t) &dirname, + (xdrproc_t) xdr_fhstatus, + (caddr_t) &status, + total_timeout); + + if (clnt_stat == RPC_SUCCESS) + goto succeeded; + + if (prevt == 0) + clnt_perror(mclient, "mount"); + auth_destroy(mclient->cl_auth); + clnt_destroy(mclient); + mclient = 0; + close(msock); + } else { + if (prevt == 0) + clnt_pcreateerror("mount"); + } + prevt = t; + + goto fail; + + succeeded: + nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers; + + if (nfsvers == 2) { + if (status.nfsv2.fhs_status != 0) { + log_message("nfsmount: %s:%s failed, reason given by server: %s", + hostname, dirname, nfs_strerror(status.nfsv2.fhs_status)); + goto fail; + } + memcpy(data.root.data, + (char *) status.nfsv2.fhstatus_u.fhs_fhandle, + NFS_FHSIZE); +#if NFS_MOUNT_VERSION >= 4 + data.root.size = NFS_FHSIZE; + memcpy(data.old_root.data, + (char *) status.nfsv2.fhstatus_u.fhs_fhandle, + NFS_FHSIZE); +#endif + } else { +#if NFS_MOUNT_VERSION >= 4 + fhandle3 *fhandle; + if (status.nfsv3.fhs_status != 0) { + log_message("nfsmount: %s:%s failed, reason given by server: %s", + hostname, dirname, nfs_strerror(status.nfsv3.fhs_status)); + goto fail; + } + fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle; + memset(data.old_root.data, 0, NFS_FHSIZE); + memset(&data.root, 0, sizeof(data.root)); + data.root.size = fhandle->fhandle3_len; + memcpy(data.root.data, + (char *) fhandle->fhandle3_val, + fhandle->fhandle3_len); + + data.flags |= NFS_MOUNT_VER3; +#endif + } + + /* create nfs socket for kernel */ + + if (tcp) { + if (nfs_mount_version < 3) { + log_message("NFS over TCP is not supported."); + goto fail; + } + fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + } else + fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (fsock < 0) { + log_perror("nfs socket"); + goto fail; + } + if (bindresvport(fsock, 0) < 0) { + log_perror("nfs bindresvport"); + goto fail; + } + if (port == 0) { + server_addr.sin_port = PMAPPORT; + port = pmap_getport(&server_addr, nfsprog, nfsvers, + tcp ? IPPROTO_TCP : IPPROTO_UDP); +#if 1 + /* Here we check to see if user is mounting with the + * tcp option. If so, and if the portmap returns a + * '0' for port (service unavailable), we then notify + * the user, and retry with udp. + */ + if (port == 0 && tcp == 1) { + log_message("NFS server reported TCP not available, retrying with UDP..."); + tcp = 0; + goto retry_mount; + } +#endif + + if (port == 0) + port = NFS_PORT; +#ifdef NFS_MOUNT_DEBUG + else + log_message("used portmapper to find NFS port"); +#endif + } +#ifdef NFS_MOUNT_DEBUG + log_message("using port %d for nfs deamon", port); +#endif + server_addr.sin_port = htons(port); + /* + * connect() the socket for kernels 1.3.10 and below only, + * to avoid problems with multihomed hosts. + * --Swen + */ + if (linux_version_code() <= 66314 + && connect(fsock, (struct sockaddr *) &server_addr, + sizeof (server_addr)) < 0) { + log_perror("nfs connect"); + goto fail; + } + + /* prepare data structure for kernel */ + + data.fd = fsock; + memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr)); + strncpy(data.hostname, hostname, sizeof(data.hostname)); + + /* clean up */ + + auth_destroy(mclient->cl_auth); + clnt_destroy(mclient); + close(msock); + return 0; + + /* abort */ + + fail: + if (msock != -1) { + if (mclient) { + auth_destroy(mclient->cl_auth); + clnt_destroy(mclient); + } + close(msock); + } + if (fsock != -1) + close(fsock); + return retval; +} + +/* + * We need to translate between nfs status return values and + * the local errno values which may not be the same. + * + * Andreas Schwab : change errno: + * "after #include the symbol errno is reserved for any use, + * it cannot even be used as a struct tag or field name". + */ + +#ifndef EDQUOT +#define EDQUOT ENOSPC +#endif + +static struct { + enum nfsstat stat; + int errnum; +} nfs_errtbl[] = { + { NFS_OK, 0 }, + { NFSERR_PERM, EPERM }, + { NFSERR_NOENT, ENOENT }, + { NFSERR_IO, EIO }, + { NFSERR_NXIO, ENXIO }, + { NFSERR_ACCES, EACCES }, + { NFSERR_EXIST, EEXIST }, + { NFSERR_NODEV, ENODEV }, + { NFSERR_NOTDIR, ENOTDIR }, + { NFSERR_ISDIR, EISDIR }, +#ifdef NFSERR_INVAL + { NFSERR_INVAL, EINVAL }, /* that Sun forgot */ +#endif + { NFSERR_FBIG, EFBIG }, + { NFSERR_NOSPC, ENOSPC }, + { NFSERR_ROFS, EROFS }, + { NFSERR_NAMETOOLONG, ENAMETOOLONG }, + { NFSERR_NOTEMPTY, ENOTEMPTY }, + { NFSERR_DQUOT, EDQUOT }, + { NFSERR_STALE, ESTALE }, +#ifdef EWFLUSH + { NFSERR_WFLUSH, EWFLUSH }, +#endif + /* Throw in some NFSv3 values for even more fun (HP returns these) */ + { 71, EREMOTE }, + + { -1, EIO } +}; + +static char *nfs_strerror(int stat) +{ + int i; + static char buf[256]; + + for (i = 0; nfs_errtbl[i].stat != (unsigned)-1; i++) { + if (nfs_errtbl[i].stat == (unsigned)stat) + return strerror(nfs_errtbl[i].errnum); + } + sprintf(buf, "unknown nfs status return value: %d", stat); + return buf; +} + diff --git a/nfsmount.h b/nfsmount.h new file mode 100644 index 0000000..a27e8a8 --- /dev/null +++ b/nfsmount.h @@ -0,0 +1,331 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _NFSMOUNT_H_RPCGEN +#define _NFSMOUNT_H_RPCGEN + +#include + +int nfsmount_prepare(const char *spec, char **mount_opts); + + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user or with the express written consent of + * Sun Microsystems, Inc. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1985, 1990 by Sun Microsystems, Inc. + */ + +/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */ +#ifndef _rpcsvc_mount_h +#define _rpcsvc_mount_h +#include +#define MNTPATHLEN 1024 +#define MNTNAMLEN 255 +#define FHSIZE 32 +#define FHSIZE3 64 + +typedef char fhandle[FHSIZE]; + +typedef struct { + u_int fhandle3_len; + char *fhandle3_val; +} fhandle3; + +enum mountstat3 { + MNT_OK = 0, + MNT3ERR_PERM = 1, + MNT3ERR_NOENT = 2, + MNT3ERR_IO = 5, + MNT3ERR_ACCES = 13, + MNT3ERR_NOTDIR = 20, + MNT3ERR_INVAL = 22, + MNT3ERR_NAMETOOLONG = 63, + MNT3ERR_NOTSUPP = 10004, + MNT3ERR_SERVERFAULT = 10006, +}; +typedef enum mountstat3 mountstat3; + +struct fhstatus { + u_int fhs_status; + union { + fhandle fhs_fhandle; + } fhstatus_u; +}; +typedef struct fhstatus fhstatus; + +struct mountres3_ok { + fhandle3 fhandle; + struct { + u_int auth_flavours_len; + int *auth_flavours_val; + } auth_flavours; +}; +typedef struct mountres3_ok mountres3_ok; + +struct mountres3 { + mountstat3 fhs_status; + union { + mountres3_ok mountinfo; + } mountres3_u; +}; +typedef struct mountres3 mountres3; + +typedef char *dirpath; + +typedef char *name; + +typedef struct mountbody *mountlist; + +struct mountbody { + name ml_hostname; + dirpath ml_directory; + mountlist ml_next; +}; +typedef struct mountbody mountbody; + +typedef struct groupnode *groups; + +struct groupnode { + name gr_name; + groups gr_next; +}; +typedef struct groupnode groupnode; + +typedef struct exportnode *exports; + +struct exportnode { + dirpath ex_dir; + groups ex_groups; + exports ex_next; +}; +typedef struct exportnode exportnode; + +struct ppathcnf { + int pc_link_max; + short pc_max_canon; + short pc_max_input; + short pc_name_max; + short pc_path_max; + short pc_pipe_buf; + u_char pc_vdisable; + char pc_xxx; + short pc_mask[2]; +}; +typedef struct ppathcnf ppathcnf; +#endif /*!_rpcsvc_mount_h*/ + +#define MOUNTPROG 100005 +#define MOUNTVERS 1 + +#if defined(__STDC__) || defined(__cplusplus) +#define MOUNTPROC_NULL 0 +extern void * mountproc_null_1(void *, CLIENT *); +extern void * mountproc_null_1_svc(void *, struct svc_req *); +#define MOUNTPROC_MNT 1 +extern fhstatus * mountproc_mnt_1(dirpath *, CLIENT *); +extern fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *); +#define MOUNTPROC_DUMP 2 +extern mountlist * mountproc_dump_1(void *, CLIENT *); +extern mountlist * mountproc_dump_1_svc(void *, struct svc_req *); +#define MOUNTPROC_UMNT 3 +extern void * mountproc_umnt_1(dirpath *, CLIENT *); +extern void * mountproc_umnt_1_svc(dirpath *, struct svc_req *); +#define MOUNTPROC_UMNTALL 4 +extern void * mountproc_umntall_1(void *, CLIENT *); +extern void * mountproc_umntall_1_svc(void *, struct svc_req *); +#define MOUNTPROC_EXPORT 5 +extern exports * mountproc_export_1(void *, CLIENT *); +extern exports * mountproc_export_1_svc(void *, struct svc_req *); +#define MOUNTPROC_EXPORTALL 6 +extern exports * mountproc_exportall_1(void *, CLIENT *); +extern exports * mountproc_exportall_1_svc(void *, struct svc_req *); +extern int mountprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + +#else /* K&R C */ +#define MOUNTPROC_NULL 0 +extern void * mountproc_null_1(); +extern void * mountproc_null_1_svc(); +#define MOUNTPROC_MNT 1 +extern fhstatus * mountproc_mnt_1(); +extern fhstatus * mountproc_mnt_1_svc(); +#define MOUNTPROC_DUMP 2 +extern mountlist * mountproc_dump_1(); +extern mountlist * mountproc_dump_1_svc(); +#define MOUNTPROC_UMNT 3 +extern void * mountproc_umnt_1(); +extern void * mountproc_umnt_1_svc(); +#define MOUNTPROC_UMNTALL 4 +extern void * mountproc_umntall_1(); +extern void * mountproc_umntall_1_svc(); +#define MOUNTPROC_EXPORT 5 +extern exports * mountproc_export_1(); +extern exports * mountproc_export_1_svc(); +#define MOUNTPROC_EXPORTALL 6 +extern exports * mountproc_exportall_1(); +extern exports * mountproc_exportall_1_svc(); +extern int mountprog_1_freeresult (); +#endif /* K&R C */ +#define MOUNTVERS_POSIX 2 + +#if defined(__STDC__) || defined(__cplusplus) +extern void * mountproc_null_2(void *, CLIENT *); +extern void * mountproc_null_2_svc(void *, struct svc_req *); +extern fhstatus * mountproc_mnt_2(dirpath *, CLIENT *); +extern fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *); +extern mountlist * mountproc_dump_2(void *, CLIENT *); +extern mountlist * mountproc_dump_2_svc(void *, struct svc_req *); +extern void * mountproc_umnt_2(dirpath *, CLIENT *); +extern void * mountproc_umnt_2_svc(dirpath *, struct svc_req *); +extern void * mountproc_umntall_2(void *, CLIENT *); +extern void * mountproc_umntall_2_svc(void *, struct svc_req *); +extern exports * mountproc_export_2(void *, CLIENT *); +extern exports * mountproc_export_2_svc(void *, struct svc_req *); +extern exports * mountproc_exportall_2(void *, CLIENT *); +extern exports * mountproc_exportall_2_svc(void *, struct svc_req *); +#define MOUNTPROC_PATHCONF 7 +extern ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *); +extern ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *); +extern int mountprog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + +#else /* K&R C */ +extern void * mountproc_null_2(); +extern void * mountproc_null_2_svc(); +extern fhstatus * mountproc_mnt_2(); +extern fhstatus * mountproc_mnt_2_svc(); +extern mountlist * mountproc_dump_2(); +extern mountlist * mountproc_dump_2_svc(); +extern void * mountproc_umnt_2(); +extern void * mountproc_umnt_2_svc(); +extern void * mountproc_umntall_2(); +extern void * mountproc_umntall_2_svc(); +extern exports * mountproc_export_2(); +extern exports * mountproc_export_2_svc(); +extern exports * mountproc_exportall_2(); +extern exports * mountproc_exportall_2_svc(); +#define MOUNTPROC_PATHCONF 7 +extern ppathcnf * mountproc_pathconf_2(); +extern ppathcnf * mountproc_pathconf_2_svc(); +extern int mountprog_2_freeresult (); +#endif /* K&R C */ +#define MOUNT_V3 3 + +#if defined(__STDC__) || defined(__cplusplus) +#define MOUNTPROC3_NULL 0 +extern void * mountproc3_null_3(void *, CLIENT *); +extern void * mountproc3_null_3_svc(void *, struct svc_req *); +#define MOUNTPROC3_MNT 1 +extern mountres3 * mountproc3_mnt_3(dirpath *, CLIENT *); +extern mountres3 * mountproc3_mnt_3_svc(dirpath *, struct svc_req *); +#define MOUNTPROC3_DUMP 2 +extern mountlist * mountproc3_dump_3(void *, CLIENT *); +extern mountlist * mountproc3_dump_3_svc(void *, struct svc_req *); +#define MOUNTPROC3_UMNT 3 +extern void * mountproc3_umnt_3(dirpath *, CLIENT *); +extern void * mountproc3_umnt_3_svc(dirpath *, struct svc_req *); +#define MOUNTPROC3_UMNTALL 4 +extern void * mountproc3_umntall_3(void *, CLIENT *); +extern void * mountproc3_umntall_3_svc(void *, struct svc_req *); +#define MOUNTPROC3_EXPORT 5 +extern exports * mountproc3_export_3(void *, CLIENT *); +extern exports * mountproc3_export_3_svc(void *, struct svc_req *); +extern int mountprog_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + +#else /* K&R C */ +#define MOUNTPROC3_NULL 0 +extern void * mountproc3_null_3(); +extern void * mountproc3_null_3_svc(); +#define MOUNTPROC3_MNT 1 +extern mountres3 * mountproc3_mnt_3(); +extern mountres3 * mountproc3_mnt_3_svc(); +#define MOUNTPROC3_DUMP 2 +extern mountlist * mountproc3_dump_3(); +extern mountlist * mountproc3_dump_3_svc(); +#define MOUNTPROC3_UMNT 3 +extern void * mountproc3_umnt_3(); +extern void * mountproc3_umnt_3_svc(); +#define MOUNTPROC3_UMNTALL 4 +extern void * mountproc3_umntall_3(); +extern void * mountproc3_umntall_3_svc(); +#define MOUNTPROC3_EXPORT 5 +extern exports * mountproc3_export_3(); +extern exports * mountproc3_export_3_svc(); +extern int mountprog_3_freeresult (); +#endif /* K&R C */ + +/* the xdr functions */ + +#if defined(__STDC__) || defined(__cplusplus) +extern bool_t xdr_fhandle (XDR *, fhandle); +extern bool_t xdr_fhandle3 (XDR *, fhandle3*); +extern bool_t xdr_mountstat3 (XDR *, mountstat3*); +extern bool_t xdr_fhstatus (XDR *, fhstatus*); +extern bool_t xdr_mountres3_ok (XDR *, mountres3_ok*); +extern bool_t xdr_mountres3 (XDR *, mountres3*); +extern bool_t xdr_dirpath (XDR *, dirpath*); +extern bool_t xdr_name (XDR *, name*); +extern bool_t xdr_mountlist (XDR *, mountlist*); +extern bool_t xdr_mountbody (XDR *, mountbody*); +extern bool_t xdr_groups (XDR *, groups*); +extern bool_t xdr_groupnode (XDR *, groupnode*); +extern bool_t xdr_exports (XDR *, exports*); +extern bool_t xdr_exportnode (XDR *, exportnode*); +extern bool_t xdr_ppathcnf (XDR *, ppathcnf*); + +#else /* K&R C */ +extern bool_t xdr_fhandle (); +extern bool_t xdr_fhandle3 (); +extern bool_t xdr_mountstat3 (); +extern bool_t xdr_fhstatus (); +extern bool_t xdr_mountres3_ok (); +extern bool_t xdr_mountres3 (); +extern bool_t xdr_dirpath (); +extern bool_t xdr_name (); +extern bool_t xdr_mountlist (); +extern bool_t xdr_mountbody (); +extern bool_t xdr_groups (); +extern bool_t xdr_groupnode (); +extern bool_t xdr_exports (); +extern bool_t xdr_exportnode (); +extern bool_t xdr_ppathcnf (); + +#endif /* K&R C */ + +#ifdef __cplusplus +} +#endif + +#endif /* !_NFSMOUNT_H_RPCGEN */ + diff --git a/pci-resource/.cvsignore b/pci-resource/.cvsignore new file mode 100644 index 0000000..4c7b084 --- /dev/null +++ b/pci-resource/.cvsignore @@ -0,0 +1 @@ +pci-ids.h diff --git a/pci-resource/Makefile b/pci-resource/Makefile new file mode 100644 index 0000000..8627ab0 --- /dev/null +++ b/pci-resource/Makefile @@ -0,0 +1,25 @@ + #****************************************************************************** + # + # $Id$ + # + # Guillaume Cottenceau (gc@mandrakesoft.com) + # + # Copyright 2000 MandrakeSoft + # + # This software may be freely redistributed under the terms of the GNU + # public license. + # + # You should have received a copy of the GNU General Public License + # along with this program; if not, write to the Free Software + # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + # + #***************************************************************************** + + +all: pci-ids.h + +pci-ids.h: /usr/share/ldetect-lst/pcitable update-pci-ids.pl + perl update-pci-ids.pl > $@ || rm -f $@ + +clean: + rm -f pci-ids.h diff --git a/pci-resource/update-pci-ids.pl b/pci-resource/update-pci-ids.pl new file mode 100755 index 0000000..f31d275 --- /dev/null +++ b/pci-resource/update-pci-ids.pl @@ -0,0 +1,74 @@ +#!/usr/bin/perl + +use MDK::Common; + +-x "../mar/mar" or die "\t*FAILED* Sorry, need ../mar/mar binary\n"; + +require '/usr/bin/merge2pcitable.pl'; +my $drivers = read_pcitable("/usr/share/ldetect-lst/pcitable"); + +print ' +#define PCI_REVISION_ID 0x08 /* Revision ID */ + +struct pci_module_map { + unsigned short vendor; /* PCI vendor id */ + unsigned short device; /* PCI device id */ + const char *name; /* PCI human readable name */ + const char *module; /* module to load */ +}; + +'; + +my %t = ( network => [ 'network' ], + medias => [ 'hd', 'cdrom', 'other' ] + ); +my %sanity_check = + arch() =~ /ia64/ ? + ( network => [ '3c59x', 'eepro100', 'e100', 'tulip', 'via-rhine', 'ne2k-pci', '8139too', '3c90x' ], + medias => [ 'aic7xxx', 'advansys', 'sym53c8xx', 'initio' ], + ) : + arch() =~ /ppc/ ? + ( network => [ '3c59x', 'eepro100', 'tulip', 'via-rhine', 'ne2k-pci', '8139too' ], + medias => [ 'aic7xxx', 'sym53c8xx', 'initio' ], + ) : +# ( network => [ '3c59x', 'eepro100', 'e100', 'tulip', 'via-rhine', 'ne2k-pci', '8139too', 'tlan', '3c90x' ], + ( network => [ '3c59x', 'eepro100', 'e100', 'tulip', 'via-rhine', 'ne2k-pci', '8139too', 'tlan', 'b44', 'e1000', 'sk98lin', 'nvnet' ], + medias => [ 'aic7xxx', 'advansys', 'ncr53c8xx', 'sym53c8xx', 'initio', 'aic79xx' ], + ); + +foreach $type (keys %t) { + print STDERR "$type (checks: ", join('/', @{$sanity_check{$type}}), ") "; + my @modulez; + foreach $floppy (@{$t{$type}}) { + foreach $marfile (glob("../../all.modules/*/${floppy}_modules.mar")) { + -f $marfile or die "\t*FAILED* Sorry, need $marfile mar file\n"; + my @modz = `../mar/mar -l $marfile`; + if ($marfile !~ /(2\.2\.14|19)|(other)/) { + foreach $mandatory (@{$sanity_check{$type}}) { + grep(/\t$mandatory\.o/, @modz) or die "\t*FAILED* Sanity check should prove that $mandatory.o be part of $marfile\n" + } + } + push @modulez, @modz; + print STDERR "."; + } + } + + print "#ifndef DISABLE_".uc($type)." +struct pci_module_map ${type}_pci_ids[] = { +"; + + while (my ($k, $v) = each %$drivers) { + grep(/^\t$v->[0]\.o/, @modulez) or next; + $k =~ /^(....)(....)/; + printf qq|\t{ 0x%s, 0x%s, "%s", "%s" },\n|, + $1, $2, $v->[1], $v->[0]; + } + + print "}; +int ${type}_num_ids = sizeof(${type}_pci_ids) / sizeof(struct pci_module_map); +#endif + +"; + + print STDERR "\n"; +} diff --git a/pcmcia/Makefile b/pcmcia/Makefile new file mode 100644 index 0000000..6363583 --- /dev/null +++ b/pcmcia/Makefile @@ -0,0 +1,48 @@ + #****************************************************************************** + # + # Guillaume Cottenceau (gc@mandrakesoft.com) + # + # Copyright 2000 MandrakeSoft + # + # This software may be freely redistributed under the terms of the GNU + # public license. + # + # You should have received a copy of the GNU General Public License + # along with this program; if not, write to the Free Software + # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + # + #***************************************************************************** + +top_dir = .. + +include $(top_dir)/Makefile.common + + +all: libpcmcia.a libpcmcia-DIET.a + +clean: + rm -f *.o libpcmcia.a + +FLAGS = -Wall -Os -fomit-frame-pointer -pipe -c -I.. -D_BSD_SOURCE + + +OBJS = pcmcia_probe.o cardmgr.o lex_config.o yacc_config.o + +OBJS-DIET = $(subst .o,-DIET.o,$(OBJS)) + + +libpcmcia.a: $(OBJS) + ar -cru $@ $^ + ranlib $@ + +libpcmcia-DIET.a: $(OBJS-DIET) + ar -cru $@ $^ + ranlib $@ + + +$(OBJS): %.o: %.c + gcc $(FLAGS) $(GLIBC_INCLUDES) -c $< -o $@ + +$(OBJS-DIET): %-DIET.o: %.c + gcc $(FLAGS) $(DIETLIBC_INCLUDES) -c $< -o $@ + diff --git a/pcmcia/bulkmem.h b/pcmcia/bulkmem.h new file mode 100644 index 0000000..7748d44 --- /dev/null +++ b/pcmcia/bulkmem.h @@ -0,0 +1,195 @@ +/* + * Definitions for bulk memory services + * + * bulkmem.h 1.13 2001/08/24 12:16:12 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + * bulkmem.h 1.3 1995/05/27 04:49:49 + */ + +#ifndef _LINUX_BULKMEM_H +#define _LINUX_BULKMEM_H + +/* For GetFirstRegion and GetNextRegion */ +typedef struct region_info_t { + u_int Attributes; + u_int CardOffset; + u_int RegionSize; + u_int AccessSpeed; + u_int BlockSize; + u_int PartMultiple; + u_char JedecMfr, JedecInfo; + memory_handle_t next; +} region_info_t; + +#define REGION_TYPE 0x0001 +#define REGION_TYPE_CM 0x0000 +#define REGION_TYPE_AM 0x0001 +#define REGION_PREFETCH 0x0008 +#define REGION_CACHEABLE 0x0010 +#define REGION_BAR_MASK 0xe000 +#define REGION_BAR_SHIFT 13 + +/* For OpenMemory */ +typedef struct open_mem_t { + u_int Attributes; + u_int Offset; +} open_mem_t; + +/* Attributes for OpenMemory */ +#define MEMORY_TYPE 0x0001 +#define MEMORY_TYPE_CM 0x0000 +#define MEMORY_TYPE_AM 0x0001 +#define MEMORY_EXCLUSIVE 0x0002 +#define MEMORY_PREFETCH 0x0008 +#define MEMORY_CACHEABLE 0x0010 +#define MEMORY_BAR_MASK 0xe000 +#define MEMORY_BAR_SHIFT 13 + +typedef struct eraseq_entry_t { + memory_handle_t Handle; + u_char State; + u_int Size; + u_int Offset; + void *Optional; +} eraseq_entry_t; + +typedef struct eraseq_hdr_t { + int QueueEntryCnt; + eraseq_entry_t *QueueEntryArray; +} eraseq_hdr_t; + +#define ERASE_QUEUED 0x00 +#define ERASE_IN_PROGRESS(n) (((n) > 0) && ((n) < 0x80)) +#define ERASE_IDLE 0xff +#define ERASE_PASSED 0xe0 +#define ERASE_FAILED 0xe1 + +#define ERASE_MISSING 0x80 +#define ERASE_MEDIA_WRPROT 0x84 +#define ERASE_NOT_ERASABLE 0x85 +#define ERASE_BAD_OFFSET 0xc1 +#define ERASE_BAD_TECH 0xc2 +#define ERASE_BAD_SOCKET 0xc3 +#define ERASE_BAD_VCC 0xc4 +#define ERASE_BAD_VPP 0xc5 +#define ERASE_BAD_SIZE 0xc6 + +/* For CopyMemory */ +typedef struct copy_op_t { + u_int Attributes; + u_int SourceOffset; + u_int DestOffset; + u_int Count; +} copy_op_t; + +/* For ReadMemory and WriteMemory */ +typedef struct mem_op_t { + u_int Attributes; + u_int Offset; + u_int Count; +} mem_op_t; + +#define MEM_OP_BUFFER 0x01 +#define MEM_OP_BUFFER_USER 0x00 +#define MEM_OP_BUFFER_KERNEL 0x01 +#define MEM_OP_DISABLE_ERASE 0x02 +#define MEM_OP_VERIFY 0x04 + +/* For RegisterMTD */ +typedef struct mtd_reg_t { + u_int Attributes; + u_int Offset; + u_long MediaID; +} mtd_reg_t; + +/* + * Definitions for MTD requests + */ + +typedef struct mtd_request_t { + u_int SrcCardOffset; + u_int DestCardOffset; + u_int TransferLength; + u_int Function; + u_long MediaID; + u_int Status; + u_int Timeout; +} mtd_request_t; + +/* Fields in MTD Function */ +#define MTD_REQ_ACTION 0x003 +#define MTD_REQ_ERASE 0x000 +#define MTD_REQ_READ 0x001 +#define MTD_REQ_WRITE 0x002 +#define MTD_REQ_COPY 0x003 +#define MTD_REQ_NOERASE 0x004 +#define MTD_REQ_VERIFY 0x008 +#define MTD_REQ_READY 0x010 +#define MTD_REQ_TIMEOUT 0x020 +#define MTD_REQ_LAST 0x040 +#define MTD_REQ_FIRST 0x080 +#define MTD_REQ_KERNEL 0x100 + +/* Status codes */ +#define MTD_WAITREQ 0x00 +#define MTD_WAITTIMER 0x01 +#define MTD_WAITRDY 0x02 +#define MTD_WAITPOWER 0x03 + +/* + * Definitions for MTD helper functions + */ + +/* For MTDModifyWindow */ +typedef struct mtd_mod_win_t { + u_int Attributes; + u_int AccessSpeed; + u_int CardOffset; +} mtd_mod_win_t; + +/* For MTDSetVpp */ +typedef struct mtd_vpp_req_t { + u_char Vpp1, Vpp2; +} mtd_vpp_req_t; + +/* For MTDRDYMask */ +typedef struct mtd_rdy_req_t { + u_int Mask; +} mtd_rdy_req_t; + +enum mtd_helper { + MTDRequestWindow, MTDModifyWindow, MTDReleaseWindow, + MTDSetVpp, MTDRDYMask +}; + +#ifdef IN_CARD_SERVICES +extern int MTDHelperEntry(int func, void *a1, void *a2); +#else +extern int MTDHelperEntry(int func, ...); +#endif + +#endif /* _LINUX_BULKMEM_H */ diff --git a/pcmcia/bus_ops.h b/pcmcia/bus_ops.h new file mode 100644 index 0000000..d5f362a --- /dev/null +++ b/pcmcia/bus_ops.h @@ -0,0 +1,157 @@ +/* + * bus_ops.h 1.12 2001/08/24 12:16:12 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_BUS_OPS_H +#define _LINUX_BUS_OPS_H + +#include + +#ifdef CONFIG_VIRTUAL_BUS + +typedef struct bus_operations { + void *priv; + u32 (*b_in)(void *bus, u32 port, s32 sz); + void (*b_ins)(void *bus, u32 port, void *buf, + u32 count, s32 sz); + void (*b_out)(void *bus, u32 val, u32 port, s32 sz); + void (*b_outs)(void *bus, u32 port, void *buf, + u32 count, s32 sz); + void *(*b_ioremap)(void *bus, u_long ofs, u_long sz); + void (*b_iounmap)(void *bus, void *addr); + u32 (*b_read)(void *bus, void *addr, s32 sz); + void (*b_write)(void *bus, u32 val, void *addr, s32 sz); + void (*b_copy_from)(void *bus, void *d, void *s, u32 count); + void (*b_copy_to)(void *bus, void *d, void *s, u32 count); + int (*b_request_irq)(void *bus, u_int irq, + void (*handler)(int, void *, + struct pt_regs *), + u_long flags, const char *device, + void *dev_id); + void (*b_free_irq)(void *bus, u_int irq, void *dev_id); +} bus_operations; + +#define bus_inb(b,p) (b)->b_in((b),(p),0) +#define bus_inw(b,p) (b)->b_in((b),(p),1) +#define bus_inl(b,p) (b)->b_in((b),(p),2) +#define bus_inw_ns(b,p) (b)->b_in((b),(p),-1) +#define bus_inl_ns(b,p) (b)->b_in((b),(p),-2) + +#define bus_insb(b,p,a,c) (b)->b_ins((b),(p),(a),(c),0) +#define bus_insw(b,p,a,c) (b)->b_ins((b),(p),(a),(c),1) +#define bus_insl(b,p,a,c) (b)->b_ins((b),(p),(a),(c),2) +#define bus_insw_ns(b,p,a,c) (b)->b_ins((b),(p),(a),(c),-1) +#define bus_insl_ns(b,p,a,c) (b)->b_ins((b),(p),(a),(c),-2) + +#define bus_outb(b,v,p) (b)->b_out((b),(v),(p),0) +#define bus_outw(b,v,p) (b)->b_out((b),(v),(p),1) +#define bus_outl(b,v,p) (b)->b_out((b),(v),(p),2) +#define bus_outw_ns(b,v,p) (b)->b_out((b),(v),(p),-1) +#define bus_outl_ns(b,v,p) (b)->b_out((b),(v),(p),-2) + +#define bus_outsb(b,p,a,c) (b)->b_outs((b),(p),(a),(c),0) +#define bus_outsw(b,p,a,c) (b)->b_outs((b),(p),(a),(c),1) +#define bus_outsl(b,p,a,c) (b)->b_outs((b),(p),(a),(c),2) +#define bus_outsw_ns(b,p,a,c) (b)->b_outs((b),(p),(a),(c),-1) +#define bus_outsl_ns(b,p,a,c) (b)->b_outs((b),(p),(a),(c),-2) + +#define bus_readb(b,a) (b)->b_read((b),(a),0) +#define bus_readw(b,a) (b)->b_read((b),(a),1) +#define bus_readl(b,a) (b)->b_read((b),(a),2) +#define bus_readw_ns(b,a) (b)->b_read((b),(a),-1) +#define bus_readl_ns(b,a) (b)->b_read((b),(a),-2) + +#define bus_writeb(b,v,a) (b)->b_write((b),(v),(a),0) +#define bus_writew(b,v,a) (b)->b_write((b),(v),(a),1) +#define bus_writel(b,v,a) (b)->b_write((b),(v),(a),2) +#define bus_writew_ns(b,v,a) (b)->b_write((b),(v),(a),-1) +#define bus_writel_ns(b,v,a) (b)->b_write((b),(v),(a),-2) + +#define bus_ioremap(b,s,n) (b)->b_ioremap((b),(s),(n)) +#define bus_iounmap(b,a) (b)->b_iounmap((b),(a)) +#define bus_memcpy_fromio(b,d,s,n) (b)->b_copy_from((b),(d),(s),(n)) +#define bus_memcpy_toio(b,d,s,n) (b)->b_copy_to((b),(d),(s),(n)) + +#define bus_request_irq(b,i,h,f,n,d) \ + (b)->b_request_irq((b),(i),(h),(f),(n),(d)) +#define bus_free_irq(b,i,d) (b)->b_free_irq((b),(i),(d)) + +#else + +#define bus_inb(b,p) inb(p) +#define bus_inw(b,p) inw(p) +#define bus_inl(b,p) inl(p) +#define bus_inw_ns(b,p) inw_ns(p) +#define bus_inl_ns(b,p) inl_ns(p) + +#define bus_insb(b,p,a,c) insb(p,a,c) +#define bus_insw(b,p,a,c) insw(p,a,c) +#define bus_insl(b,p,a,c) insl(p,a,c) +#define bus_insw_ns(b,p,a,c) insw_ns(p,a,c) +#define bus_insl_ns(b,p,a,c) insl_ns(p,a,c) + +#define bus_outb(b,v,p) outb(b,v,p) +#define bus_outw(b,v,p) outw(b,v,p) +#define bus_outl(b,v,p) outl(b,v,p) +#define bus_outw_ns(b,v,p) outw_ns(b,v,p) +#define bus_outl_ns(b,v,p) outl_ns(b,v,p) + +#define bus_outsb(b,p,a,c) outsb(p,a,c) +#define bus_outsw(b,p,a,c) outsw(p,a,c) +#define bus_outsl(b,p,a,c) outsl(p,a,c) +#define bus_outsw_ns(b,p,a,c) outsw_ns(p,a,c) +#define bus_outsl_ns(b,p,a,c) outsl_ns(p,a,c) + +#define bus_readb(b,a) readb(a) +#define bus_readw(b,a) readw(a) +#define bus_readl(b,a) readl(a) +#define bus_readw_ns(b,a) readw_ns(a) +#define bus_readl_ns(b,a) readl_ns(a) + +#define bus_writeb(b,v,a) writeb(v,a) +#define bus_writew(b,v,a) writew(v,a) +#define bus_writel(b,v,a) writel(v,a) +#define bus_writew_ns(b,v,a) writew_ns(v,a) +#define bus_writel_ns(b,v,a) writel_ns(v,a) + +#define bus_ioremap(b,s,n) ioremap(s,n) +#define bus_iounmap(b,a) iounmap(a) +#define bus_memcpy_fromio(b,d,s,n) memcpy_fromio(d,s,n) +#define bus_memcpy_toio(b,d,s,n) memcpy_toio(d,s,n) + +#ifdef CONFIG_8xx +#define bus_request_irq(b,i,h,f,n,d) request_8xxirq((i),(h),(f),(n),(d)) +#else +#define bus_request_irq(b,i,h,f,n,d) request_irq((i),(h),(f),(n),(d)) +#endif + +#define bus_free_irq(b,i,d) free_irq((i),(d)) + +#endif /* CONFIG_VIRTUAL_BUS */ + +#endif /* _LINUX_BUS_OPS_H */ diff --git a/pcmcia/cardmgr.c b/pcmcia/cardmgr.c new file mode 100644 index 0000000..8add099 --- /dev/null +++ b/pcmcia/cardmgr.c @@ -0,0 +1,1471 @@ +/*====================================================================== + + PCMCIA Card Manager daemon + + cardmgr.c 1.183 2003/02/27 07:11:45 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU General Public License version 2 (the "GPL"), in + which case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "cardmgr.h" + +/*====================================================================*/ + +typedef struct socket_info_t { + int fd; + int state; + card_info_t *card; + bind_info_t *bind[MAX_BINDINGS]; + mtd_ident_t *mtd[2*CISTPL_MAX_DEVICES]; + cistpl_funcid_t funcid; + cistpl_manfid_t manfid; + cistpl_vers_1_t prodid; +} socket_info_t; + +#define SOCKET_PRESENT 0x01 +#define SOCKET_READY 0x02 +#define SOCKET_HOTPLUG 0x04 + +/* Linked list of resource adjustments */ +struct adjust_list_t *root_adjust = NULL; + +/* Linked list of device definitions */ +struct device_info_t *root_device = NULL; + +/* Special pointer to "anonymous" card definition */ +struct card_info_t *blank_card = NULL; + +/* Linked list of card definitions */ +struct card_info_t *root_card = NULL; + +/* Linked list of function definitions */ +struct card_info_t *root_func = NULL; + +/* Linked list of MTD definitions */ +struct mtd_ident_t *root_mtd = NULL; + +/* Default MTD */ +struct mtd_ident_t *default_mtd = NULL; + +static int sockets; +static struct socket_info_t socket[MAX_SOCKS]; + +/* Default path for config file, device scripts */ +#ifdef ETC +static char *configpath = ETC; +#else +static char *configpath = "/etc/pcmcia"; +#endif + +/* Default path for pid file */ +static char *pidfile = "/var/run/cardmgr.pid"; + +/* Default path for finding modules */ +static char *modpath = NULL; + +/* Default path for socket info table */ +static char *stabfile; + +/* If set, don't generate beeps when cards are inserted */ +static int be_quiet = 0; + +/* If set, use modprobe instead of insmod */ +static int do_modprobe = 0; + +/* If set, configure already inserted cards, then exit */ +static int one_pass = 0; + +/* Extra message logging? */ +static int verbose = 0; + +#define EITHER_OR(a, b) ((a) ? (a) : (b)) + +/*====================================================================*/ + +static int major = 0; + +static int lookup_dev(char *name) +{ + FILE *f; + int n; + char s[32], t[32]; + + f = fopen("/proc/devices", "r"); + if (f == NULL) + return -errno; + while (fgets(s, 32, f) != NULL) { + if (sscanf(s, "%d %s", &n, t) == 2) + if (strcmp(name, t) == 0) + break; + } + fclose(f); + if (strcmp(name, t) == 0) + return n; + else + return -ENODEV; +} + +int open_dev(dev_t dev, int mode) +{ + static char *paths[] = { + "/var/lib/pcmcia", "/var/run", "/dev", "/tmp", NULL + }; + static int nd = 0; + char **p, fn[64]; + int fd; + + int o_mode = (mode & S_IWRITE) ? O_RDWR : O_RDONLY; + for (p = paths; *p; p++) { + sprintf(fn, "%s/cm-%d-%d", *p, getpid(), nd++); + if (mknod(fn, mode, dev) == 0) { + fd = open(fn, o_mode); + if (fd < 0) + fd = open(fn, O_NONBLOCK|o_mode); + unlink(fn); + if (fd >= 0) + return fd; + if (errno == ENODEV) + break; + } + + } + return -1; +} + +int open_sock(int sock, int mode) +{ + dev_t dev = (major<<8)+sock; + return open_dev(dev, mode); +} + +/*====================================================================== + + xlate_scsi_name() is a sort-of-hack used to deduce the minor + device numbers of SCSI devices, from the information available to + the low-level driver. + +======================================================================*/ + +/* getting these from headers is too much grief */ +#define SCSI_DISK0_MAJOR 8 +#define SCSI_TAPE_MAJOR 9 +#define SCSI_CDROM_MAJOR 11 +#define SCSI_GENERIC_MAJOR 21 +#define SCSI_IOCTL_GET_IDLUN 0x5382 + +static int xlate_scsi_name(bind_info_t *bind) +{ + int i, fd, mode, minor; + u_long arg[2], id1, id2; + + id1 = strtol(bind->name+3, NULL, 16); + if ((bind->major == SCSI_DISK0_MAJOR) || + (bind->major == SCSI_CDROM_MAJOR)) + mode = S_IREAD|S_IFBLK; + else + mode = S_IREAD|S_IFCHR; + + for (i = 0; i < 16; i++) { + minor = (bind->major == SCSI_DISK0_MAJOR) ? (i<<4) : i; + fd = open_dev((bind->major<<8)+minor, mode); + if (fd < 0) + continue; + if (ioctl(fd, SCSI_IOCTL_GET_IDLUN, arg) == 0) { + id2 = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) + + ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000); + if (id1 == id2) { + close(fd); + switch (bind->major) { + case SCSI_DISK0_MAJOR: + case SCSI_GENERIC_MAJOR: + sprintf(bind->name+2, "%c", 'a'+i); break; + case SCSI_CDROM_MAJOR: + sprintf(bind->name, "scd%d", i); break; + case SCSI_TAPE_MAJOR: + sprintf(bind->name+2, "%d", i); break; + } + bind->minor = minor; + return 0; + } + } + close(fd); + } + return -1; +} + +/*====================================================================*/ + +#define BEEP_TIME 150 +#define BEEP_OK 1000 +#define BEEP_WARN 2000 +#define BEEP_ERR 4000 + +#include + +static void beep(unsigned int ms, unsigned int freq) +{ + int fd, arg; + + if (be_quiet) + return; + fd = open("/dev/tty0", O_RDWR); + if (fd < 0) + return; + arg = (ms << 16) | freq; + ioctl(fd, KDMKTONE, arg); + close(fd); + usleep(ms*1000); +} + +/*====================================================================*/ + +static void write_pid(void) +{ + FILE *f; + f = fopen(pidfile, "w"); + if (f == NULL) + syslog(LOG_WARNING, "could not open %s: %m", pidfile); + else { + fprintf(f, "%d\n", getpid()); + fclose(f); + } +} + +static void write_stab(void) +{ + int i, j, k; + FILE *f; + socket_info_t *s; + bind_info_t *bind; + + f = fopen(stabfile, "w"); + if (f == NULL) { + syslog(LOG_WARNING, "fopen(stabfile) failed: %m"); + return; + } + if (flock(fileno(f), LOCK_EX) != 0) { + syslog(LOG_ERR, "flock(stabfile) failed: %m"); + return; + } + for (i = 0; i < sockets; i++) { + s = &socket[i]; + fprintf(f, "Socket %d: ", i); + if (!(s->state & SOCKET_PRESENT)) { + fprintf(f, "empty\n"); + } else if (s->state & SOCKET_HOTPLUG) { + fprintf(f, "CardBus hotplug device\n"); + } else if (!s->card) { + fprintf(f, "unsupported card\n"); + } else { + fprintf(f, "%s\n", s->card->name); + for (j = 0; j < s->card->bindings; j++) + for (k = 0, bind = s->bind[j]; + bind != NULL; + k++, bind = bind->next) { + char *class = s->card->class[j]; + if (!class) class = s->card->device[j]->class; + fprintf(f, "%d\t%s\t%s\t%d\t%s", + i, (class ? class : "none"), + bind->dev_info, k, bind->name); + if (bind->major) + fprintf(f, "\t%d\t%d\n", + bind->major, bind->minor); + else + fputc('\n', f); + } + } + } + fflush(f); + flock(fileno(f), LOCK_UN); + fclose(f); +} + +/*====================================================================*/ + +static int get_tuple(int ns, cisdata_t code, ds_ioctl_arg_t *arg) +{ + socket_info_t *s = &socket[ns]; + + arg->tuple.DesiredTuple = code; + arg->tuple.Attributes = 0; + if (ioctl(s->fd, DS_GET_FIRST_TUPLE, arg) != 0) + return -1; + arg->tuple.TupleOffset = 0; + if (ioctl(s->fd, DS_GET_TUPLE_DATA, arg) != 0) { + syslog(LOG_INFO, "error reading CIS data on socket %d: %m", ns); + return -1; + } + if (ioctl(s->fd, DS_PARSE_TUPLE, arg) != 0) { + syslog(LOG_INFO, "error parsing CIS on socket %d: %m", ns); + return -1; + } + return 0; +} + +/*====================================================================== + + For configurations with the standalone PCMCIA modules, this is + used to get PCI device ID's for CardBus cards. + +======================================================================*/ + +typedef struct pci_id { + u_short vendor, device; + struct pci_id *next; +} pci_id_t; + +static int get_pci_id(int ns, pci_id_t *id) +{ + socket_info_t *s = &socket[ns]; + config_info_t config; + + config.Function = config.ConfigBase = 0; + if ((ioctl(s->fd, DS_GET_CONFIGURATION_INFO, &config) != 0) || + (config.IntType != INT_CARDBUS) || !config.ConfigBase) + return 0; + id->vendor = config.ConfigBase & 0xffff; + id->device = config.ConfigBase >> 16; + return 1; +} + +/*====================================================================*/ + +static void log_card_info(socket_info_t *s, pci_id_t *pci_id) +{ + char v[256] = ""; + int i; + static char *fn[] = { + "multi", "memory", "serial", "parallel", "fixed disk", + "video", "network", "AIMS", "SCSI" + }; + + if (s->prodid.ns) { + for (i = 0; i < s->prodid.ns; i++) + sprintf(v+strlen(v), "%s\"%s\"", + (i>0) ? ", " : "", s->prodid.str+s->prodid.ofs[i]); + syslog(LOG_INFO, " product info: %s", v); + } else { + syslog(LOG_INFO, " no product info available"); + } + *v = '\0'; + if (s->manfid.manf != 0) + sprintf(v, " manfid: 0x%04x, 0x%04x", + s->manfid.manf, s->manfid.card); + if (s->funcid.func != 0xff) + sprintf(v+strlen(v), " function: %d (%s)", s->funcid.func, + fn[s->funcid.func]); + if (strlen(v) > 0) syslog(LOG_INFO, "%s", v); + if (pci_id->vendor != 0) + syslog(LOG_INFO, " PCI id: 0x%04x, 0x%04x", + pci_id->vendor, pci_id->device); +} + +static card_info_t *lookup_card(int ns) +{ + socket_info_t *s = &socket[ns]; + card_info_t *card = NULL; + ds_ioctl_arg_t arg; + pci_id_t pci_id = { 0, 0 }; + cs_status_t status; + int i, ret, has_cis = 0; + + s->manfid = (cistpl_manfid_t) { 0, 0 }; + s->funcid = (cistpl_funcid_t) { 0xff, 0xff }; + s->prodid = (cistpl_vers_1_t) { 0, 0, 0 }; + + /* Do we have a CIS structure? */ + ret = ioctl(s->fd, DS_VALIDATE_CIS, &arg); + has_cis = ((ret == 0) && (arg.cisinfo.Chains > 0)); + + /* Try to read VERS_1, MANFID tuples */ + if (has_cis) { + /* rule of thumb: cards with no FUNCID, but with common memory + device geometry information, are probably memory cards */ + if (get_tuple(ns, CISTPL_FUNCID, &arg) == 0) + s->funcid = arg.tuple_parse.parse.funcid; + else if (get_tuple(ns, CISTPL_DEVICE_GEO, &arg) == 0) + s->funcid.func = CISTPL_FUNCID_MEMORY; + if (get_tuple(ns, CISTPL_MANFID, &arg) == 0) + s->manfid = arg.tuple_parse.parse.manfid; + if (get_tuple(ns, CISTPL_VERS_1, &arg) == 0) + s->prodid = arg.tuple_parse.parse.version_1; + + for (card = root_card; card; card = card->next) { + + if (card->ident_type & + ~(VERS_1_IDENT|MANFID_IDENT|TUPLE_IDENT)) + continue; + + if (card->ident_type & VERS_1_IDENT) { + if (!s->prodid.ns) + continue; + for (i = 0; i < card->id.vers.ns; i++) { + if (strcmp(card->id.vers.pi[i], "*") == 0) + continue; + if (i >= s->prodid.ns) + break; + if (strcmp(card->id.vers.pi[i], + s->prodid.str+s->prodid.ofs[i]) != 0) + break; + } + if (i < card->id.vers.ns) + continue; + } + + if (card->ident_type & MANFID_IDENT) { + if ((s->manfid.manf != card->manfid.manf) || + (s->manfid.card != card->manfid.card)) + continue; + } + + if (card->ident_type & TUPLE_IDENT) { + arg.tuple.DesiredTuple = card->id.tuple.code; + arg.tuple.Attributes = 0; + ret = ioctl(s->fd, DS_GET_FIRST_TUPLE, &arg); + if (ret != 0) continue; + arg.tuple.TupleOffset = card->id.tuple.ofs; + ret = ioctl(s->fd, DS_GET_TUPLE_DATA, &arg); + if (ret != 0) continue; + if (strncmp((char *)arg.tuple_parse.data, + card->id.tuple.info, + strlen(card->id.tuple.info)) != 0) + continue; + } + + break; /* we have a match */ + } + } + + /* Check PCI vendor/device info */ + status.Function = 0; + ioctl(s->fd, DS_GET_STATUS, &status); + if (status.CardState & CS_EVENT_CB_DETECT) { + if (get_pci_id(ns, &pci_id)) { + if (!card) { + for (card = root_card; card; card = card->next) + if ((card->ident_type == PCI_IDENT) && + (pci_id.vendor == card->manfid.manf) && + (pci_id.device == card->manfid.card)) + break; + } + } else { + /* this is a 2.4 kernel; hotplug handles these cards */ + s->state |= SOCKET_HOTPLUG; + syslog(LOG_INFO, "socket %d: CardBus hotplug device", ns); + //beep(BEEP_TIME, BEEP_OK); + return NULL; + } + } + + /* Try for a FUNCID match */ + if (!card && (s->funcid.func != 0xff)) { + for (card = root_func; card; card = card->next) + if (card->id.func.funcid == s->funcid.func) + break; + } + + if (card) { + syslog(LOG_INFO, "socket %d: %s", ns, card->name); + beep(BEEP_TIME, BEEP_OK); + if (verbose) log_card_info(s, &pci_id); + return card; + } + + if (!blank_card || (status.CardState & CS_EVENT_CB_DETECT) || + s->manfid.manf || s->manfid.card || s->prodid.ns || pci_id.vendor) { + syslog(LOG_INFO, "unsupported card in socket %d", ns); + if (one_pass) return NULL; + beep(BEEP_TIME, BEEP_ERR); + log_card_info(s, &pci_id); + write_stab(); + return NULL; + } else { + card = blank_card; + syslog(LOG_INFO, "socket %d: %s", ns, card->name); + beep(BEEP_TIME, BEEP_WARN); + return card; + } +} + +/*====================================================================*/ + +static void load_config(void) +{ + if (chdir(configpath) != 0) { + syslog(LOG_ERR, "chdir to %s failed: %m", configpath); + exit(EXIT_FAILURE); + } + if (parse_configfile("config") != 0) + exit(EXIT_FAILURE); + if (root_device == NULL) + syslog(LOG_WARNING, "no device drivers defined"); + if ((root_card == NULL) && (root_func == NULL)) + syslog(LOG_WARNING, "no cards defined"); +} + +/*====================================================================*/ + +static void free_card(card_info_t *card) +{ + if (card && (--card->refs == 0)) { + int i; + free(card->name); + switch(card->ident_type) { + case VERS_1_IDENT: + for (i = 0; i < card->id.vers.ns; i++) + free(card->id.vers.pi[i]); + break; + case TUPLE_IDENT: + free(card->id.tuple.info); + break; + default: + break; + } + for (i = 0; i < card->bindings; i++) + if (card->class[i]) + free(card->class[i]); + free(card); + } +} + +static void free_device(device_info_t *dev) +{ + if (dev && (--dev->refs == 0)) { + int i; + for (i = 0; i < dev->modules; i++) { + free(dev->module[i]); + if (dev->opts[i]) free(dev->opts[i]); + } + if (dev->class) free(dev->class); + free(dev); + } +} + +static void free_mtd(mtd_ident_t *mtd) +{ + if (mtd && (--mtd->refs == 0)) { + free(mtd->name); + free(mtd->module); + free(mtd); + } +} + +static void free_config(void) +{ + while (root_adjust != NULL) { + adjust_list_t *adj = root_adjust; + root_adjust = root_adjust->next; + free(adj); + } + + while (root_device != NULL) { + device_info_t *dev = root_device; + root_device = root_device->next; + free_device(dev); + } + + while (root_card != NULL) { + card_info_t *card = root_card; + root_card = root_card->next; + free_card(card); + } + + while (root_func != NULL) { + card_info_t *card = root_func; + root_func = root_func->next; + free_card(card); + } + blank_card = NULL; + + while (root_mtd != NULL) { + mtd_ident_t *mtd = root_mtd; + root_mtd = root_mtd->next; + free_mtd(mtd); + } + default_mtd = NULL; +} + +/*====================================================================*/ + +static int execute(char *msg, char *cmd) +{ + int ret; + FILE *f; + char line[256]; + + syslog(LOG_INFO, "executing: '%s'", cmd); + strcat(cmd, " 2>&1"); + f = popen(cmd, "r"); + while (fgets(line, 255, f)) { + line[strlen(line)-1] = '\0'; + syslog(LOG_INFO, "+ %s", line); + } + ret = pclose(f); + if (WIFEXITED(ret)) { + if (WEXITSTATUS(ret)) + syslog(LOG_INFO, "%s exited with status %d", + msg, WEXITSTATUS(ret)); + return WEXITSTATUS(ret); + } else + syslog(LOG_INFO, "%s exited on signal %d", + msg, WTERMSIG(ret)); + return -1; +} + +/*====================================================================*/ + +static int execute_on_dev(char *action, char *class, char *dev) +{ + /* Fixed length strings are ok here */ + char msg[128], cmd[128]; + + sprintf(msg, "%s cmd", action); + sprintf(cmd, "./%s %s %s", class, action, dev); + return execute(msg, cmd); +} + +static void eprintf(char *name, char *fmt, ...) +{ + va_list args; + char s[32]; + va_start(args, fmt); + vsprintf(s, fmt, args); + setenv(name, s, 1); + va_end(args); +} + +static int execute_on_all(char *cmd, char *class, int sn, int fn) +{ + socket_info_t *s = &socket[sn]; + bind_info_t *bind; + int i, k, ret = 0; + char m[10]; + + eprintf("MANFID", "%04x,%04x", s->manfid.manf, s->manfid.card); + eprintf("FUNCID", "%d", s->funcid.func); + for (i = 0; i < 4; i++) { + sprintf(m, "PRODID_%d", i+1); + if (i < s->prodid.ns) + setenv(m, s->prodid.str+s->prodid.ofs[i], 1); + else + unsetenv(m); + } + eprintf("SOCKET", "%d", sn); + + for (k = 0, bind = s->bind[fn]; bind != NULL; k++, bind = bind->next) + if (bind->name[0] && (bind->name[2] != '#')) { + setenv("CLASS", class, 1); + setenv("DRIVER", bind->dev_info, 1); + eprintf("INSTANCE", "%d", k); + if (bind->major) { + eprintf("MAJOR", "%d", bind->major); + eprintf("MINOR", "%d", bind->minor); + } else { + unsetenv("MAJOR"); + unsetenv("MINOR"); + } + ret |= execute_on_dev(cmd, class, bind->name); + } + return ret; +} + +/*====================================================================*/ + +typedef struct module_list_t { + char *mod; + int usage; + struct module_list_t *next; +} module_list_t; + +static module_list_t *module_list = NULL; + +static int try_insmod(char *mod, char *opts) +{ + char *cmd = malloc(strlen(mod) + strlen(modpath) + + (opts ? strlen(opts) : 0) + 30); + int ret; + + strcpy(cmd, "insmod "); + if (strchr(mod, '/') != NULL) + sprintf(cmd+7, "%s/%s.o", modpath, mod); + else + sprintf(cmd+7, "%s/pcmcia/%s.o", modpath, mod); + if (access(cmd+7, R_OK) != 0) { + syslog(LOG_INFO, "module %s not available", cmd+7); + free(cmd); + return -1; + } + if (opts) { + strcat(cmd, " "); + strcat(cmd, opts); + } + ret = execute("insmod", cmd); + free(cmd); + return ret; +} + +static int try_modprobe(char *mod, char *opts) +{ + char *cmd = malloc(strlen(mod) + (opts ? strlen(opts) : 0) + 20); + char *s = strrchr(mod, '/'); + int ret; + + sprintf(cmd, "modprobe %s", (s) ? s+1 : mod); + if (opts) { + strcat(cmd, " "); + strcat(cmd, opts); + } + ret = execute("modprobe", cmd); + free(cmd); + return ret; +} + +static void install_module(char *mod, char *opts) +{ + module_list_t *ml; + + for (ml = module_list; ml != NULL; ml = ml->next) + if (strcmp(mod, ml->mod) == 0) break; + if (ml == NULL) { + ml = (module_list_t *)malloc(sizeof(struct module_list_t)); + ml->mod = mod; + ml->usage = 0; + ml->next = module_list; + module_list = ml; + } + ml->usage++; + if (ml->usage != 1) + return; + + if (access("/proc/bus/pccard/drivers", R_OK) == 0) { + FILE *f = fopen("/proc/bus/pccard/drivers", "r"); + if (f) { + char a[61], s[33]; + while (fgets(a, 60, f)) { + int is_kernel; + sscanf(a, "%s %d", s, &is_kernel); + if (strcmp(s, mod) != 0) continue; + /* If it isn't a module, we won't try to rmmod */ + ml->usage += is_kernel; + fclose(f); + return; + } + fclose(f); + } + } + + if (do_modprobe) { + if (try_modprobe(mod, opts) != 0) + try_insmod(mod, opts); + } else { + if (try_insmod(mod, opts) != 0) + try_modprobe(mod, opts); + } +} + +static void remove_module(char *mod) +{ + char *s, cmd[128]; + module_list_t *ml; + + for (ml = module_list; ml != NULL; ml = ml->next) + if (strcmp(mod, ml->mod) == 0) break; + if (ml != NULL) { + ml->usage--; + if (ml->usage == 0) { + /* Strip off leading path names */ + s = strrchr(mod, '/'); + s = (s) ? s+1 : mod; + sprintf(cmd, do_modprobe ? "modprobe -r %s" : "rmmod %s", s); + execute(do_modprobe ? "modprobe" : "rmmod", cmd); + } + } +} + +/*====================================================================*/ + +static mtd_ident_t *lookup_mtd(region_info_t *region) +{ + mtd_ident_t *mtd; + int match = 0; + + for (mtd = root_mtd; mtd; mtd = mtd->next) { + switch (mtd->mtd_type) { + case JEDEC_MTD: + if ((mtd->jedec_mfr == region->JedecMfr) && + (mtd->jedec_info == region->JedecInfo)) { + match = 1; + break; + } + case DTYPE_MTD: + break; + default: + break; + } + if (match) break; + } + if (mtd) + return mtd; + else + return default_mtd; +} + +/*====================================================================*/ + +static void bind_mtd(int sn) +{ + socket_info_t *s = &socket[sn]; + region_info_t region; + bind_info_t bind; + mtd_info_t mtd_info; + mtd_ident_t *mtd; + int i, attr, ret, nr; + + nr = 0; + for (attr = 0; attr < 2; attr++) { + region.Attributes = attr; + ret = ioctl(s->fd, DS_GET_FIRST_REGION, ®ion); + while (ret == 0) { + mtd = lookup_mtd(®ion); + if (mtd) { + /* Have we seen this MTD before? */ + for (i = 0; i < nr; i++) + if (s->mtd[i] == mtd) break; + if (i == nr) { + install_module(mtd->module, mtd->opts); + s->mtd[nr] = mtd; + mtd->refs++; + nr++; + } + syslog(LOG_INFO, " %s memory region at 0x%x: %s", + attr ? "Attribute" : "Common", region.CardOffset, + mtd->name); + /* Bind MTD to this region */ + strcpy(mtd_info.dev_info, s->mtd[i]->module); + mtd_info.Attributes = region.Attributes; + mtd_info.CardOffset = region.CardOffset; + if (ioctl(s->fd, DS_BIND_MTD, &mtd_info) != 0) { + syslog(LOG_INFO, + "bind MTD '%s' to region at 0x%x failed: %m", + (char *)mtd_info.dev_info, region.CardOffset); + } + } + ret = ioctl(s->fd, DS_GET_NEXT_REGION, ®ion); + } + } + s->mtd[nr] = NULL; + + /* Now bind each unique MTD as a normal client of this socket */ + for (i = 0; i < nr; i++) { + strcpy(bind.dev_info, s->mtd[i]->module); + bind.function = 0; + if (ioctl(s->fd, DS_BIND_REQUEST, &bind) != 0) + syslog(LOG_INFO, "bind MTD '%s' to socket %d failed: %m", + (char *)bind.dev_info, sn); + } +} + +/*====================================================================*/ + +static void update_cis(socket_info_t *s) +{ + cisdump_t cis; + FILE *f = fopen(s->card->cis_file, "r"); + if (f == NULL) + syslog(LOG_ERR, "could not open '%s': %m", s->card->cis_file); + else { + cis.Length = fread(cis.Data, 1, CISTPL_MAX_CIS_SIZE, f); + fclose(f); + if (ioctl(s->fd, DS_REPLACE_CIS, &cis) != 0) + syslog(LOG_ERR, "could not replace CIS: %m"); + } +} + +/*====================================================================*/ + +static void do_insert(int sn) +{ + socket_info_t *s = &socket[sn]; + card_info_t *card; + device_info_t **dev; + bind_info_t *bind, **tail; + int i, j, ret; + + /* Already identified? */ + if ((s->card != NULL) && (s->card != blank_card)) + return; + + if (verbose) syslog(LOG_INFO, "initializing socket %d", sn); + card = lookup_card(sn); + if (s->state & SOCKET_HOTPLUG) { + write_stab(); + return; + } + /* Make sure we've learned something new before continuing */ + if (card == s->card) + return; + s->card = card; + card->refs++; + if (card->cis_file) update_cis(s); + + dev = card->device; + + /* Set up MTD's */ + for (i = 0; i < card->bindings; i++) + if (dev[i]->needs_mtd) + break; + if (i < card->bindings) + bind_mtd(sn); + + /* Install kernel modules */ + for (i = 0; i < card->bindings; i++) { + dev[i]->refs++; + for (j = 0; j < dev[i]->modules; j++) + install_module(dev[i]->module[j], dev[i]->opts[j]); + } + + /* Bind drivers by their dev_info identifiers */ + for (i = 0; i < card->bindings; i++) { + bind = calloc(1, sizeof(bind_info_t)); + strcpy((char *)bind->dev_info, (char *)dev[i]->dev_info); + if (strcmp(bind->dev_info, "cb_enabler") == 0) + bind->function = BIND_FN_ALL; + else + bind->function = card->dev_fn[i]; + if (ioctl(s->fd, DS_BIND_REQUEST, bind) != 0) { + if (errno == EBUSY) { + syslog(LOG_INFO, "'%s' already bound to socket %d", + (char *)bind->dev_info, sn); + } else { + syslog(LOG_INFO, "bind '%s' to socket %d failed: %m", + (char *)bind->dev_info, sn); + beep(BEEP_TIME, BEEP_ERR); + write_stab(); + return; + } + } + + for (ret = j = 0; j < 10; j++) { + ret = ioctl(s->fd, DS_GET_DEVICE_INFO, bind); + if ((ret == 0) || (errno != EAGAIN)) + break; + usleep(100000); + } + if (ret != 0) { + syslog(LOG_INFO, "get dev info on socket %d failed: %m", + sn); + if ((errno == EAGAIN) && + (strcmp(dev[i]->module[dev[i]->modules-1], + (char *)bind->dev_info) != 0)) + syslog(LOG_INFO, "wrong module '%s' for device '%s'?", + dev[i]->module[dev[i]->modules-1], + (char *)bind->dev_info); + ioctl(s->fd, DS_UNBIND_REQUEST, bind); + beep(BEEP_TIME, BEEP_ERR); + write_stab(); + return; + } + tail = &s->bind[i]; + while (ret == 0) { + bind_info_t *old; + if ((strlen(bind->name) > 3) && (bind->name[2] == '#')) + xlate_scsi_name(bind); + old = *tail = bind; tail = (bind_info_t **)&bind->next; + bind = (bind_info_t *)malloc(sizeof(bind_info_t)); + memcpy(bind, old, sizeof(bind_info_t)); + ret = ioctl(s->fd, DS_GET_NEXT_DEVICE, bind); + } + *tail = NULL; free(bind); + write_stab(); + } + + /* Run "start" commands */ + for (i = ret = 0; i < card->bindings; i++) { + char *class = EITHER_OR(card->class[i], dev[i]->class); + if (class) + ret |= execute_on_all("start", class, sn, i); + } + beep(BEEP_TIME, (ret) ? BEEP_ERR : BEEP_OK); + +} + +/*====================================================================*/ + +static int do_check(int sn) +{ + socket_info_t *s = &socket[sn]; + card_info_t *card; + device_info_t **dev; + int i; + + card = s->card; + if (card == NULL) + return 0; + + /* Run "check" commands */ + dev = card->device; + for (i = 0; i < card->bindings; i++) { + char *class = EITHER_OR(card->class[i], dev[i]->class); + if (class && execute_on_all("check", class, sn, i)) + return CS_IN_USE; + } + return 0; +} + +/*====================================================================*/ + +static void do_remove(int sn) +{ + socket_info_t *s = &socket[sn]; + card_info_t *card; + device_info_t **dev; + bind_info_t *bind; + int i, j; + + if (verbose) syslog(LOG_INFO, "shutting down socket %d", sn); + + card = s->card; + if (card == NULL) + goto done; + + /* Run "stop" commands */ + dev = card->device; + for (i = 0; i < card->bindings; i++) { + char *class = EITHER_OR(card->class[i], dev[i]->class); + if (class) + execute_on_all("stop", class, sn, i); + } + + /* unbind driver instances */ + for (i = 0; i < card->bindings; i++) { + if (s->bind[i]) { + if (ioctl(s->fd, DS_UNBIND_REQUEST, s->bind[i]) != 0) + syslog(LOG_INFO, "unbind '%s' from socket %d failed: %m", + (char *)s->bind[i]->dev_info, sn); + while (s->bind[i]) { + bind = s->bind[i]; + s->bind[i] = bind->next; + free(bind); + } + } + } + for (i = 0; (s->mtd[i] != NULL); i++) { + bind_info_t b; + strcpy(b.dev_info, s->mtd[i]->module); + b.function = 0; + if (ioctl(s->fd, DS_UNBIND_REQUEST, &b) != 0) + syslog(LOG_INFO, "unbind MTD '%s' from socket %d failed: %m", + s->mtd[i]->module, sn); + } + + /* remove kernel modules in inverse order */ + for (i = 0; i < card->bindings; i++) { + for (j = dev[i]->modules-1; j >= 0; j--) + remove_module(dev[i]->module[j]); + free_device(dev[i]); + } + /* Remove any MTD's bound to this socket */ + for (i = 0; (s->mtd[i] != NULL); i++) { + remove_module(s->mtd[i]->module); + free_mtd(s->mtd[i]); + s->mtd[i] = NULL; + } + +done: + beep(BEEP_TIME, BEEP_OK); + free_card(card); + s->card = NULL; + write_stab(); +} + +/*====================================================================*/ + +static void do_suspend(int sn) +{ + socket_info_t *s = &socket[sn]; + card_info_t *card; + device_info_t **dev; + int i; + + card = s->card; + if (card == NULL) + return; + dev = card->device; + for (i = 0; i < card->bindings; i++) { + char *class = EITHER_OR(card->class[i], dev[i]->class); + if (class && execute_on_all("suspend", class, sn, i)) + beep(BEEP_TIME, BEEP_ERR); + } +} + +/*====================================================================*/ + +static void do_resume(int sn) +{ + socket_info_t *s = &socket[sn]; + card_info_t *card; + device_info_t **dev; + int i; + + card = s->card; + if (card == NULL) + return; + dev = card->device; + for (i = 0; i < card->bindings; i++) { + char *class = EITHER_OR(card->class[i], dev[i]->class); + if (class && execute_on_all("resume", class, sn, i)) + beep(BEEP_TIME, BEEP_ERR); + } +} + +/*====================================================================*/ + +static void wait_for_pending(void) +{ + cs_status_t status; + int i; + status.Function = 0; + for (;;) { + usleep(100000); + for (i = 0; i < sockets; i++) + if ((ioctl(socket[i].fd, DS_GET_STATUS, &status) == 0) && + (status.CardState & CS_EVENT_CARD_INSERTION)) + break; + if (i == sockets) break; + } +} + +/*====================================================================*/ + +static void free_resources(void) +{ + adjust_list_t *al; + int fd = socket[0].fd; + + for (al = root_adjust; al; al = al->next) { + if (al->adj.Action == ADD_MANAGED_RESOURCE) { + al->adj.Action = REMOVE_MANAGED_RESOURCE; + ioctl(fd, DS_ADJUST_RESOURCE_INFO, &al->adj); + } else if ((al->adj.Action == REMOVE_MANAGED_RESOURCE) && + (al->adj.Resource == RES_IRQ)) { + al->adj.Action = ADD_MANAGED_RESOURCE; + ioctl(fd, DS_ADJUST_RESOURCE_INFO, &al->adj); + } + } + +} + +/*====================================================================*/ + +static void adjust_resources(void) +{ + adjust_list_t *al; + int ret; + char tmp[64]; + int fd = socket[0].fd; + + for (al = root_adjust; al; al = al->next) { + ret = ioctl(fd, DS_ADJUST_RESOURCE_INFO, &al->adj); + if (ret != 0) { + switch (al->adj.Resource) { + case RES_MEMORY_RANGE: + sprintf(tmp, "memory %#lx-%#lx", + al->adj.resource.memory.Base, + al->adj.resource.memory.Base + + al->adj.resource.memory.Size - 1); + break; + case RES_IO_RANGE: + sprintf(tmp, "IO ports %#x-%#x", + al->adj.resource.io.BasePort, + al->adj.resource.io.BasePort + + al->adj.resource.io.NumPorts - 1); + break; + case RES_IRQ: + sprintf(tmp, "irq %u", al->adj.resource.irq.IRQ); + break; + } + syslog(LOG_INFO, "could not adjust resource: %s: %m", tmp); + } + } +} + +/*====================================================================*/ + +static void fork_now(void) +{ + int ret; + if ((ret = fork()) > 0) + _exit(0); + if (ret == -1) + syslog(LOG_ERR, "forking: %m"); + if (setsid() < 0) + syslog(LOG_ERR, "detaching from tty: %m"); +} + +static void done(void) +{ + syslog(LOG_INFO, "exiting"); + unlink(pidfile); + unlink(stabfile); +} + +/*====================================================================*/ + +/* most recent signal */ +static int caught_signal = 0; + +static void catch_signal(int sig) +{ + caught_signal = sig; + if (signal(sig, catch_signal) == SIG_ERR) + syslog(LOG_INFO, "signal(%d): %m", sig); +} + +static void handle_signal(void) +{ + int i; + switch (caught_signal) { + case SIGTERM: + case SIGINT: + for (i = 0; i < sockets; i++) + if ((socket[i].state & SOCKET_PRESENT) && + (do_check(i) == 0)) do_remove(i); + free_resources(); + exit(0); + break; + case SIGHUP: + free_resources(); + free_config(); + syslog(LOG_INFO, "re-loading config file"); + load_config(); + adjust_resources(); + break; +#ifdef SIGPWR + case SIGPWR: + break; +#endif + } +} + +/*====================================================================*/ + +static int init_sockets(void) +{ + int fd, i; + + major = lookup_dev("pcmcia"); + if (major < 0) { + if (major == -ENODEV) + syslog(LOG_ERR, "no pcmcia driver in /proc/devices"); + else + syslog(LOG_ERR, "could not open /proc/devices: %m"); + exit(EXIT_FAILURE); + } + for (fd = -1, i = 0; i < MAX_SOCKS; i++) { + fd = open_sock(i, S_IFCHR|S_IREAD|S_IWRITE); + if (fd < 0) break; + socket[i].fd = fd; + socket[i].state = 0; + } + if ((fd < 0) && (errno != ENODEV) && (errno != ENOENT)) + syslog(LOG_ERR, "open_sock(socket %d) failed: %m", i); + sockets = i; + if (sockets == 0) { + if (errno == ENODEV) + syslog(LOG_ERR, "no sockets found!"); + else if (errno == EBUSY) + syslog(LOG_ERR, "another cardmgr is already running?"); + return -1; + } else + syslog(LOG_INFO, "watching %d sockets", sockets); + + adjust_resources(); + return 0; +} + +/*====================================================================*/ + +int cardmgr_call(void) +{ + int i, max_fd, ret, event, pass; + int delay_fork = 0; + struct timeval tv; + fd_set fds; + + if (access("/var/lib/pcmcia", R_OK) == 0) { + stabfile = "/var/lib/pcmcia/stab"; + } else { + stabfile = "/var/run/stab"; + } + do_modprobe = (access("/sbin/modprobe", X_OK) == 0); + + //openlog("cardmgr", LOG_PID|LOG_PERROR, LOG_DAEMON); + +/* + putenv("PATH=/bin:/sbin:/usr/bin:/usr/sbin"); + if (verbose) + putenv("VERBOSE=1"); + if (one_pass) + putenv("ONEPASS=1"); +*/ + if (modpath == NULL) { + if (access("/lib/modules/preferred", X_OK) == 0) + modpath = "/lib/modules/preferred"; + else { + struct utsname utsname; + if (uname(&utsname) != 0) { + log_message("CM: uname(): %m"); + exit(EXIT_FAILURE); + } + modpath = (char *)malloc(strlen(utsname.release)+14); + sprintf(modpath, "/lib/modules/%s", utsname.release); + } + } + if (access(modpath, X_OK) != 0) + syslog(LOG_INFO, "cannot access %s: %m", modpath); + /* We default to using modprobe if it is available */ + do_modprobe |= (access("/sbin/modprobe", X_OK) == 0); + + load_config(); + + if (init_sockets() != 0) + exit(EXIT_FAILURE); + + closelog(); + close(0); close(1); close(2); + if (!delay_fork && !one_pass) + fork_now(); + log_message("CM: cardmgr/hacked starting, version is " CS_RELEASE); + + /* If we've gotten this far, then clean up pid and stab at exit */ + atexit(&done); + write_pid(); + write_stab(); + + for (i = max_fd = 0; i < sockets; i++) + max_fd = (socket[i].fd > max_fd) ? socket[i].fd : max_fd; + + /* First select() call: poll, don't wait */ + tv.tv_sec = tv.tv_usec = 0; + + /* Wait for sockets in setup-pending state to settle */ + if (one_pass || delay_fork) + wait_for_pending(); + + for (pass = 0; ; pass++) { + FD_ZERO(&fds); + for (i = 0; i < sockets; i++) + FD_SET(socket[i].fd, &fds); + + while ((ret = select(max_fd+1, &fds, NULL, NULL, + ((pass == 0) ? &tv : NULL))) < 0) { + if (errno == EINTR) { + handle_signal(); + } else { + log_message("CM: select(): %m"); + exit(EXIT_FAILURE); + } + } + + for (i = 0; i < sockets; i++) { + if (!FD_ISSET(socket[i].fd, &fds)) + continue; + ret = read(socket[i].fd, &event, 4); + if ((ret == -1) && (errno != EAGAIN)) + log_message("CM: read(%d): %m\n", i); + if (ret != 4) + continue; + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + socket[i].state = 0; + do_remove(i); + break; + case CS_EVENT_EJECTION_REQUEST: + ret = do_check(i); + if (ret == 0) { + socket[i].state = 0; + do_remove(i); + } + write(socket[i].fd, &ret, 4); + break; + case CS_EVENT_CARD_INSERTION: + case CS_EVENT_INSERTION_REQUEST: + socket[i].state |= SOCKET_PRESENT; + case CS_EVENT_CARD_RESET: + socket[i].state |= SOCKET_READY; + do_insert(i); + break; + case CS_EVENT_RESET_PHYSICAL: + socket[i].state &= ~SOCKET_READY; + break; + case CS_EVENT_PM_SUSPEND: + do_suspend(i); + break; + case CS_EVENT_PM_RESUME: + do_resume(i); + break; + } + + } + + if (one_pass) + exit(EXIT_SUCCESS); + if (delay_fork) { + fork_now(); + write_pid(); + delay_fork = 0; + } + + } /* repeat */ + return 0; +} diff --git a/pcmcia/cardmgr.h b/pcmcia/cardmgr.h new file mode 100644 index 0000000..d519068 --- /dev/null +++ b/pcmcia/cardmgr.h @@ -0,0 +1,113 @@ +/* + * cardmgr.h 1.38 2002/08/19 03:21:20 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#define MAX_SOCKS 8 +#define MAX_BINDINGS 4 +#define MAX_MODULES 4 + +typedef struct adjust_list_t { + adjust_t adj; + struct adjust_list_t *next; +} adjust_list_t; + +typedef struct func_ident_t { + u_char funcid; +} func_ident_t; + +typedef struct manfid_ident_t { + u_short manf; + u_short card; +} manfid_ident_t; + +typedef struct vers_ident_t { + int ns; + char *pi[4]; +} vers_ident_t; + +typedef struct tuple_ident_t { + cisdata_t code; + long ofs; + char *info; +} tuple_ident_t; + +typedef struct device_info_t { + dev_info_t dev_info; + int needs_mtd; + int modules; + char *module[MAX_MODULES]; + char *opts[MAX_MODULES]; + char *class; + int refs; + struct device_info_t *next; +} device_info_t; + +#define VERS_1_IDENT 0x0001 +#define MANFID_IDENT 0x0002 +#define TUPLE_IDENT 0x0010 +#define FUNC_IDENT 0x0020 +#define BLANK_IDENT 0x0040 +#define PCI_IDENT 0x0080 +#define EXCL_IDENT 0x00f0 + +typedef struct card_info_t { + char *name; + int ident_type; + union { + vers_ident_t vers; + tuple_ident_t tuple; + func_ident_t func; + } id; + manfid_ident_t manfid; + int bindings; + device_info_t *device[MAX_BINDINGS]; + int dev_fn[MAX_BINDINGS]; + char *class[MAX_BINDINGS]; + char *cis_file; + int refs; + struct card_info_t *next; +} card_info_t; + +typedef struct mtd_ident_t { + char *name; + enum { + JEDEC_MTD=1, DTYPE_MTD, DEFAULT_MTD + } mtd_type; + int dtype, jedec_mfr, jedec_info; + char *module, *opts; + int refs; + struct mtd_ident_t *next; +} mtd_ident_t; + +extern adjust_list_t *root_adjust; +extern device_info_t *root_device; +extern card_info_t *blank_card; +extern card_info_t *root_card, *root_func; +extern mtd_ident_t *root_mtd, *default_mtd; + +int parse_configfile(char *fn); diff --git a/pcmcia/cirrus.h b/pcmcia/cirrus.h new file mode 100644 index 0000000..49d7fa2 --- /dev/null +++ b/pcmcia/cirrus.h @@ -0,0 +1,182 @@ +/* + * cirrus.h 1.10 2001/08/24 12:15:33 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_CIRRUS_H +#define _LINUX_CIRRUS_H + +#ifndef PCI_VENDOR_ID_CIRRUS +#define PCI_VENDOR_ID_CIRRUS 0x1013 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_6729 +#define PCI_DEVICE_ID_CIRRUS_6729 0x1100 +#endif +#ifndef PCI_DEVICE_ID_CIRRUS_6832 +#define PCI_DEVICE_ID_CIRRUS_6832 0x1110 +#endif + +#define PD67_MISC_CTL_1 0x16 /* Misc control 1 */ +#define PD67_FIFO_CTL 0x17 /* FIFO control */ +#define PD67_MISC_CTL_2 0x1E /* Misc control 2 */ +#define PD67_CHIP_INFO 0x1f /* Chip information */ +#define PD67_ATA_CTL 0x026 /* 6730: ATA control */ +#define PD67_EXT_INDEX 0x2e /* Extension index */ +#define PD67_EXT_DATA 0x2f /* Extension data */ + +#define pd67_ext_get(s, r) \ + (i365_set(s, PD67_EXT_INDEX, r), i365_get(s, PD67_EXT_DATA)) +#define pd67_ext_set(s, r, v) \ + (i365_set(s, PD67_EXT_INDEX, r), i365_set(s, PD67_EXT_DATA, v)) + +/* PD6722 extension registers -- indexed in PD67_EXT_INDEX */ +#define PD67_DATA_MASK0 0x01 /* Data mask 0 */ +#define PD67_DATA_MASK1 0x02 /* Data mask 1 */ +#define PD67_DMA_CTL 0x03 /* DMA control */ + +/* PD6730 extension registers -- indexed in PD67_EXT_INDEX */ +#define PD67_EXT_CTL_1 0x03 /* Extension control 1 */ +#define PD67_MEM_PAGE(n) ((n)+5) /* PCI window bits 31:24 */ +#define PD67_EXTERN_DATA 0x0a +#define PD67_MISC_CTL_3 0x25 +#define PD67_SMB_PWR_CTL 0x26 + +/* I/O window address offset */ +#define PD67_IO_OFF(w) (0x36+((w)<<1)) + +/* Timing register sets */ +#define PD67_TIME_SETUP(n) (0x3a + 3*(n)) +#define PD67_TIME_CMD(n) (0x3b + 3*(n)) +#define PD67_TIME_RECOV(n) (0x3c + 3*(n)) + +/* Flags for PD67_MISC_CTL_1 */ +#define PD67_MC1_5V_DET 0x01 /* 5v detect */ +#define PD67_MC1_MEDIA_ENA 0x01 /* 6730: Multimedia enable */ +#define PD67_MC1_VCC_3V 0x02 /* 3.3v Vcc */ +#define PD67_MC1_PULSE_MGMT 0x04 +#define PD67_MC1_PULSE_IRQ 0x08 +#define PD67_MC1_SPKR_ENA 0x10 +#define PD67_MC1_INPACK_ENA 0x80 + +/* Flags for PD67_FIFO_CTL */ +#define PD67_FIFO_EMPTY 0x80 + +/* Flags for PD67_MISC_CTL_2 */ +#define PD67_MC2_FREQ_BYPASS 0x01 +#define PD67_MC2_DYNAMIC_MODE 0x02 +#define PD67_MC2_SUSPEND 0x04 +#define PD67_MC2_5V_CORE 0x08 +#define PD67_MC2_LED_ENA 0x10 /* IRQ 12 is LED enable */ +#define PD67_MC2_FAST_PCI 0x10 /* 6729: PCI bus > 25 MHz */ +#define PD67_MC2_3STATE_BIT7 0x20 /* Floppy change bit */ +#define PD67_MC2_DMA_MODE 0x40 +#define PD67_MC2_IRQ15_RI 0x80 /* IRQ 15 is ring enable */ + +/* Flags for PD67_CHIP_INFO */ +#define PD67_INFO_SLOTS 0x20 /* 0 = 1 slot, 1 = 2 slots */ +#define PD67_INFO_CHIP_ID 0xc0 +#define PD67_INFO_REV 0x1c + +/* Fields in PD67_TIME_* registers */ +#define PD67_TIME_SCALE 0xc0 +#define PD67_TIME_SCALE_1 0x00 +#define PD67_TIME_SCALE_16 0x40 +#define PD67_TIME_SCALE_256 0x80 +#define PD67_TIME_SCALE_4096 0xc0 +#define PD67_TIME_MULT 0x3f + +/* Fields in PD67_DMA_CTL */ +#define PD67_DMA_MODE 0xc0 +#define PD67_DMA_OFF 0x00 +#define PD67_DMA_DREQ_INPACK 0x40 +#define PD67_DMA_DREQ_WP 0x80 +#define PD67_DMA_DREQ_BVD2 0xc0 +#define PD67_DMA_PULLUP 0x20 /* Disable socket pullups? */ + +/* Fields in PD67_EXT_CTL_1 */ +#define PD67_EC1_VCC_PWR_LOCK 0x01 +#define PD67_EC1_AUTO_PWR_CLEAR 0x02 +#define PD67_EC1_LED_ENA 0x04 +#define PD67_EC1_INV_CARD_IRQ 0x08 +#define PD67_EC1_INV_MGMT_IRQ 0x10 +#define PD67_EC1_PULLUP_CTL 0x20 + +/* Fields in PD67_EXTERN_DATA */ +#define PD67_EXD_VS1(s) (0x01 << ((s)<<1)) +#define PD67_EXD_VS2(s) (0x02 << ((s)<<1)) + +/* Fields in PD67_MISC_CTL_3 */ +#define PD67_MC3_IRQ_MASK 0x03 +#define PD67_MC3_IRQ_PCPCI 0x00 +#define PD67_MC3_IRQ_EXTERN 0x01 +#define PD67_MC3_IRQ_PCIWAY 0x02 +#define PD67_MC3_IRQ_PCI 0x03 +#define PD67_MC3_PWR_MASK 0x0c +#define PD67_MC3_PWR_SERIAL 0x00 +#define PD67_MC3_PWR_TI2202 0x08 +#define PD67_MC3_PWR_SMB 0x0c + +/* Register definitions for Cirrus PD6832 PCI-to-CardBus bridge */ + +/* PD6832 extension registers -- indexed in PD67_EXT_INDEX */ +#define PD68_EXT_CTL_2 0x0b +#define PD68_PCI_SPACE 0x22 +#define PD68_PCCARD_SPACE 0x23 +#define PD68_WINDOW_TYPE 0x24 +#define PD68_EXT_CSC 0x2e +#define PD68_MISC_CTL_4 0x2f +#define PD68_MISC_CTL_5 0x30 +#define PD68_MISC_CTL_6 0x31 + +/* Extra flags in PD67_MISC_CTL_3 */ +#define PD68_MC3_HW_SUSP 0x10 +#define PD68_MC3_MM_EXPAND 0x40 +#define PD68_MC3_MM_ARM 0x80 + +/* Bridge Control Register */ +#define PD6832_BCR_MGMT_IRQ_ENA 0x0800 + +/* Socket Number Register */ +#define PD6832_SOCKET_NUMBER 0x004c /* 8 bit */ + +/* Data structure for tracking vendor-specific state */ +typedef struct cirrus_state_t { + u_char misc1; /* PD67_MISC_CTL_1 */ + u_char misc2; /* PD67_MISC_CTL_2 */ + u_char ectl1; /* PD67_EXT_CTL_1 */ + u_char timer[6]; /* PD67_TIME_* */ +} cirrus_state_t; + +#define CIRRUS_PCIC_ID \ + IS_PD6729, IS_PD6730, IS_PD6832 + +#define CIRRUS_PCIC_INFO \ + { "Cirrus PD6729", IS_CIRRUS|IS_PCI, ID(CIRRUS, 6729) }, \ + { "Cirrus PD6730", IS_CIRRUS|IS_PCI, PCI_VENDOR_ID_CIRRUS, -1 }, \ + { "Cirrus PD6832", IS_CIRRUS|IS_CARDBUS, ID(CIRRUS, 6832) } + +#endif /* _LINUX_CIRRUS_H */ diff --git a/pcmcia/ciscode.h b/pcmcia/ciscode.h new file mode 100644 index 0000000..e6bacef --- /dev/null +++ b/pcmcia/ciscode.h @@ -0,0 +1,138 @@ +/* + * ciscode.h 1.57 2002/11/03 20:38:14 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_CISCODE_H +#define _LINUX_CISCODE_H + +/* Manufacturer and Product ID codes */ + +#define MANFID_3COM 0x0101 +#define PRODID_3COM_3CXEM556 0x0035 +#define PRODID_3COM_3CCFEM556 0x0556 +#define PRODID_3COM_3C562 0x0562 + +#define MANFID_ACCTON 0x01bf +#define PRODID_ACCTON_EN2226 0x010a + +#define MANFID_ADAPTEC 0x012f +#define PRODID_ADAPTEC_SCSI 0x0001 + +#define MANFID_ATT 0xffff +#define PRODID_ATT_KIT 0x0100 + +#define MANFID_CONTEC 0xc001 + +#define MANFID_FUJITSU 0x0004 +#define PRODID_FUJITSU_MBH10302 0x0004 +#define PRODID_FUJITSU_MBH10304 0x1003 +#define PRODID_FUJITSU_LA501 0x2000 + +#define MANFID_IBM 0x00a4 +#define PRODID_IBM_HOME_AND_AWAY 0x002e + +#define MANFID_INTEL 0x0089 +#define PRODID_INTEL_DUAL_RS232 0x0301 +#define PRODID_INTEL_2PLUS 0x8422 + +#define MANFID_KME 0x0032 +#define PRODID_KME_KXLC005_A 0x0704 +#define PRODID_KME_KXLC005_B 0x2904 + +#define MANFID_LINKSYS 0x0143 +#define PRODID_LINKSYS_PCMLM28 0xc0ab +#define PRODID_LINKSYS_3400 0x3341 + +#define MANFID_MEGAHERTZ 0x0102 +#define PRODID_MEGAHERTZ_VARIOUS 0x0000 +#define PRODID_MEGAHERTZ_EM3288 0x0006 + +#define MANFID_MACNICA 0xc00b + +#define MANFID_MOTOROLA 0x0109 +#define PRODID_MOTOROLA_MARINER 0x0501 + +#define MANFID_NATINST 0x010b +#define PRODID_NATINST_QUAD_RS232 0xd180 + +#define MANFID_NEW_MEDIA 0x0057 + +#define MANFID_NOKIA 0x0124 +#define PRODID_NOKIA_CARDPHONE 0x0900 + +#define MANFID_OLICOM 0x0121 +#define PRODID_OLICOM_OC2231 0x3122 +#define PRODID_OLICOM_OC2232 0x3222 + +#define MANFID_OMEGA 0x0137 +#define PRODID_OMEGA_QSP_100 0x0025 + +#define MANFID_OSITECH 0x0140 +#define PRODID_OSITECH_JACK_144 0x0001 +#define PRODID_OSITECH_JACK_288 0x0002 +#define PRODID_OSITECH_JACK_336 0x0007 +#define PRODID_OSITECH_SEVEN 0x0008 + +#define MANFID_OXSEMI 0x0279 + +#define MANFID_PIONEER 0x000b + +#define MANFID_PSION 0x016c +#define PRODID_PSION_NET100 0x0023 + +#define MANFID_QUATECH 0x0137 +#define PRODID_QUATECH_SPP100 0x0003 +#define PRODID_QUATECH_DUAL_RS232 0x0012 +#define PRODID_QUATECH_DUAL_RS232_D1 0x0007 +#define PRODID_QUATECH_DUAL_RS232_D2 0x0052 +#define PRODID_QUATECH_QUAD_RS232 0x001b +#define PRODID_QUATECH_DUAL_RS422 0x000e +#define PRODID_QUATECH_QUAD_RS422 0x0045 + +#define MANFID_SMC 0x0108 +#define PRODID_SMC_ETHER 0x0105 + +#define MANFID_SOCKET 0x0104 +#define PRODID_SOCKET_DUAL_RS232 0x0006 +#define PRODID_SOCKET_EIO 0x000a +#define PRODID_SOCKET_LPE 0x000d +#define PRODID_SOCKET_LPE_CF 0x0075 + +#define MANFID_SUNDISK 0x0045 + +#define MANFID_TDK 0x0105 +#define PRODID_TDK_CF010 0x0900 +#define PRODID_TDK_GN3410 0x4815 + +#define MANFID_TOSHIBA 0x0098 + +#define MANFID_UNGERMANN 0x02c0 + +#define MANFID_XIRCOM 0x0105 + +#endif /* _LINUX_CISCODE_H */ diff --git a/pcmcia/cisreg.h b/pcmcia/cisreg.h new file mode 100644 index 0000000..cb9fe39 --- /dev/null +++ b/pcmcia/cisreg.h @@ -0,0 +1,135 @@ +/* + * cisreg.h 1.18 2001/08/24 12:16:12 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_CISREG_H +#define _LINUX_CISREG_H + +/* + * Offsets from ConfigBase for CIS registers + */ +#define CISREG_COR 0x00 +#define CISREG_CCSR 0x02 +#define CISREG_PRR 0x04 +#define CISREG_SCR 0x06 +#define CISREG_ESR 0x08 +#define CISREG_IOBASE_0 0x0a +#define CISREG_IOBASE_1 0x0c +#define CISREG_IOBASE_2 0x0e +#define CISREG_IOBASE_3 0x10 +#define CISREG_IOSIZE 0x12 + +/* + * Configuration Option Register + */ +#define COR_CONFIG_MASK 0x3f +#define COR_MFC_CONFIG_MASK 0x38 +#define COR_FUNC_ENA 0x01 +#define COR_ADDR_DECODE 0x02 +#define COR_IREQ_ENA 0x04 +#define COR_LEVEL_REQ 0x40 +#define COR_SOFT_RESET 0x80 + +/* + * Card Configuration and Status Register + */ +#define CCSR_INTR_ACK 0x01 +#define CCSR_INTR_PENDING 0x02 +#define CCSR_POWER_DOWN 0x04 +#define CCSR_AUDIO_ENA 0x08 +#define CCSR_IOIS8 0x20 +#define CCSR_SIGCHG_ENA 0x40 +#define CCSR_CHANGED 0x80 + +/* + * Pin Replacement Register + */ +#define PRR_WP_STATUS 0x01 +#define PRR_READY_STATUS 0x02 +#define PRR_BVD2_STATUS 0x04 +#define PRR_BVD1_STATUS 0x08 +#define PRR_WP_EVENT 0x10 +#define PRR_READY_EVENT 0x20 +#define PRR_BVD2_EVENT 0x40 +#define PRR_BVD1_EVENT 0x80 + +/* + * Socket and Copy Register + */ +#define SCR_SOCKET_NUM 0x0f +#define SCR_COPY_NUM 0x70 + +/* + * Extended Status Register + */ +#define ESR_REQ_ATTN_ENA 0x01 +#define ESR_REQ_ATTN 0x10 + +/* + * CardBus Function Status Registers + */ +#define CBFN_EVENT 0x00 +#define CBFN_MASK 0x04 +#define CBFN_STATE 0x08 +#define CBFN_FORCE 0x0c + +/* + * These apply to all the CardBus function registers + */ +#define CBFN_WP 0x0001 +#define CBFN_READY 0x0002 +#define CBFN_BVD2 0x0004 +#define CBFN_BVD1 0x0008 +#define CBFN_GWAKE 0x0010 +#define CBFN_INTR 0x8000 + +/* + * Extra bits in the Function Event Mask Register + */ +#define FEMR_BAM_ENA 0x0020 +#define FEMR_PWM_ENA 0x0040 +#define FEMR_WKUP_MASK 0x4000 + +/* + * Indirect Addressing Registers for Zoomed Video: these are addresses + * in common memory space + */ +#define CISREG_ICTRL0 0x02 /* control registers */ +#define CISREG_ICTRL1 0x03 +#define CISREG_IADDR0 0x04 /* address registers */ +#define CISREG_IADDR1 0x05 +#define CISREG_IADDR2 0x06 +#define CISREG_IADDR3 0x07 +#define CISREG_IDATA0 0x08 /* data registers */ +#define CISREG_IDATA1 0x09 + +#define ICTRL0_COMMON 0x01 +#define ICTRL0_AUTOINC 0x02 +#define ICTRL0_BYTEGRAN 0x04 + +#endif /* _LINUX_CISREG_H */ diff --git a/pcmcia/cistpl.h b/pcmcia/cistpl.h new file mode 100644 index 0000000..1d4cac2 --- /dev/null +++ b/pcmcia/cistpl.h @@ -0,0 +1,604 @@ +/* + * cistpl.h 1.35 2001/08/24 12:16:12 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_CISTPL_H +#define _LINUX_CISTPL_H + +#define CISTPL_NULL 0x00 +#define CISTPL_DEVICE 0x01 +#define CISTPL_LONGLINK_CB 0x02 +#define CISTPL_INDIRECT 0x03 +#define CISTPL_CONFIG_CB 0x04 +#define CISTPL_CFTABLE_ENTRY_CB 0x05 +#define CISTPL_LONGLINK_MFC 0x06 +#define CISTPL_BAR 0x07 +#define CISTPL_PWR_MGMNT 0x08 +#define CISTPL_EXTDEVICE 0x09 +#define CISTPL_CHECKSUM 0x10 +#define CISTPL_LONGLINK_A 0x11 +#define CISTPL_LONGLINK_C 0x12 +#define CISTPL_LINKTARGET 0x13 +#define CISTPL_NO_LINK 0x14 +#define CISTPL_VERS_1 0x15 +#define CISTPL_ALTSTR 0x16 +#define CISTPL_DEVICE_A 0x17 +#define CISTPL_JEDEC_C 0x18 +#define CISTPL_JEDEC_A 0x19 +#define CISTPL_CONFIG 0x1a +#define CISTPL_CFTABLE_ENTRY 0x1b +#define CISTPL_DEVICE_OC 0x1c +#define CISTPL_DEVICE_OA 0x1d +#define CISTPL_DEVICE_GEO 0x1e +#define CISTPL_DEVICE_GEO_A 0x1f +#define CISTPL_MANFID 0x20 +#define CISTPL_FUNCID 0x21 +#define CISTPL_FUNCE 0x22 +#define CISTPL_SWIL 0x23 +#define CISTPL_END 0xff +/* Layer 2 tuples */ +#define CISTPL_VERS_2 0x40 +#define CISTPL_FORMAT 0x41 +#define CISTPL_GEOMETRY 0x42 +#define CISTPL_BYTEORDER 0x43 +#define CISTPL_DATE 0x44 +#define CISTPL_BATTERY 0x45 +#define CISTPL_FORMAT_A 0x47 +/* Layer 3 tuples */ +#define CISTPL_ORG 0x46 +#define CISTPL_SPCL 0x90 + +typedef struct cistpl_longlink_t { + u_int addr; +} cistpl_longlink_t; + +typedef struct cistpl_checksum_t { + u_short addr; + u_short len; + u_char sum; +} cistpl_checksum_t; + +#define CISTPL_MAX_FUNCTIONS 8 +#define CISTPL_MFC_ATTR 0x00 +#define CISTPL_MFC_COMMON 0x01 + +typedef struct cistpl_longlink_mfc_t { + u_char nfn; + struct { + u_char space; + u_int addr; + } fn[CISTPL_MAX_FUNCTIONS]; +} cistpl_longlink_mfc_t; + +#define CISTPL_MAX_ALTSTR_STRINGS 4 + +typedef struct cistpl_altstr_t { + u_char ns; + u_char ofs[CISTPL_MAX_ALTSTR_STRINGS]; + char str[254]; +} cistpl_altstr_t; + +#define CISTPL_DTYPE_NULL 0x00 +#define CISTPL_DTYPE_ROM 0x01 +#define CISTPL_DTYPE_OTPROM 0x02 +#define CISTPL_DTYPE_EPROM 0x03 +#define CISTPL_DTYPE_EEPROM 0x04 +#define CISTPL_DTYPE_FLASH 0x05 +#define CISTPL_DTYPE_SRAM 0x06 +#define CISTPL_DTYPE_DRAM 0x07 +#define CISTPL_DTYPE_FUNCSPEC 0x0d +#define CISTPL_DTYPE_EXTEND 0x0e + +#define CISTPL_MAX_DEVICES 4 + +typedef struct cistpl_device_t { + u_char ndev; + struct { + u_char type; + u_char wp; + u_int speed; + u_int size; + } dev[CISTPL_MAX_DEVICES]; +} cistpl_device_t; + +#define CISTPL_DEVICE_MWAIT 0x01 +#define CISTPL_DEVICE_3VCC 0x02 + +typedef struct cistpl_device_o_t { + u_char flags; + cistpl_device_t device; +} cistpl_device_o_t; + +#define CISTPL_VERS_1_MAX_PROD_STRINGS 4 + +typedef struct cistpl_vers_1_t { + u_char major; + u_char minor; + u_char ns; + u_char ofs[CISTPL_VERS_1_MAX_PROD_STRINGS]; + char str[254]; +} cistpl_vers_1_t; + +typedef struct cistpl_jedec_t { + u_char nid; + struct { + u_char mfr; + u_char info; + } id[CISTPL_MAX_DEVICES]; +} cistpl_jedec_t; + +typedef struct cistpl_manfid_t { + u_short manf; + u_short card; +} cistpl_manfid_t; + +#define CISTPL_FUNCID_MULTI 0x00 +#define CISTPL_FUNCID_MEMORY 0x01 +#define CISTPL_FUNCID_SERIAL 0x02 +#define CISTPL_FUNCID_PARALLEL 0x03 +#define CISTPL_FUNCID_FIXED 0x04 +#define CISTPL_FUNCID_VIDEO 0x05 +#define CISTPL_FUNCID_NETWORK 0x06 +#define CISTPL_FUNCID_AIMS 0x07 +#define CISTPL_FUNCID_SCSI 0x08 + +#define CISTPL_SYSINIT_POST 0x01 +#define CISTPL_SYSINIT_ROM 0x02 + +typedef struct cistpl_funcid_t { + u_char func; + u_char sysinit; +} cistpl_funcid_t; + +typedef struct cistpl_funce_t { + u_char type; + u_char data[0]; +} cistpl_funce_t; + +/*====================================================================== + + Modem Function Extension Tuples + +======================================================================*/ + +#define CISTPL_FUNCE_SERIAL_IF 0x00 +#define CISTPL_FUNCE_SERIAL_CAP 0x01 +#define CISTPL_FUNCE_SERIAL_SERV_DATA 0x02 +#define CISTPL_FUNCE_SERIAL_SERV_FAX 0x03 +#define CISTPL_FUNCE_SERIAL_SERV_VOICE 0x04 +#define CISTPL_FUNCE_SERIAL_CAP_DATA 0x05 +#define CISTPL_FUNCE_SERIAL_CAP_FAX 0x06 +#define CISTPL_FUNCE_SERIAL_CAP_VOICE 0x07 +#define CISTPL_FUNCE_SERIAL_IF_DATA 0x08 +#define CISTPL_FUNCE_SERIAL_IF_FAX 0x09 +#define CISTPL_FUNCE_SERIAL_IF_VOICE 0x0a + +/* UART identification */ +#define CISTPL_SERIAL_UART_8250 0x00 +#define CISTPL_SERIAL_UART_16450 0x01 +#define CISTPL_SERIAL_UART_16550 0x02 +#define CISTPL_SERIAL_UART_8251 0x03 +#define CISTPL_SERIAL_UART_8530 0x04 +#define CISTPL_SERIAL_UART_85230 0x05 + +/* UART capabilities */ +#define CISTPL_SERIAL_UART_SPACE 0x01 +#define CISTPL_SERIAL_UART_MARK 0x02 +#define CISTPL_SERIAL_UART_ODD 0x04 +#define CISTPL_SERIAL_UART_EVEN 0x08 +#define CISTPL_SERIAL_UART_5BIT 0x01 +#define CISTPL_SERIAL_UART_6BIT 0x02 +#define CISTPL_SERIAL_UART_7BIT 0x04 +#define CISTPL_SERIAL_UART_8BIT 0x08 +#define CISTPL_SERIAL_UART_1STOP 0x10 +#define CISTPL_SERIAL_UART_MSTOP 0x20 +#define CISTPL_SERIAL_UART_2STOP 0x40 + +typedef struct cistpl_serial_t { + u_char uart_type; + u_char uart_cap_0; + u_char uart_cap_1; +} cistpl_serial_t; + +typedef struct cistpl_modem_cap_t { + u_char flow; + u_char cmd_buf; + u_char rcv_buf_0, rcv_buf_1, rcv_buf_2; + u_char xmit_buf_0, xmit_buf_1, xmit_buf_2; +} cistpl_modem_cap_t; + +#define CISTPL_SERIAL_MOD_103 0x01 +#define CISTPL_SERIAL_MOD_V21 0x02 +#define CISTPL_SERIAL_MOD_V23 0x04 +#define CISTPL_SERIAL_MOD_V22 0x08 +#define CISTPL_SERIAL_MOD_212A 0x10 +#define CISTPL_SERIAL_MOD_V22BIS 0x20 +#define CISTPL_SERIAL_MOD_V26 0x40 +#define CISTPL_SERIAL_MOD_V26BIS 0x80 +#define CISTPL_SERIAL_MOD_V27BIS 0x01 +#define CISTPL_SERIAL_MOD_V29 0x02 +#define CISTPL_SERIAL_MOD_V32 0x04 +#define CISTPL_SERIAL_MOD_V32BIS 0x08 +#define CISTPL_SERIAL_MOD_V34 0x10 + +#define CISTPL_SERIAL_ERR_MNP2_4 0x01 +#define CISTPL_SERIAL_ERR_V42_LAPM 0x02 + +#define CISTPL_SERIAL_CMPR_V42BIS 0x01 +#define CISTPL_SERIAL_CMPR_MNP5 0x02 + +#define CISTPL_SERIAL_CMD_AT1 0x01 +#define CISTPL_SERIAL_CMD_AT2 0x02 +#define CISTPL_SERIAL_CMD_AT3 0x04 +#define CISTPL_SERIAL_CMD_MNP_AT 0x08 +#define CISTPL_SERIAL_CMD_V25BIS 0x10 +#define CISTPL_SERIAL_CMD_V25A 0x20 +#define CISTPL_SERIAL_CMD_DMCL 0x40 + +typedef struct cistpl_data_serv_t { + u_char max_data_0; + u_char max_data_1; + u_char modulation_0; + u_char modulation_1; + u_char error_control; + u_char compression; + u_char cmd_protocol; + u_char escape; + u_char encrypt; + u_char misc_features; + u_char ccitt_code[0]; +} cistpl_data_serv_t; + +typedef struct cistpl_fax_serv_t { + u_char max_data_0; + u_char max_data_1; + u_char modulation; + u_char encrypt; + u_char features_0; + u_char features_1; + u_char ccitt_code[0]; +} cistpl_fax_serv_t; + +typedef struct cistpl_voice_serv_t { + u_char max_data_0; + u_char max_data_1; +} cistpl_voice_serv_t; + +/*====================================================================== + + LAN Function Extension Tuples + +======================================================================*/ + +#define CISTPL_FUNCE_LAN_TECH 0x01 +#define CISTPL_FUNCE_LAN_SPEED 0x02 +#define CISTPL_FUNCE_LAN_MEDIA 0x03 +#define CISTPL_FUNCE_LAN_NODE_ID 0x04 +#define CISTPL_FUNCE_LAN_CONNECTOR 0x05 + +/* LAN technologies */ +#define CISTPL_LAN_TECH_ARCNET 0x01 +#define CISTPL_LAN_TECH_ETHERNET 0x02 +#define CISTPL_LAN_TECH_TOKENRING 0x03 +#define CISTPL_LAN_TECH_LOCALTALK 0x04 +#define CISTPL_LAN_TECH_FDDI 0x05 +#define CISTPL_LAN_TECH_ATM 0x06 +#define CISTPL_LAN_TECH_WIRELESS 0x07 + +typedef struct cistpl_lan_tech_t { + u_char tech; +} cistpl_lan_tech_t; + +typedef struct cistpl_lan_speed_t { + u_int speed; +} cistpl_lan_speed_t; + +/* LAN media definitions */ +#define CISTPL_LAN_MEDIA_UTP 0x01 +#define CISTPL_LAN_MEDIA_STP 0x02 +#define CISTPL_LAN_MEDIA_THIN_COAX 0x03 +#define CISTPL_LAN_MEDIA_THICK_COAX 0x04 +#define CISTPL_LAN_MEDIA_FIBER 0x05 +#define CISTPL_LAN_MEDIA_900MHZ 0x06 +#define CISTPL_LAN_MEDIA_2GHZ 0x07 +#define CISTPL_LAN_MEDIA_5GHZ 0x08 +#define CISTPL_LAN_MEDIA_DIFF_IR 0x09 +#define CISTPL_LAN_MEDIA_PTP_IR 0x0a + +typedef struct cistpl_lan_media_t { + u_char media; +} cistpl_lan_media_t; + +typedef struct cistpl_lan_node_id_t { + u_char nb; + u_char id[16]; +} cistpl_lan_node_id_t; + +typedef struct cistpl_lan_connector_t { + u_char code; +} cistpl_lan_connector_t; + +/*====================================================================== + + IDE Function Extension Tuples + +======================================================================*/ + +#define CISTPL_IDE_INTERFACE 0x01 + +typedef struct cistpl_ide_interface_t { + u_char interface; +} cistpl_ide_interface_t; + +/* First feature byte */ +#define CISTPL_IDE_SILICON 0x04 +#define CISTPL_IDE_UNIQUE 0x08 +#define CISTPL_IDE_DUAL 0x10 + +/* Second feature byte */ +#define CISTPL_IDE_HAS_SLEEP 0x01 +#define CISTPL_IDE_HAS_STANDBY 0x02 +#define CISTPL_IDE_HAS_IDLE 0x04 +#define CISTPL_IDE_LOW_POWER 0x08 +#define CISTPL_IDE_REG_INHIBIT 0x10 +#define CISTPL_IDE_HAS_INDEX 0x20 +#define CISTPL_IDE_IOIS16 0x40 + +typedef struct cistpl_ide_feature_t { + u_char feature1; + u_char feature2; +} cistpl_ide_feature_t; + +#define CISTPL_FUNCE_IDE_IFACE 0x01 +#define CISTPL_FUNCE_IDE_MASTER 0x02 +#define CISTPL_FUNCE_IDE_SLAVE 0x03 + +/*====================================================================== + + Configuration Table Entries + +======================================================================*/ + +#define CISTPL_BAR_SPACE 0x07 +#define CISTPL_BAR_SPACE_IO 0x10 +#define CISTPL_BAR_PREFETCH 0x20 +#define CISTPL_BAR_CACHEABLE 0x40 +#define CISTPL_BAR_1MEG_MAP 0x80 + +typedef struct cistpl_bar_t { + u_char attr; + u_int size; +} cistpl_bar_t; + +typedef struct cistpl_config_t { + u_char last_idx; + u_int base; + u_int rmask[4]; + u_char subtuples; +} cistpl_config_t; + +/* These are bits in the 'present' field, and indices in 'param' */ +#define CISTPL_POWER_VNOM 0 +#define CISTPL_POWER_VMIN 1 +#define CISTPL_POWER_VMAX 2 +#define CISTPL_POWER_ISTATIC 3 +#define CISTPL_POWER_IAVG 4 +#define CISTPL_POWER_IPEAK 5 +#define CISTPL_POWER_IDOWN 6 + +#define CISTPL_POWER_HIGHZ_OK 0x01 +#define CISTPL_POWER_HIGHZ_REQ 0x02 + +typedef struct cistpl_power_t { + u_char present; + u_char flags; + u_int param[7]; +} cistpl_power_t; + +typedef struct cistpl_timing_t { + u_int wait, waitscale; + u_int ready, rdyscale; + u_int reserved, rsvscale; +} cistpl_timing_t; + +#define CISTPL_IO_LINES_MASK 0x1f +#define CISTPL_IO_8BIT 0x20 +#define CISTPL_IO_16BIT 0x40 +#define CISTPL_IO_RANGE 0x80 + +#define CISTPL_IO_MAX_WIN 16 + +typedef struct cistpl_io_t { + u_char flags; + u_char nwin; + struct { + u_int base; + u_int len; + } win[CISTPL_IO_MAX_WIN]; +} cistpl_io_t; + +typedef struct cistpl_irq_t { + u_int IRQInfo1; + u_int IRQInfo2; +} cistpl_irq_t; + +#define CISTPL_MEM_MAX_WIN 8 + +typedef struct cistpl_mem_t { + u_char flags; + u_char nwin; + struct { + u_int len; + u_int card_addr; + u_int host_addr; + } win[CISTPL_MEM_MAX_WIN]; +} cistpl_mem_t; + +#define CISTPL_CFTABLE_DEFAULT 0x0001 +#define CISTPL_CFTABLE_BVDS 0x0002 +#define CISTPL_CFTABLE_WP 0x0004 +#define CISTPL_CFTABLE_RDYBSY 0x0008 +#define CISTPL_CFTABLE_MWAIT 0x0010 +#define CISTPL_CFTABLE_AUDIO 0x0800 +#define CISTPL_CFTABLE_READONLY 0x1000 +#define CISTPL_CFTABLE_PWRDOWN 0x2000 + +typedef struct cistpl_cftable_entry_t { + u_char index; + u_short flags; + u_char interface; + cistpl_power_t vcc, vpp1, vpp2; + cistpl_timing_t timing; + cistpl_io_t io; + cistpl_irq_t irq; + cistpl_mem_t mem; + u_char subtuples; +} cistpl_cftable_entry_t; + +#define CISTPL_CFTABLE_MASTER 0x000100 +#define CISTPL_CFTABLE_INVALIDATE 0x000200 +#define CISTPL_CFTABLE_VGA_PALETTE 0x000400 +#define CISTPL_CFTABLE_PARITY 0x000800 +#define CISTPL_CFTABLE_WAIT 0x001000 +#define CISTPL_CFTABLE_SERR 0x002000 +#define CISTPL_CFTABLE_FAST_BACK 0x004000 +#define CISTPL_CFTABLE_BINARY_AUDIO 0x010000 +#define CISTPL_CFTABLE_PWM_AUDIO 0x020000 + +typedef struct cistpl_cftable_entry_cb_t { + u_char index; + u_int flags; + cistpl_power_t vcc, vpp1, vpp2; + u_char io; + cistpl_irq_t irq; + u_char mem; + u_char subtuples; +} cistpl_cftable_entry_cb_t; + +typedef struct cistpl_device_geo_t { + u_char ngeo; + struct { + u_char buswidth; + u_int erase_block; + u_int read_block; + u_int write_block; + u_int partition; + u_int interleave; + } geo[CISTPL_MAX_DEVICES]; +} cistpl_device_geo_t; + +typedef struct cistpl_vers_2_t { + u_char vers; + u_char comply; + u_short dindex; + u_char vspec8, vspec9; + u_char nhdr; + u_char vendor, info; + char str[244]; +} cistpl_vers_2_t; + +typedef struct cistpl_org_t { + u_char data_org; + char desc[30]; +} cistpl_org_t; + +#define CISTPL_ORG_FS 0x00 +#define CISTPL_ORG_APPSPEC 0x01 +#define CISTPL_ORG_XIP 0x02 + +typedef struct cistpl_format_t { + u_char type; + u_char edc; + u_int offset; + u_int length; +} cistpl_format_t; + +#define CISTPL_FORMAT_DISK 0x00 +#define CISTPL_FORMAT_MEM 0x01 + +#define CISTPL_EDC_NONE 0x00 +#define CISTPL_EDC_CKSUM 0x01 +#define CISTPL_EDC_CRC 0x02 +#define CISTPL_EDC_PCC 0x03 + +typedef union cisparse_t { + cistpl_device_t device; + cistpl_checksum_t checksum; + cistpl_longlink_t longlink; + cistpl_longlink_mfc_t longlink_mfc; + cistpl_vers_1_t version_1; + cistpl_altstr_t altstr; + cistpl_jedec_t jedec; + cistpl_manfid_t manfid; + cistpl_funcid_t funcid; + cistpl_funce_t funce; + cistpl_bar_t bar; + cistpl_config_t config; + cistpl_cftable_entry_t cftable_entry; + cistpl_cftable_entry_cb_t cftable_entry_cb; + cistpl_device_geo_t device_geo; + cistpl_vers_2_t vers_2; + cistpl_org_t org; + cistpl_format_t format; +} cisparse_t; + +typedef struct tuple_t { + u_int Attributes; + cisdata_t DesiredTuple; + u_int Flags; /* internal use */ + u_int LinkOffset; /* internal use */ + u_int CISOffset; /* internal use */ + cisdata_t TupleCode; + cisdata_t TupleLink; + cisdata_t TupleOffset; + cisdata_t TupleDataMax; + cisdata_t TupleDataLen; + cisdata_t *TupleData; +} tuple_t; + +/* Special cisdata_t value */ +#define RETURN_FIRST_TUPLE 0xff + +/* Attributes for tuple calls */ +#define TUPLE_RETURN_LINK 0x01 +#define TUPLE_RETURN_COMMON 0x02 + +/* For ValidateCIS */ +typedef struct cisinfo_t { + u_int Chains; +} cisinfo_t; + +#define CISTPL_MAX_CIS_SIZE 0x200 + +/* For ReplaceCIS */ +typedef struct cisdump_t { + u_int Length; + cisdata_t Data[CISTPL_MAX_CIS_SIZE]; +} cisdump_t; + +#endif /* LINUX_CISTPL_H */ diff --git a/pcmcia/config.h b/pcmcia/config.h new file mode 100644 index 0000000..4ad8fe8 --- /dev/null +++ b/pcmcia/config.h @@ -0,0 +1,59 @@ +/* + Automatically generated by 'make config' -- don't edit! +*/ +#ifndef _PCMCIA_CONFIG_H +#define _PCMCIA_CONFIG_H + +#define AUTOCONF_INCLUDED +#define __IN_PCMCIA_PACKAGE__ + +#define LINUX "/home/gc/rpm/BUILD/linux" +#define PREFIX "/home/gc/rpm/tmp/kernel-2.4.0-build" +#define CC "/usr/bin/kgcc" +#define LD "ld" +#define KFLAGS "" +#define UFLAGS "" +#define PCDEBUG "" +#define USE_PM 1 +#define UNSAFE_TOOLS 1 +#define CONFIG_CARDBUS 1 +#undef CONFIG_PNP_BIOS +#define MODDIR "/lib/modules/2.4.0-6mdk" + +/* Options from /home/gc/rpm/BUILD/linux/.config */ +#define CONFIG_MODULES 1 +#undef CONFIG_PCMCIA +#undef CONFIG_SMP +#define CONFIG_PCI 1 +#define CONFIG_PCI_QUIRKS 1 +#define CONFIG_PM 1 +#define CONFIG_SCSI 1 +#define CONFIG_IEEE1394 1 +#define CONFIG_INET 1 +#define CONFIG_NET_PCMCIA_RADIO 1 +#define CONFIG_TR 1 +#undef CONFIG_NET_FASTROUTE +#undef CONFIG_NET_DIVERT +#define CONFIG_MODVERSIONS 1 +#define CONFIG_X86_L1_CACHE_BYTES 32 +#define CONFIG_X86_L1_CACHE_SHIFT 5 +#define CONFIG_PROC_FS 1 +#define ARCH "i386" +#define HOST_ARCH "i386" +#define AFLAGS "" +#define CONFIG_ISA 1 +#define CONFIG_UID16 1 + +#define UTS_RELEASE "2.4.0-6mdk" +#define UTS_VERSION "#1 Wed Jan 24 16:10:16 CET 2001" +#define LINUX_VERSION_CODE 132096 +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) + +#define HAS_PROC_BUS 1 +#define SYSV_INIT 1 +#define RC_DIR "/etc/rc.d" +#undef HAS_FORMS +#define MANDIR "/usr/share/man" +#define XMANDIR "/usr/X11R6/man" + +#endif /* _PCMCIA_CONFIG_H */ diff --git a/pcmcia/cs.h b/pcmcia/cs.h new file mode 100644 index 0000000..8e202c6 --- /dev/null +++ b/pcmcia/cs.h @@ -0,0 +1,441 @@ +/* + * cs.h 1.74 2001/10/04 03:15:22 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_CS_H +#define _LINUX_CS_H + +/* For AccessConfigurationRegister */ +typedef struct conf_reg_t { + u_char Function; + u_int Action; + off_t Offset; + u_int Value; +} conf_reg_t; + +/* Actions */ +#define CS_READ 1 +#define CS_WRITE 2 + +/* for AdjustResourceInfo */ +typedef struct adjust_t { + u_int Action; + u_int Resource; + u_int Attributes; + union { + struct memory { + u_long Base; + u_long Size; + } memory; + struct io { + ioaddr_t BasePort; + ioaddr_t NumPorts; + u_int IOAddrLines; + } io; + struct irq { + u_int IRQ; + } irq; + } resource; +} adjust_t; + +/* Action field */ +#define REMOVE_MANAGED_RESOURCE 1 +#define ADD_MANAGED_RESOURCE 2 +#define GET_FIRST_MANAGED_RESOURCE 3 +#define GET_NEXT_MANAGED_RESOURCE 4 +/* Resource field */ +#define RES_MEMORY_RANGE 1 +#define RES_IO_RANGE 2 +#define RES_IRQ 3 +/* Attribute field */ +#define RES_IRQ_TYPE 0x03 +#define RES_IRQ_TYPE_EXCLUSIVE 0 +#define RES_IRQ_TYPE_TIME 1 +#define RES_IRQ_TYPE_DYNAMIC 2 +#define RES_IRQ_CSC 0x04 +#define RES_SHARED 0x08 +#define RES_RESERVED 0x10 +#define RES_ALLOCATED 0x20 +#define RES_REMOVED 0x40 + +typedef struct servinfo_t { + char Signature[2]; + u_int Count; + u_int Revision; + u_int CSLevel; + char *VendorString; +} servinfo_t; + +typedef struct event_callback_args_t { + client_handle_t client_handle; + void *info; + void *mtdrequest; + void *buffer; + void *misc; + void *client_data; + struct bus_operations *bus; +} event_callback_args_t; + +/* for GetConfigurationInfo */ +typedef struct config_info_t { + u_char Function; + u_int Attributes; + u_int Vcc, Vpp1, Vpp2; + u_int IntType; + u_int ConfigBase; + u_char Status, Pin, Copy, Option, ExtStatus; + u_int Present; + u_int CardValues; + u_int AssignedIRQ; + u_int IRQAttributes; + ioaddr_t BasePort1; + ioaddr_t NumPorts1; + u_int Attributes1; + ioaddr_t BasePort2; + ioaddr_t NumPorts2; + u_int Attributes2; + u_int IOAddrLines; +} config_info_t; + +/* For CardValues field */ +#define CV_OPTION_VALUE 0x01 +#define CV_STATUS_VALUE 0x02 +#define CV_PIN_REPLACEMENT 0x04 +#define CV_COPY_VALUE 0x08 +#define CV_EXT_STATUS 0x10 + +/* For GetFirst/NextClient */ +typedef struct client_req_t { + socket_t Socket; + u_int Attributes; +} client_req_t; + +#define CLIENT_THIS_SOCKET 0x01 + +/* For RegisterClient */ +typedef struct client_reg_t { + dev_info_t *dev_info; + u_int Attributes; + u_int EventMask; + int (*event_handler)(event_t event, int priority, + event_callback_args_t *); + event_callback_args_t event_callback_args; + u_int Version; +} client_reg_t; + +/* ModifyConfiguration */ +typedef struct modconf_t { + u_int Attributes; + u_int Vcc, Vpp1, Vpp2; +} modconf_t; + +/* Attributes for ModifyConfiguration */ +#define CONF_IRQ_CHANGE_VALID 0x100 +#define CONF_VCC_CHANGE_VALID 0x200 +#define CONF_VPP1_CHANGE_VALID 0x400 +#define CONF_VPP2_CHANGE_VALID 0x800 + +/* For RequestConfiguration */ +typedef struct config_req_t { + u_int Attributes; + u_int Vcc, Vpp1, Vpp2; + u_int IntType; + u_int ConfigBase; + u_char Status, Pin, Copy, ExtStatus; + u_char ConfigIndex; + u_int Present; +} config_req_t; + +/* Attributes for RequestConfiguration */ +#define CONF_ENABLE_IRQ 0x01 +#define CONF_ENABLE_DMA 0x02 +#define CONF_ENABLE_SPKR 0x04 +#define CONF_VALID_CLIENT 0x100 + +/* IntType field */ +#define INT_MEMORY 0x01 +#define INT_MEMORY_AND_IO 0x02 +#define INT_CARDBUS 0x04 +#define INT_ZOOMED_VIDEO 0x08 + +/* For RequestIO and ReleaseIO */ +typedef struct io_req_t { + ioaddr_t BasePort1; + ioaddr_t NumPorts1; + u_int Attributes1; + ioaddr_t BasePort2; + ioaddr_t NumPorts2; + u_int Attributes2; + u_int IOAddrLines; +} io_req_t; + +/* Attributes for RequestIO and ReleaseIO */ +#define IO_SHARED 0x01 +#define IO_FIRST_SHARED 0x02 +#define IO_FORCE_ALIAS_ACCESS 0x04 +#define IO_DATA_PATH_WIDTH 0x18 +#define IO_DATA_PATH_WIDTH_8 0x00 +#define IO_DATA_PATH_WIDTH_16 0x08 +#define IO_DATA_PATH_WIDTH_AUTO 0x10 + +/* For RequestIRQ and ReleaseIRQ */ +typedef struct irq_req_t { + u_int Attributes; + u_int AssignedIRQ; + u_int IRQInfo1, IRQInfo2; + void *Handler; + void *Instance; +} irq_req_t; + +/* Attributes for RequestIRQ and ReleaseIRQ */ +#define IRQ_TYPE 0x03 +#define IRQ_TYPE_EXCLUSIVE 0x00 +#define IRQ_TYPE_TIME 0x01 +#define IRQ_TYPE_DYNAMIC_SHARING 0x02 +#define IRQ_FORCED_PULSE 0x04 +#define IRQ_FIRST_SHARED 0x08 +#define IRQ_HANDLE_PRESENT 0x10 +#define IRQ_PULSE_ALLOCATED 0x100 + +/* Bits in IRQInfo1 field */ +#define IRQ_MASK 0x0f +#define IRQ_NMI_ID 0x01 +#define IRQ_IOCK_ID 0x02 +#define IRQ_BERR_ID 0x04 +#define IRQ_VEND_ID 0x08 +#define IRQ_INFO2_VALID 0x10 +#define IRQ_LEVEL_ID 0x20 +#define IRQ_PULSE_ID 0x40 +#define IRQ_SHARE_ID 0x80 + +typedef struct eventmask_t { + u_int Attributes; + u_int EventMask; +} eventmask_t; + +#define CONF_EVENT_MASK_VALID 0x01 + +/* Configuration registers present */ +#define PRESENT_OPTION 0x001 +#define PRESENT_STATUS 0x002 +#define PRESENT_PIN_REPLACE 0x004 +#define PRESENT_COPY 0x008 +#define PRESENT_EXT_STATUS 0x010 +#define PRESENT_IOBASE_0 0x020 +#define PRESENT_IOBASE_1 0x040 +#define PRESENT_IOBASE_2 0x080 +#define PRESENT_IOBASE_3 0x100 +#define PRESENT_IOSIZE 0x200 + +/* For GetMemPage, MapMemPage */ +typedef struct memreq_t { + u_int CardOffset; + page_t Page; +} memreq_t; + +/* For ModifyWindow */ +typedef struct modwin_t { + u_int Attributes; + u_int AccessSpeed; +} modwin_t; + +/* For RequestWindow */ +typedef struct win_req_t { + u_int Attributes; + u_long Base; + u_int Size; + u_int AccessSpeed; +} win_req_t; + +/* Attributes for RequestWindow */ +#define WIN_ADDR_SPACE 0x0001 +#define WIN_ADDR_SPACE_MEM 0x0000 +#define WIN_ADDR_SPACE_IO 0x0001 +#define WIN_MEMORY_TYPE 0x0002 +#define WIN_MEMORY_TYPE_CM 0x0000 +#define WIN_MEMORY_TYPE_AM 0x0002 +#define WIN_ENABLE 0x0004 +#define WIN_DATA_WIDTH 0x0018 +#define WIN_DATA_WIDTH_8 0x0000 +#define WIN_DATA_WIDTH_16 0x0008 +#define WIN_DATA_WIDTH_32 0x0010 +#define WIN_PAGED 0x0020 +#define WIN_SHARED 0x0040 +#define WIN_FIRST_SHARED 0x0080 +#define WIN_USE_WAIT 0x0100 +#define WIN_STRICT_ALIGN 0x0200 +#define WIN_MAP_BELOW_1MB 0x0400 +#define WIN_PREFETCH 0x0800 +#define WIN_CACHEABLE 0x1000 +#define WIN_BAR_MASK 0xe000 +#define WIN_BAR_SHIFT 13 + +/* Attributes for RegisterClient */ +#define INFO_MASTER_CLIENT 0x01 +#define INFO_IO_CLIENT 0x02 +#define INFO_MTD_CLIENT 0x04 +#define INFO_MEM_CLIENT 0x08 +#define MAX_NUM_CLIENTS 3 + +#define INFO_CARD_SHARE 0x10 +#define INFO_CARD_EXCL 0x20 + +typedef struct cs_status_t { + u_char Function; + event_t CardState; + event_t SocketState; +} cs_status_t; + +typedef struct error_info_t { + int func; + int retcode; +} error_info_t; + +/* Special stuff for binding drivers to sockets */ +typedef struct bind_req_t { + socket_t Socket; + u_char Function; + dev_info_t *dev_info; +} bind_req_t; + +/* Flag to bind to all functions */ +#define BIND_FN_ALL 0xff + +typedef struct mtd_bind_t { + socket_t Socket; + u_int Attributes; + u_int CardOffset; + dev_info_t *dev_info; +} mtd_bind_t; + +/* Events */ +#define CS_EVENT_PRI_LOW 0 +#define CS_EVENT_PRI_HIGH 1 + +#define CS_EVENT_WRITE_PROTECT 0x000001 +#define CS_EVENT_CARD_LOCK 0x000002 +#define CS_EVENT_CARD_INSERTION 0x000004 +#define CS_EVENT_CARD_REMOVAL 0x000008 +#define CS_EVENT_BATTERY_DEAD 0x000010 +#define CS_EVENT_BATTERY_LOW 0x000020 +#define CS_EVENT_READY_CHANGE 0x000040 +#define CS_EVENT_CARD_DETECT 0x000080 +#define CS_EVENT_RESET_REQUEST 0x000100 +#define CS_EVENT_RESET_PHYSICAL 0x000200 +#define CS_EVENT_CARD_RESET 0x000400 +#define CS_EVENT_REGISTRATION_COMPLETE 0x000800 +#define CS_EVENT_RESET_COMPLETE 0x001000 +#define CS_EVENT_PM_SUSPEND 0x002000 +#define CS_EVENT_PM_RESUME 0x004000 +#define CS_EVENT_INSERTION_REQUEST 0x008000 +#define CS_EVENT_EJECTION_REQUEST 0x010000 +#define CS_EVENT_MTD_REQUEST 0x020000 +#define CS_EVENT_ERASE_COMPLETE 0x040000 +#define CS_EVENT_REQUEST_ATTENTION 0x080000 +#define CS_EVENT_CB_DETECT 0x100000 +#define CS_EVENT_3VCARD 0x200000 +#define CS_EVENT_XVCARD 0x400000 + +/* Return codes */ +#define CS_SUCCESS 0x00 +#define CS_BAD_ADAPTER 0x01 +#define CS_BAD_ATTRIBUTE 0x02 +#define CS_BAD_BASE 0x03 +#define CS_BAD_EDC 0x04 +#define CS_BAD_IRQ 0x06 +#define CS_BAD_OFFSET 0x07 +#define CS_BAD_PAGE 0x08 +#define CS_READ_FAILURE 0x09 +#define CS_BAD_SIZE 0x0a +#define CS_BAD_SOCKET 0x0b +#define CS_BAD_TYPE 0x0d +#define CS_BAD_VCC 0x0e +#define CS_BAD_VPP 0x0f +#define CS_BAD_WINDOW 0x11 +#define CS_WRITE_FAILURE 0x12 +#define CS_NO_CARD 0x14 +#define CS_UNSUPPORTED_FUNCTION 0x15 +#define CS_UNSUPPORTED_MODE 0x16 +#define CS_BAD_SPEED 0x17 +#define CS_BUSY 0x18 +#define CS_GENERAL_FAILURE 0x19 +#define CS_WRITE_PROTECTED 0x1a +#define CS_BAD_ARG_LENGTH 0x1b +#define CS_BAD_ARGS 0x1c +#define CS_CONFIGURATION_LOCKED 0x1d +#define CS_IN_USE 0x1e +#define CS_NO_MORE_ITEMS 0x1f +#define CS_OUT_OF_RESOURCE 0x20 +#define CS_BAD_HANDLE 0x21 + +#define CS_BAD_TUPLE 0x40 + +#ifdef __KERNEL__ + +/* + * Calls to set up low-level "Socket Services" drivers + */ + +typedef int (*ss_entry_t)(u_int sock, u_int cmd, void *arg); +extern int register_ss_entry(int nsock, ss_entry_t entry); +extern void unregister_ss_entry(ss_entry_t entry); + +/* + * The main Card Services entry point + */ + +enum service { + AccessConfigurationRegister, AddSocketServices, + AdjustResourceInfo, CheckEraseQueue, CloseMemory, CopyMemory, + DeregisterClient, DeregisterEraseQueue, GetCardServicesInfo, + GetClientInfo, GetConfigurationInfo, GetEventMask, + GetFirstClient, GetFirstPartion, GetFirstRegion, GetFirstTuple, + GetNextClient, GetNextPartition, GetNextRegion, GetNextTuple, + GetStatus, GetTupleData, MapLogSocket, MapLogWindow, MapMemPage, + MapPhySocket, MapPhyWindow, ModifyConfiguration, ModifyWindow, + OpenMemory, ParseTuple, ReadMemory, RegisterClient, + RegisterEraseQueue, RegisterMTD, RegisterTimer, + ReleaseConfiguration, ReleaseExclusive, ReleaseIO, ReleaseIRQ, + ReleaseSocketMask, ReleaseWindow, ReplaceSocketServices, + RequestConfiguration, RequestExclusive, RequestIO, RequestIRQ, + RequestSocketMask, RequestWindow, ResetCard, ReturnSSEntry, + SetEventMask, SetRegion, ValidateCIS, VendorSpecific, + WriteMemory, BindDevice, BindMTD, ReportError, + SuspendCard, ResumeCard, EjectCard, InsertCard, ReplaceCIS, + GetFirstWindow, GetNextWindow, GetMemPage +}; + +#ifdef IN_CARD_SERVICES +extern int CardServices(int func, void *a1, void *a2, void *a3); +#else +extern int CardServices(int func, ...); +#endif + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_CS_H */ diff --git a/pcmcia/cs_types.h b/pcmcia/cs_types.h new file mode 100644 index 0000000..88471f9 --- /dev/null +++ b/pcmcia/cs_types.h @@ -0,0 +1,70 @@ +/* + * cs_types.h 1.20 2002/04/17 02:52:39 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_CS_TYPES_H +#define _LINUX_CS_TYPES_H + +#ifdef __linux__ +#ifdef __KERNEL__ +#include +#else +#include +#endif +#endif + +#ifdef __arm__ +typedef u_int ioaddr_t; +#else +typedef u_short ioaddr_t; +#endif + +typedef u_short socket_t; +typedef u_int event_t; +typedef u_char cisdata_t; +typedef u_short page_t; + +struct client_t; +typedef struct client_t *client_handle_t; + +struct window_t; +typedef struct window_t *window_handle_t; + +struct region_t; +typedef struct region_t *memory_handle_t; + +struct eraseq_t; +typedef struct eraseq_t *eraseq_handle_t; + +#ifndef DEV_NAME_LEN +#define DEV_NAME_LEN 32 +#endif + +typedef char dev_info_t[DEV_NAME_LEN]; + +#endif /* _LINUX_CS_TYPES_H */ diff --git a/pcmcia/driver_ops.h b/pcmcia/driver_ops.h new file mode 100644 index 0000000..9903e5b --- /dev/null +++ b/pcmcia/driver_ops.h @@ -0,0 +1,73 @@ +/* + * driver_ops.h 1.17 2001/10/04 03:15:22 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_DRIVER_OPS_H +#define _LINUX_DRIVER_OPS_H + +#ifndef DEV_NAME_LEN +#define DEV_NAME_LEN 32 +#endif + +#ifdef __KERNEL__ + +typedef struct dev_node_t { + char dev_name[DEV_NAME_LEN]; + u_short major, minor; + struct dev_node_t *next; +} dev_node_t; + +typedef struct dev_locator_t { + enum { LOC_ISA, LOC_PCI } bus; + union { + struct { + u_short io_base_1, io_base_2; + u_long mem_base; + u_char irq, dma; + } isa; + struct { + u_char bus; + u_char devfn; + } pci; + } b; +} dev_locator_t; + +typedef struct driver_operations { + char *name; + dev_node_t *(*attach) (dev_locator_t *loc); + void (*suspend) (dev_node_t *dev); + void (*resume) (dev_node_t *dev); + void (*detach) (dev_node_t *dev); +} driver_operations; + +int register_driver(struct driver_operations *ops); +void unregister_driver(struct driver_operations *ops); + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_DRIVER_OPS_H */ diff --git a/pcmcia/ds.h b/pcmcia/ds.h new file mode 100644 index 0000000..b372e59 --- /dev/null +++ b/pcmcia/ds.h @@ -0,0 +1,148 @@ +/* + * ds.h 1.58 2001/10/04 03:15:22 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_DS_H +#define _LINUX_DS_H + +#include +#include + +typedef struct tuple_parse_t { + tuple_t tuple; + cisdata_t data[255]; + cisparse_t parse; +} tuple_parse_t; + +typedef struct win_info_t { + window_handle_t handle; + win_req_t window; + memreq_t map; +} win_info_t; + +typedef struct bind_info_t { + dev_info_t dev_info; + u_char function; + struct dev_link_t *instance; + char name[DEV_NAME_LEN]; + u_short major, minor; + void *next; +} bind_info_t; + +typedef struct mtd_info_t { + dev_info_t dev_info; + u_int Attributes; + u_int CardOffset; +} mtd_info_t; + +typedef union ds_ioctl_arg_t { + servinfo_t servinfo; + adjust_t adjust; + config_info_t config; + tuple_t tuple; + tuple_parse_t tuple_parse; + client_req_t client_req; + cs_status_t status; + conf_reg_t conf_reg; + cisinfo_t cisinfo; + region_info_t region; + bind_info_t bind_info; + mtd_info_t mtd_info; + win_info_t win_info; + cisdump_t cisdump; +} ds_ioctl_arg_t; + +#define DS_GET_CARD_SERVICES_INFO _IOR ('d', 1, servinfo_t) +#define DS_ADJUST_RESOURCE_INFO _IOWR('d', 2, adjust_t) +#define DS_GET_CONFIGURATION_INFO _IOWR('d', 3, config_info_t) +#define DS_GET_FIRST_TUPLE _IOWR('d', 4, tuple_t) +#define DS_GET_NEXT_TUPLE _IOWR('d', 5, tuple_t) +#define DS_GET_TUPLE_DATA _IOWR('d', 6, tuple_parse_t) +#define DS_PARSE_TUPLE _IOWR('d', 7, tuple_parse_t) +#define DS_RESET_CARD _IO ('d', 8) +#define DS_GET_STATUS _IOWR('d', 9, cs_status_t) +#define DS_ACCESS_CONFIGURATION_REGISTER _IOWR('d', 10, conf_reg_t) +#define DS_VALIDATE_CIS _IOR ('d', 11, cisinfo_t) +#define DS_SUSPEND_CARD _IO ('d', 12) +#define DS_RESUME_CARD _IO ('d', 13) +#define DS_EJECT_CARD _IO ('d', 14) +#define DS_INSERT_CARD _IO ('d', 15) +#define DS_GET_FIRST_REGION _IOWR('d', 16, region_info_t) +#define DS_GET_NEXT_REGION _IOWR('d', 17, region_info_t) +#define DS_REPLACE_CIS _IOWR('d', 18, cisdump_t) +#define DS_GET_FIRST_WINDOW _IOR ('d', 19, win_info_t) +#define DS_GET_NEXT_WINDOW _IOWR('d', 20, win_info_t) +#define DS_GET_MEM_PAGE _IOWR('d', 21, win_info_t) + +#define DS_BIND_REQUEST _IOWR('d', 60, bind_info_t) +#define DS_GET_DEVICE_INFO _IOWR('d', 61, bind_info_t) +#define DS_GET_NEXT_DEVICE _IOWR('d', 62, bind_info_t) +#define DS_UNBIND_REQUEST _IOW ('d', 63, bind_info_t) +#define DS_BIND_MTD _IOWR('d', 64, mtd_info_t) + +#ifdef __KERNEL__ + +typedef struct dev_link_t { + dev_node_t *dev; + u_int state, open; + wait_queue_head_t pending; + struct timer_list release; + client_handle_t handle; + io_req_t io; + irq_req_t irq; + config_req_t conf; + window_handle_t win; + void *priv; + struct dev_link_t *next; +} dev_link_t; + +/* Flags for device state */ +#define DEV_PRESENT 0x01 +#define DEV_CONFIG 0x02 +#define DEV_STALE_CONFIG 0x04 /* release on close */ +#define DEV_STALE_LINK 0x08 /* detach on release */ +#define DEV_CONFIG_PENDING 0x10 +#define DEV_RELEASE_PENDING 0x20 +#define DEV_SUSPEND 0x40 +#define DEV_BUSY 0x80 + +#define DEV_OK(l) \ + ((l) && ((l->state & ~DEV_BUSY) == (DEV_CONFIG|DEV_PRESENT))) + +int register_pccard_driver(dev_info_t *dev_info, + dev_link_t *(*attach)(void), + void (*detach)(dev_link_t *)); + +int unregister_pccard_driver(dev_info_t *dev_info); + +#define register_pcmcia_driver register_pccard_driver +#define unregister_pcmcia_driver unregister_pccard_driver + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_DS_H */ diff --git a/pcmcia/i82365.h b/pcmcia/i82365.h new file mode 100644 index 0000000..15e8e25 --- /dev/null +++ b/pcmcia/i82365.h @@ -0,0 +1,154 @@ +/* + * i82365.h 1.20 2000/07/20 23:00:27 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_I82365_H +#define _LINUX_I82365_H + +/* register definitions for the Intel 82365SL PCMCIA controller */ + +/* Offsets for PCIC registers */ +#define I365_IDENT 0x00 /* Identification and revision */ +#define I365_STATUS 0x01 /* Interface status */ +#define I365_POWER 0x02 /* Power and RESETDRV control */ +#define I365_INTCTL 0x03 /* Interrupt and general control */ +#define I365_CSC 0x04 /* Card status change */ +#define I365_CSCINT 0x05 /* Card status change interrupt control */ +#define I365_ADDRWIN 0x06 /* Address window enable */ +#define I365_IOCTL 0x07 /* I/O control */ +#define I365_GENCTL 0x16 /* Card detect and general control */ +#define I365_GBLCTL 0x1E /* Global control register */ + +/* Offsets for I/O and memory window registers */ +#define I365_IO(map) (0x08+((map)<<2)) +#define I365_MEM(map) (0x10+((map)<<3)) +#define I365_W_START 0 +#define I365_W_STOP 2 +#define I365_W_OFF 4 + +/* Flags for I365_STATUS */ +#define I365_CS_BVD1 0x01 +#define I365_CS_STSCHG 0x01 +#define I365_CS_BVD2 0x02 +#define I365_CS_SPKR 0x02 +#define I365_CS_DETECT 0x0C +#define I365_CS_WRPROT 0x10 +#define I365_CS_READY 0x20 /* Inverted */ +#define I365_CS_POWERON 0x40 +#define I365_CS_GPI 0x80 + +/* Flags for I365_POWER */ +#define I365_PWR_OFF 0x00 /* Turn off the socket */ +#define I365_PWR_OUT 0x80 /* Output enable */ +#define I365_PWR_NORESET 0x40 /* Disable RESETDRV on resume */ +#define I365_PWR_AUTO 0x20 /* Auto pwr switch enable */ +#define I365_VCC_MASK 0x18 /* Mask for turning off Vcc */ +/* There are different layouts for B-step and DF-step chips: the B + step has independent Vpp1/Vpp2 control, and the DF step has only + Vpp1 control, plus 3V control */ +#define I365_VCC_5V 0x10 /* Vcc = 5.0v */ +#define I365_VCC_3V 0x18 /* Vcc = 3.3v */ +#define I365_VPP2_MASK 0x0c /* Mask for turning off Vpp2 */ +#define I365_VPP2_5V 0x04 /* Vpp2 = 5.0v */ +#define I365_VPP2_12V 0x08 /* Vpp2 = 12.0v */ +#define I365_VPP1_MASK 0x03 /* Mask for turning off Vpp1 */ +#define I365_VPP1_5V 0x01 /* Vpp2 = 5.0v */ +#define I365_VPP1_12V 0x02 /* Vpp2 = 12.0v */ + +/* Flags for I365_INTCTL */ +#define I365_RING_ENA 0x80 +#define I365_PC_RESET 0x40 +#define I365_PC_IOCARD 0x20 +#define I365_INTR_ENA 0x10 +#define I365_IRQ_MASK 0x0F + +/* Flags for I365_CSC and I365_CSCINT*/ +#define I365_CSC_BVD1 0x01 +#define I365_CSC_STSCHG 0x01 +#define I365_CSC_BVD2 0x02 +#define I365_CSC_READY 0x04 +#define I365_CSC_DETECT 0x08 +#define I365_CSC_ANY 0x0F +#define I365_CSC_GPI 0x10 + +/* Flags for I365_ADDRWIN */ +#define I365_ADDR_MEMCS16 0x20 +#define I365_ENA_IO(map) (0x40 << (map)) +#define I365_ENA_MEM(map) (0x01 << (map)) + +/* Flags for I365_IOCTL */ +#define I365_IOCTL_MASK(map) (0x0F << (map<<2)) +#define I365_IOCTL_WAIT(map) (0x08 << (map<<2)) +#define I365_IOCTL_0WS(map) (0x04 << (map<<2)) +#define I365_IOCTL_IOCS16(map) (0x02 << (map<<2)) +#define I365_IOCTL_16BIT(map) (0x01 << (map<<2)) + +/* Flags for I365_GENCTL */ +#define I365_CTL_16DELAY 0x01 +#define I365_CTL_RESET 0x02 +#define I365_CTL_GPI_ENA 0x04 +#define I365_CTL_GPI_CTL 0x08 +#define I365_CTL_RESUME 0x10 +#define I365_CTL_SW_IRQ 0x20 + +/* Flags for I365_GBLCTL */ +#define I365_GBL_PWRDOWN 0x01 +#define I365_GBL_CSC_LEV 0x02 +#define I365_GBL_WRBACK 0x04 +#define I365_GBL_IRQ_0_LEV 0x08 +#define I365_GBL_IRQ_1_LEV 0x10 + +/* Flags for memory window registers */ +#define I365_MEM_16BIT 0x8000 /* In memory start high byte */ +#define I365_MEM_0WS 0x4000 +#define I365_MEM_WS1 0x8000 /* In memory stop high byte */ +#define I365_MEM_WS0 0x4000 +#define I365_MEM_WRPROT 0x8000 /* In offset high byte */ +#define I365_MEM_REG 0x4000 + +#define I365_REG(slot, reg) (((slot) << 6) | (reg)) + +/* Default ISA interrupt mask */ +#define I365_ISA_IRQ_MASK 0xdeb8 /* irq's 3-5,7,9-12,14,15 */ + +/* Device ID's for PCI-to-PCMCIA bridges */ + +#ifndef PCI_VENDOR_ID_INTEL +#define PCI_VENDOR_ID_INTEL 0x8086 +#endif +#ifndef PCI_DEVICE_ID_INTEL_82092AA_0 +#define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221 +#endif +#ifndef PCI_VENDOR_ID_OMEGA +#define PCI_VENDOR_ID_OMEGA 0x119b +#endif +#ifndef PCI_DEVICE_ID_OMEGA_82C092G +#define PCI_DEVICE_ID_OMEGA_82C092G 0x1221 +#endif + +#endif /* _LINUX_I82365_H */ diff --git a/pcmcia/lex_config.c b/pcmcia/lex_config.c new file mode 100644 index 0000000..6bebec7 --- /dev/null +++ b/pcmcia/lex_config.c @@ -0,0 +1,2062 @@ +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header$ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include +#include + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include +#include +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 44 +#define YY_END_OF_BUFFER 45 +static yyconst short int yy_accept[246] = + { 0, + 4, 4, 0, 0, 45, 43, 4, 3, 4, 43, + 5, 40, 40, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 2, + 44, 4, 4, 5, 0, 42, 0, 5, 40, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, + 0, 2, 0, 42, 0, 41, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, 0, 17, + 0, 0, 0, 0, 22, 0, 0, 0, 0, 25, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 24, 0, 26, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 10, 0, 0, 13, 0, 0, 0, 0, 18, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 30, 0, 0, 0, 0, 0, 12, 0, 0, 0, + 0, 19, 20, 21, 0, 0, 0, 27, 0, 0, + 0, 0, 0, 0, 0, 0, 11, 14, 0, 0, + 16, 0, 0, 0, 0, 28, 0, 0, 1, 31, + + 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, + 0, 0, 38, 6, 0, 0, 23, 0, 0, 0, + 0, 0, 35, 0, 0, 0, 0, 0, 0, 32, + 0, 0, 0, 33, 0, 0, 0, 39, 0, 0, + 34, 36, 0, 37, 0 + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4, 1, 5, 6, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 1, 6, 1, + 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 10, 1, 1, 11, 1, 12, 13, 14, 15, + + 16, 17, 18, 1, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst int yy_meta[36] = + { 0, + 1, 1, 2, 1, 1, 1, 3, 3, 3, 1, + 1, 3, 3, 3, 3, 3, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst short int yy_base[252] = + { 0, + 0, 0, 282, 281, 283, 286, 34, 286, 35, 35, + 0, 35, 39, 25, 263, 36, 34, 247, 32, 28, + 264, 41, 263, 252, 47, 261, 51, 29, 54, 0, + 286, 73, 76, 0, 69, 286, 78, 0, 77, 0, + 253, 250, 250, 245, 243, 259, 69, 235, 255, 234, + 243, 252, 238, 249, 239, 239, 246, 245, 73, 229, + 230, 238, 228, 69, 226, 226, 222, 286, 226, 223, + 235, 0, 85, 86, 89, 0, 220, 224, 232, 231, + 286, 216, 232, 224, 216, 219, 224, 225, 216, 286, + 221, 219, 210, 203, 286, 218, 199, 202, 218, 286, + + 199, 209, 211, 207, 206, 196, 201, 193, 205, 209, + 184, 286, 286, 189, 186, 202, 199, 183, 198, 182, + 180, 196, 190, 180, 185, 177, 180, 286, 182, 286, + 178, 174, 190, 188, 185, 182, 178, 171, 181, 171, + 286, 171, 176, 286, 176, 179, 170, 173, 286, 172, + 151, 169, 173, 155, 160, 157, 148, 167, 156, 161, + 286, 151, 164, 162, 148, 142, 286, 155, 155, 144, + 152, 286, 156, 286, 143, 144, 148, 286, 147, 147, + 150, 98, 136, 147, 130, 126, 286, 286, 137, 131, + 286, 140, 123, 141, 129, 286, 138, 123, 102, 286, + + 133, 132, 117, 116, 286, 132, 128, 130, 130, 114, + 114, 126, 286, 286, 116, 108, 286, 120, 108, 103, + 104, 105, 286, 115, 117, 103, 111, 96, 95, 286, + 98, 95, 94, 286, 101, 84, 75, 286, 69, 77, + 286, 286, 40, 286, 286, 106, 109, 112, 115, 118, + 59 + } ; + +static yyconst short int yy_def[252] = + { 0, + 245, 1, 246, 246, 245, 245, 245, 245, 245, 247, + 248, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 249, + 245, 245, 245, 248, 247, 245, 250, 248, 245, 251, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 249, 247, 247, 250, 251, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 0, 245, 245, 245, 245, 245, + 245 + } ; + +static yyconst short int yy_nxt[322] = + { 0, + 6, 7, 8, 9, 10, 11, 12, 13, 6, 6, + 6, 14, 15, 16, 17, 18, 19, 6, 20, 21, + 6, 6, 22, 23, 24, 25, 6, 26, 27, 28, + 6, 29, 6, 6, 6, 32, 32, 32, 33, 36, + 34, 39, 39, 41, 37, 39, 39, 44, 42, 47, + 50, 52, 55, 68, 45, 53, 56, 46, 61, 69, + 62, 76, 51, 48, 65, 57, 66, 244, 40, 70, + 58, 63, 71, 36, 32, 67, 32, 32, 37, 33, + 35, 34, 74, 39, 39, 83, 102, 75, 96, 36, + 36, 35, 243, 74, 37, 37, 242, 103, 75, 199, + + 84, 199, 97, 199, 241, 199, 30, 30, 30, 35, + 35, 35, 38, 240, 38, 72, 239, 72, 73, 73, + 73, 238, 237, 236, 235, 234, 233, 232, 231, 230, + 229, 228, 227, 226, 225, 224, 223, 222, 221, 220, + 219, 218, 217, 216, 215, 214, 213, 212, 211, 210, + 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, + 198, 197, 196, 195, 194, 193, 192, 191, 190, 189, + 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, + 178, 177, 176, 175, 174, 173, 172, 171, 170, 169, + 168, 167, 166, 165, 164, 163, 162, 161, 160, 159, + + 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, + 148, 147, 146, 145, 144, 143, 142, 141, 140, 139, + 138, 137, 136, 135, 134, 133, 132, 131, 130, 129, + 128, 127, 126, 125, 124, 123, 122, 121, 120, 119, + 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, + 108, 107, 106, 105, 104, 101, 100, 99, 98, 95, + 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, + 82, 81, 80, 79, 78, 77, 64, 60, 59, 54, + 49, 43, 245, 31, 31, 5, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245 + } ; + +static yyconst short int yy_chk[322] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 7, 9, 7, 9, 10, + 9, 12, 12, 14, 10, 13, 13, 16, 14, 17, + 19, 20, 22, 28, 16, 20, 22, 16, 25, 28, + 25, 251, 19, 17, 27, 22, 27, 243, 12, 29, + 22, 25, 29, 35, 32, 27, 32, 33, 35, 33, + 37, 33, 37, 39, 39, 47, 64, 37, 59, 73, + 74, 75, 240, 75, 73, 74, 239, 64, 75, 182, + + 47, 182, 59, 199, 237, 199, 246, 246, 246, 247, + 247, 247, 248, 236, 248, 249, 235, 249, 250, 250, + 250, 233, 232, 231, 229, 228, 227, 226, 225, 224, + 222, 221, 220, 219, 218, 216, 215, 212, 211, 210, + 209, 208, 207, 206, 204, 203, 202, 201, 198, 197, + 195, 194, 193, 192, 190, 189, 186, 185, 184, 183, + 181, 180, 179, 177, 176, 175, 173, 171, 170, 169, + 168, 166, 165, 164, 163, 162, 160, 159, 158, 157, + 156, 155, 154, 153, 152, 151, 150, 148, 147, 146, + 145, 143, 142, 140, 139, 138, 137, 136, 135, 134, + + 133, 132, 131, 129, 127, 126, 125, 124, 123, 122, + 121, 120, 119, 118, 117, 116, 115, 114, 111, 110, + 109, 108, 107, 106, 105, 104, 103, 102, 101, 99, + 98, 97, 96, 94, 93, 92, 91, 89, 88, 87, + 86, 85, 84, 83, 82, 80, 79, 78, 77, 71, + 70, 69, 67, 66, 65, 63, 62, 61, 60, 58, + 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, + 46, 45, 44, 43, 42, 41, 26, 24, 23, 21, + 18, 15, 5, 4, 3, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 245 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "lex_config.l" +#define INITIAL 0 +/* Special state for handling include files */ +#define src 1 + +#line 5 "lex_config.l" +/* + * lex_config.l 1.49 2002/10/07 16:39:21 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#undef src + +#include +#include +#include +#include +#include + +#ifdef HAS_WORDEXP +#include +#else +#include +#endif + +#define src 1 + +#include +#include + +#include "yacc_config.h" + +/* 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); + + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp = NULL, *yy_bp = NULL; + register int yy_act; + +#line 70 "lex_config.l" + + + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 246 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 286 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 72 "lex_config.l" +BEGIN(src); return SOURCE; + YY_BREAK +case 2: +YY_RULE_SETUP +#line 73 "lex_config.l" +do_source(yytext); BEGIN(INITIAL); + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(src): +#line 74 "lex_config.l" +if (do_eof()) yyterminate(); + YY_BREAK +case 3: +YY_RULE_SETUP +#line 76 "lex_config.l" +current_lineno++; + YY_BREAK +case 4: +YY_RULE_SETUP +#line 77 "lex_config.l" +/* skip */ ; + YY_BREAK +case 5: +YY_RULE_SETUP +#line 78 "lex_config.l" +/* skip */ ; + YY_BREAK +case 6: +YY_RULE_SETUP +#line 80 "lex_config.l" +return ANONYMOUS; + YY_BREAK +case 7: +YY_RULE_SETUP +#line 81 "lex_config.l" +return BIND; + YY_BREAK +case 8: +YY_RULE_SETUP +#line 82 "lex_config.l" +return CIS; + YY_BREAK +case 9: +YY_RULE_SETUP +#line 83 "lex_config.l" +return CARD; + YY_BREAK +case 10: +YY_RULE_SETUP +#line 84 "lex_config.l" +return CLASS; + YY_BREAK +case 11: +YY_RULE_SETUP +#line 85 "lex_config.l" +return DEFAULT; + YY_BREAK +case 12: +YY_RULE_SETUP +#line 86 "lex_config.l" +return DEVICE; + YY_BREAK +case 13: +YY_RULE_SETUP +#line 87 "lex_config.l" +return DTYPE; + YY_BREAK +case 14: +YY_RULE_SETUP +#line 88 "lex_config.l" +return EXCLUDE; + YY_BREAK +case 15: +YY_RULE_SETUP +#line 89 "lex_config.l" +return FUNCTION; + YY_BREAK +case 16: +YY_RULE_SETUP +#line 90 "lex_config.l" +return INCLUDE; + YY_BREAK +case 17: +YY_RULE_SETUP +#line 91 "lex_config.l" +return IRQ_NO; + YY_BREAK +case 18: +YY_RULE_SETUP +#line 92 "lex_config.l" +return JEDEC; + YY_BREAK +case 19: +YY_RULE_SETUP +#line 93 "lex_config.l" +return MANFID; + YY_BREAK +case 20: +YY_RULE_SETUP +#line 94 "lex_config.l" +return MEMORY; + YY_BREAK +case 21: +YY_RULE_SETUP +#line 95 "lex_config.l" +return MODULE; + YY_BREAK +case 22: +YY_RULE_SETUP +#line 96 "lex_config.l" +return MTD; + YY_BREAK +case 23: +YY_RULE_SETUP +#line 97 "lex_config.l" +return NEEDS_MTD; + YY_BREAK +case 24: +YY_RULE_SETUP +#line 98 "lex_config.l" +return OPTS; + YY_BREAK +case 25: +YY_RULE_SETUP +#line 99 "lex_config.l" +return PCI; + YY_BREAK +case 26: +YY_RULE_SETUP +#line 100 "lex_config.l" +return PORT; + YY_BREAK +case 27: +YY_RULE_SETUP +#line 101 "lex_config.l" +return REGION; + YY_BREAK +case 28: +YY_RULE_SETUP +#line 102 "lex_config.l" +return RESERVE; + YY_BREAK +case 29: +YY_RULE_SETUP +#line 103 "lex_config.l" +return TO; + YY_BREAK +case 30: +YY_RULE_SETUP +#line 104 "lex_config.l" +return TUPLE; + YY_BREAK +case 31: +YY_RULE_SETUP +#line 105 "lex_config.l" +return VERSION; + YY_BREAK +case 32: +YY_RULE_SETUP +#line 107 "lex_config.l" +return lex_number("1"); + YY_BREAK +case 33: +YY_RULE_SETUP +#line 108 "lex_config.l" +return lex_number("2"); + YY_BREAK +case 34: +YY_RULE_SETUP +#line 109 "lex_config.l" +return lex_number("3"); + YY_BREAK +case 35: +YY_RULE_SETUP +#line 110 "lex_config.l" +return lex_number("4"); + YY_BREAK +case 36: +YY_RULE_SETUP +#line 111 "lex_config.l" +return lex_number("5"); + YY_BREAK +case 37: +YY_RULE_SETUP +#line 112 "lex_config.l" +return lex_number("6"); + YY_BREAK +case 38: +YY_RULE_SETUP +#line 113 "lex_config.l" +return lex_number("7"); + YY_BREAK +case 39: +YY_RULE_SETUP +#line 114 "lex_config.l" +return lex_number("8"); + YY_BREAK +case 40: +YY_RULE_SETUP +#line 116 "lex_config.l" +return lex_number(yytext); + YY_BREAK +case 41: +YY_RULE_SETUP +#line 118 "lex_config.l" +return lex_number(yytext); + YY_BREAK +case 42: +YY_RULE_SETUP +#line 120 "lex_config.l" +return lex_string(yytext); + YY_BREAK +case 43: +YY_RULE_SETUP +#line 122 "lex_config.l" +return yytext[0]; + YY_BREAK +case 44: +YY_RULE_SETUP +#line 124 "lex_config.l" +ECHO; + YY_BREAK + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 246 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + register char *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 246 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 245); + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + + return c; + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 124 "lex_config.l" + + +#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_INFO, "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_INFO, "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_INFO, "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/pcmcia/lex_config.l b/pcmcia/lex_config.l new file mode 100644 index 0000000..3d859f8 --- /dev/null +++ b/pcmcia/lex_config.l @@ -0,0 +1,269 @@ +/* Special state for handling include files */ +%x src + +%{ +/* + * lex_config.l 1.49 2002/10/07 16:39:21 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#undef src + +#include +#include +#include +#include +#include + +#ifdef HAS_WORDEXP +#include +#else +#include +#endif + +#define src 1 + +#include +#include + +#include "yacc_config.h" + +/* 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; +[^\n]+ do_source(yytext); BEGIN(INITIAL); +<> if (do_eof()) yyterminate(); + +\n current_lineno++; +[ \t]* /* skip */ ; +[ ]*[#;].* /* skip */ ; + +anonymous return ANONYMOUS; +bind return BIND; +cis return CIS; +card return CARD; +class return CLASS; +default return DEFAULT; +device return DEVICE; +dtype return DTYPE; +exclude return EXCLUDE; +function return FUNCTION; +include return INCLUDE; +irq return IRQ_NO; +jedec return JEDEC; +manfid return MANFID; +memory return MEMORY; +module return MODULE; +mtd return MTD; +needs_mtd return NEEDS_MTD; +opts return OPTS; +pci return PCI; +port return PORT; +region return REGION; +reserve return RESERVE; +to return TO; +tuple return TUPLE; +version return VERSION; + +memory_card return lex_number("1"); +serial_port return lex_number("2"); +parallel_port return lex_number("3"); +fixed_disk return lex_number("4"); +video_adapter return lex_number("5"); +network_adapter return lex_number("6"); +aims_card return lex_number("7"); +scsi_adapter return lex_number("8"); + +{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_INFO, "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_INFO, "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_INFO, "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/pcmcia/pcmcia.h b/pcmcia/pcmcia.h new file mode 100644 index 0000000..1967b34 --- /dev/null +++ b/pcmcia/pcmcia.h @@ -0,0 +1,21 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _PCMCIA_CARDMGR_INTERFACE_H_ +#define _PCMCIA_CARDMGR_INTERFACE_H_ + +char * pcmcia_probe(void); +int cardmgr_call(void); + +#endif diff --git a/pcmcia/pcmcia_probe.c b/pcmcia/pcmcia_probe.c new file mode 100644 index 0000000..86bf8ac --- /dev/null +++ b/pcmcia/pcmcia_probe.c @@ -0,0 +1,419 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000-2001 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* Code comes from /anonymous@projects.sourceforge.net:/pub/pcmcia-cs/pcmcia-cs-3.1.28.tar.bz2 + * + * Licence of this code follows: + + PCMCIA controller probe + + probe.c 1.54 2001/05/10 03:01:59 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + . Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "pcmcia.h" + +/*====================================================================*/ + +typedef struct { + u_short vendor, device; + char *tag; + char *name; +} pci_id_t; + +pci_id_t pci_id[] = { + { 0x1013, 0x1100, "Cirrus Logic CL 6729", "Cirrus PD6729" }, + { 0x1013, 0x1110, "Cirrus Logic PD 6832", "Cirrus PD6832" }, + { 0x10b3, 0xb106, "SMC 34C90", "SMC 34C90" }, + { 0x1180, 0x0465, "Ricoh RL5C465", "Ricoh RL5C465" }, + { 0x1180, 0x0466, "Ricoh RL5C466", "Ricoh RL5C466" }, + { 0x1180, 0x0475, "Ricoh RL5C475", "Ricoh RL5C475" }, + { 0x1180, 0x0476, "Ricoh RL5C476", "Ricoh RL5C476" }, + { 0x1180, 0x0478, "Ricoh RL5C478", "Ricoh RL5C478" }, + { 0x104c, 0xac12, "Texas Instruments PCI1130", "TI 1130" }, + { 0x104c, 0xac13, "Texas Instruments PCI1031", "TI 1031" }, + { 0x104c, 0xac15, "Texas Instruments PCI1131", "TI 1131" }, + { 0x104c, 0xac1a, "Texas Instruments PCI1210", "TI 1210" }, + { 0x104c, 0xac1e, "Texas Instruments PCI1211", "TI 1211" }, + { 0x104c, 0xac17, "Texas Instruments PCI1220", "TI 1220" }, + { 0x104c, 0xac19, "Texas Instruments PCI1221", "TI 1221" }, + { 0x104c, 0xac1c, "Texas Instruments PCI1225", "TI 1225" }, + { 0x104c, 0xac16, "Texas Instruments PCI1250", "TI 1250A" }, + { 0x104c, 0xac1d, "Texas Instruments PCI1251A", "TI 1251A" }, + { 0x104c, 0xac1f, "Texas Instruments PCI1251B", "TI 1251B" }, + { 0x104c, 0xac50, "Texas Instruments PCI1410", "TI 1410" }, + { 0x104c, 0xac51, "Texas Instruments PCI1420", "TI 1420" }, + { 0x104c, 0xac52, "Texas Instruments PCI1451", "TI 1451" }, + { 0x104c, 0xac53, "Texas Instruments PCI1421", "TI 1421" }, + { 0x104c, 0xac54, "Texas Instruments PCI1620", "TI 1620" }, + { 0x104c, 0xac55, "Texas Instruments PCI1250", "TI 1250" }, + { 0x104c, 0xac56, "Texas Instruments PCI1510", "TI 1510" }, + { 0x104c, 0xac57, "Texas Instruments PCI1530", "TI 1530" }, + { 0x104c, 0xac58, "Texas Instruments PCI1515", "TI 1515" }, + { 0x104c, 0xac59, "Texas Instruments PCI1621", "TI 1621" }, + { 0x104c, 0xac5a, "Texas Instruments PCI1610", "TI 1610" }, + { 0x104c, 0xac1b, "Texas Instruments PCI1450", "TI 1450" }, + { 0x104c, 0xac52, "Texas Instruments PCI1451", "TI 1451" }, + { 0x104c, 0xac41, "Texas Instruments PCI4410", "TI 4410" }, + { 0x104c, 0xac40, "Texas Instruments PCI4450", "TI 4450" }, + { 0x104c, 0xac42, "Texas Instruments PCI4451", "TI 4451" }, + { 0x1217, 0x6729, "O2 Micro 6729", "O2Micro OZ6729" }, + { 0x1217, 0x673a, "O2 Micro 6730", "O2Micro OZ6730" }, + { 0x1217, 0x6832, "O2 Micro 6832/6833", "O2Micro OZ6832/OZ6833" }, + { 0x1217, 0x6836, "O2 Micro 6836/6860", "O2Micro OZ6836/OZ6860" }, + { 0x1217, 0x6872, "O2 Micro 6812", "O2Micro OZ6812" }, + { 0x1179, 0x0603, "Toshiba ToPIC95-A", "Toshiba ToPIC95-A" }, + { 0x1179, 0x060a, "Toshiba ToPIC95-B", "Toshiba ToPIC95-B" }, + { 0x1179, 0x060f, "Toshiba ToPIC97", "Toshiba ToPIC97" }, + { 0x1179, 0x0617, "Toshiba ToPIC100", "Toshiba ToPIC100" }, + { 0x119b, 0x1221, "Omega Micro 82C092G", "Omega Micro 82C092G" }, + { 0x1524, 0x1211, "ENE Technology Inc|CB1211 Cardbus Controller", "ENE CB1211" }, + { 0x1524, 0x1225, "ENE Technology Inc|CB1225 Cardbus Controller", "ENE CB1225" }, + { 0x1524, 0x1410, "ENE Technology Inc|CB1410 Cardbus Controller", "ENE CB1410" }, + { 0x1524, 0x1420, "ENE Technology Inc|CB1420 Cardbus Controller", "ENE CB1420" }, + { 0x8086, 0x1221, "Intel 82092AA", "Intel 82092AA" } + +}; +#define PCI_COUNT (sizeof(pci_id)/sizeof(pci_id_t)) + +static int pci_probe(void) +{ + char s[256], *name = NULL; + u_int device, vendor, i; + FILE *f; + + log_message("PCMCIA: probing PCI bus.."); + + f = fopen("/proc/bus/pci/devices", "r"); + + if (!f) { + log_message("where are you going without /proc/bus/pci/devices ??"); + return -1; + } + + while (fgets(s, 256, f) != NULL) { + u_int n = strtoul(s+5, NULL, 16); + vendor = (n >> 16); device = (n & 0xffff); + for (i = 0; i < PCI_COUNT; i++) + if ((vendor == pci_id[i].vendor) && + (device == pci_id[i].device)) break; + if (i < PCI_COUNT) { + name = pci_id[i].name; + break; + } + } + + fclose(f); + + if (name) { + log_message("\t%s found, 2 sockets.", name); + return 0; + } else { + log_message("\tnot found."); + return -ENODEV; + } +} + +/*====================================================================*/ + +#include +typedef u_short ioaddr_t; + +#include "i82365.h" +#include "cirrus.h" +#include "vg468.h" + +static ioaddr_t i365_base = 0x03e0; + +static u_char i365_get(u_short sock, u_short reg) +{ + u_char val = I365_REG(sock, reg); + outb(val, i365_base); val = inb(i365_base+1); + return val; +} + +static void i365_set(u_short sock, u_short reg, u_char data) +{ + u_char val = I365_REG(sock, reg); + outb(val, i365_base); outb(data, i365_base+1); +} + +static void i365_bset(u_short sock, u_short reg, u_char mask) +{ + u_char d = i365_get(sock, reg); + d |= mask; + i365_set(sock, reg, d); +} + +static void i365_bclr(u_short sock, u_short reg, u_char mask) +{ + u_char d = i365_get(sock, reg); + d &= ~mask; + i365_set(sock, reg, d); +} + +static int i365_probe(void) +{ + int val, sock, done; + char *name = "i82365sl"; + + log_message("PCMCIA: probing for Intel PCIC (ISA).."); + + sock = done = 0; + if (ioperm(i365_base, 4, 1)) { + log_perror("PCMCIA: ioperm"); + return -1; + } + ioperm(0x80, 1, 1); + for (; sock < 2; sock++) { + val = i365_get(sock, I365_IDENT); + switch (val) { + case 0x82: + name = "i82365sl A step"; + break; + case 0x83: + name = "i82365sl B step"; + break; + case 0x84: + name = "VLSI 82C146"; + break; + case 0x88: case 0x89: case 0x8a: + name = "IBM Clone"; + break; + case 0x8b: case 0x8c: + break; + default: + done = 1; + } + if (done) break; + } + + if (sock == 0) { + log_message("\tnot found."); + return -ENODEV; + } + + if ((sock == 2) && (strcmp(name, "VLSI 82C146") == 0)) + name = "i82365sl DF"; + + /* Check for Vadem chips */ + outb(0x0e, i365_base); + outb(0x37, i365_base); + i365_bset(0, VG468_MISC, VG468_MISC_VADEMREV); + val = i365_get(0, I365_IDENT); + if (val & I365_IDENT_VADEM) { + if ((val & 7) < 4) + name = "Vadem VG-468"; + else + name = "Vadem VG-469"; + i365_bclr(0, VG468_MISC, VG468_MISC_VADEMREV); + } + + /* Check for Cirrus CL-PD67xx chips */ + i365_set(0, PD67_CHIP_INFO, 0); + val = i365_get(0, PD67_CHIP_INFO); + if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) { + val = i365_get(0, PD67_CHIP_INFO); + if ((val & PD67_INFO_CHIP_ID) == 0) { + if (val & PD67_INFO_SLOTS) + name = "Cirrus CL-PD672x"; + else { + name = "Cirrus CL-PD6710"; + sock = 1; + } + i365_set(0, PD67_EXT_INDEX, 0xe5); + if (i365_get(0, PD67_EXT_INDEX) != 0xe5) + name = "VIA VT83C469"; + } + } + + log_message("\t%s found, %d sockets.", name, sock); + return 0; + +} /* i365_probe */ + + +/*====================================================================*/ + +#include "tcic.h" + +static u_char tcic_getb(ioaddr_t base, u_char reg) +{ + u_char val = inb(base+reg); + return val; +} + +static void tcic_setb(ioaddr_t base, u_char reg, u_char data) +{ + outb(data, base+reg); +} + +static u_short tcic_getw(ioaddr_t base, u_char reg) +{ + u_short val = inw(base+reg); + return val; +} + +static void tcic_setw(ioaddr_t base, u_char reg, u_short data) +{ + outw(data, base+reg); +} + +static u_short tcic_aux_getw(ioaddr_t base, u_short reg) +{ + u_char mode = (tcic_getb(base, TCIC_MODE) & TCIC_MODE_PGMMASK) | reg; + tcic_setb(base, TCIC_MODE, mode); + return tcic_getw(base, TCIC_AUX); +} + +static void tcic_aux_setw(ioaddr_t base, u_short reg, u_short data) +{ + u_char mode = (tcic_getb(base, TCIC_MODE) & TCIC_MODE_PGMMASK) | reg; + tcic_setb(base, TCIC_MODE, mode); + tcic_setw(base, TCIC_AUX, data); +} + +static int get_tcic_id(ioaddr_t base) +{ + u_short id; + tcic_aux_setw(base, TCIC_AUX_TEST, TCIC_TEST_DIAG); + id = tcic_aux_getw(base, TCIC_AUX_ILOCK); + id = (id & TCIC_ILOCKTEST_ID_MASK) >> TCIC_ILOCKTEST_ID_SH; + tcic_aux_setw(base, TCIC_AUX_TEST, 0); + return id; +} + +static int tcic_probe_at(ioaddr_t base) +{ + int i; + u_short old; + + /* Anything there?? */ + for (i = 0; i < 0x10; i += 2) + if (tcic_getw(base, i) == 0xffff) + return -1; + + log_message("\tat %#3.3x: ", base); + + /* Try to reset the chip */ + tcic_setw(base, TCIC_SCTRL, TCIC_SCTRL_RESET); + tcic_setw(base, TCIC_SCTRL, 0); + + /* Can we set the addr register? */ + old = tcic_getw(base, TCIC_ADDR); + tcic_setw(base, TCIC_ADDR, 0); + if (tcic_getw(base, TCIC_ADDR) != 0) { + tcic_setw(base, TCIC_ADDR, old); + return -2; + } + + tcic_setw(base, TCIC_ADDR, 0xc3a5); + if (tcic_getw(base, TCIC_ADDR) != 0xc3a5) + return -3; + + return 2; +} + +static int tcic_probe(void) +{ + int sock, id; + + log_message("PCMCIA: probing for Databook TCIC-2 (ISA).."); + + if (ioperm(TCIC_BASE, 16, 1)) { + log_perror("PCMCIA: ioperm"); + return -1; + } + + ioperm(0x80, 1, 1); + sock = tcic_probe_at(TCIC_BASE); + + if (sock <= 0) { + log_message("\tnot found."); + return -ENODEV; + } + + id = get_tcic_id(TCIC_BASE); + switch (id) { + case TCIC_ID_DB86082: + log_message("DB86082"); break; + case TCIC_ID_DB86082A: + log_message("DB86082A"); break; + case TCIC_ID_DB86084: + log_message("DB86084"); break; + case TCIC_ID_DB86084A: + log_message("DB86084A"); break; + case TCIC_ID_DB86072: + log_message("DB86072"); break; + case TCIC_ID_DB86184: + log_message("DB86184"); break; + case TCIC_ID_DB86082B: + log_message("DB86082B"); break; + default: + log_message("Unknown TCIC-2 ID 0x%02x", id); + } + log_message("\tfound at %#6x, %d sockets.\n", TCIC_BASE, sock); + + return 0; + +} /* tcic_probe */ + + +/*====================================================================*/ + +char * pcmcia_probe(void) +{ + if (!pci_probe()) + return "yenta_socket"; + else if (!i365_probe()) + return "i82365"; + else if (!tcic_probe()) + return "tcic"; + else + return NULL; +} diff --git a/pcmcia/tcic.h b/pcmcia/tcic.h new file mode 100644 index 0000000..92347ce --- /dev/null +++ b/pcmcia/tcic.h @@ -0,0 +1,266 @@ +/* + * tcic.h 1.14 2000/06/12 21:29:37 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_TCIC_H +#define _LINUX_TCIC_H + +#define TCIC_BASE 0x240 + +/* offsets of registers from TCIC_BASE */ +#define TCIC_DATA 0x00 +#define TCIC_ADDR 0x02 +#define TCIC_SCTRL 0x06 +#define TCIC_SSTAT 0x07 +#define TCIC_MODE 0x08 +#define TCIC_PWR 0x09 +#define TCIC_EDC 0x0A +#define TCIC_ICSR 0x0C +#define TCIC_IENA 0x0D +#define TCIC_AUX 0x0E + +#define TCIC_SS_SHFT 12 +#define TCIC_SS_MASK 0x7000 + +/* Flags for TCIC_ADDR */ +#define TCIC_ADR2_REG 0x8000 +#define TCIC_ADR2_INDREG 0x0800 + +#define TCIC_ADDR_REG 0x80000000 +#define TCIC_ADDR_SS_SHFT (TCIC_SS_SHFT+16) +#define TCIC_ADDR_SS_MASK (TCIC_SS_MASK<<16) +#define TCIC_ADDR_INDREG 0x08000000 +#define TCIC_ADDR_IO 0x04000000 +#define TCIC_ADDR_MASK 0x03ffffff + +/* Flags for TCIC_SCTRL */ +#define TCIC_SCTRL_ENA 0x01 +#define TCIC_SCTRL_INCMODE 0x18 +#define TCIC_SCTRL_INCMODE_HOLD 0x00 +#define TCIC_SCTRL_INCMODE_WORD 0x08 +#define TCIC_SCTRL_INCMODE_REG 0x10 +#define TCIC_SCTRL_INCMODE_AUTO 0x18 +#define TCIC_SCTRL_EDCSUM 0x20 +#define TCIC_SCTRL_RESET 0x80 + +/* Flags for TCIC_SSTAT */ +#define TCIC_SSTAT_6US 0x01 +#define TCIC_SSTAT_10US 0x02 +#define TCIC_SSTAT_PROGTIME 0x04 +#define TCIC_SSTAT_LBAT1 0x08 +#define TCIC_SSTAT_LBAT2 0x10 +#define TCIC_SSTAT_RDY 0x20 /* Inverted */ +#define TCIC_SSTAT_WP 0x40 +#define TCIC_SSTAT_CD 0x80 /* Card detect */ + +/* Flags for TCIC_MODE */ +#define TCIC_MODE_PGMMASK 0x1f +#define TCIC_MODE_NORMAL 0x00 +#define TCIC_MODE_PGMWR 0x01 +#define TCIC_MODE_PGMRD 0x02 +#define TCIC_MODE_PGMCE 0x04 +#define TCIC_MODE_PGMDBW 0x08 +#define TCIC_MODE_PGMWORD 0x10 +#define TCIC_MODE_AUXSEL_MASK 0xe0 + +/* Registers accessed through TCIC_AUX, by setting TCIC_MODE */ +#define TCIC_AUX_TCTL (0<<5) +#define TCIC_AUX_PCTL (1<<5) +#define TCIC_AUX_WCTL (2<<5) +#define TCIC_AUX_EXTERN (3<<5) +#define TCIC_AUX_PDATA (4<<5) +#define TCIC_AUX_SYSCFG (5<<5) +#define TCIC_AUX_ILOCK (6<<5) +#define TCIC_AUX_TEST (7<<5) + +/* Flags for TCIC_PWR */ +#define TCIC_PWR_VCC(sock) (0x01<<(sock)) +#define TCIC_PWR_VCC_MASK 0x03 +#define TCIC_PWR_VPP(sock) (0x08<<(sock)) +#define TCIC_PWR_VPP_MASK 0x18 +#define TCIC_PWR_CLIMENA 0x40 +#define TCIC_PWR_CLIMSTAT 0x80 + +/* Flags for TCIC_ICSR */ +#define TCIC_ICSR_CLEAR 0x01 +#define TCIC_ICSR_SET 0x02 +#define TCIC_ICSR_JAM (TCIC_ICSR_CLEAR|TCIC_ICSR_SET) +#define TCIC_ICSR_STOPCPU 0x04 +#define TCIC_ICSR_ILOCK 0x08 +#define TCIC_ICSR_PROGTIME 0x10 +#define TCIC_ICSR_ERR 0x20 +#define TCIC_ICSR_CDCHG 0x40 +#define TCIC_ICSR_IOCHK 0x80 + +/* Flags for TCIC_IENA */ +#define TCIC_IENA_CFG_MASK 0x03 +#define TCIC_IENA_CFG_OFF 0x00 /* disabled */ +#define TCIC_IENA_CFG_OD 0x01 /* active low, open drain */ +#define TCIC_IENA_CFG_LOW 0x02 /* active low, totem pole */ +#define TCIC_IENA_CFG_HIGH 0x03 /* active high, totem pole */ +#define TCIC_IENA_ILOCK 0x08 +#define TCIC_IENA_PROGTIME 0x10 +#define TCIC_IENA_ERR 0x20 /* overcurrent or iochk */ +#define TCIC_IENA_CDCHG 0x40 + +/* Flags for TCIC_AUX_WCTL */ +#define TCIC_WAIT_COUNT_MASK 0x001f +#define TCIC_WAIT_ASYNC 0x0020 +#define TCIC_WAIT_SENSE 0x0040 +#define TCIC_WAIT_SRC 0x0080 +#define TCIC_WCTL_WR 0x0100 +#define TCIC_WCTL_RD 0x0200 +#define TCIC_WCTL_CE 0x0400 +#define TCIC_WCTL_LLBAT1 0x0800 +#define TCIC_WCTL_LLBAT2 0x1000 +#define TCIC_WCTL_LRDY 0x2000 +#define TCIC_WCTL_LWP 0x4000 +#define TCIC_WCTL_LCD 0x8000 + +/* Flags for TCIC_AUX_SYSCFG */ +#define TCIC_SYSCFG_IRQ_MASK 0x000f +#define TCIC_SYSCFG_MCSFULL 0x0010 +#define TCIC_SYSCFG_IO1723 0x0020 +#define TCIC_SYSCFG_MCSXB 0x0040 +#define TCIC_SYSCFG_ICSXB 0x0080 +#define TCIC_SYSCFG_NOPDN 0x0100 +#define TCIC_SYSCFG_MPSEL_SHFT 9 +#define TCIC_SYSCFG_MPSEL_MASK 0x0e00 +#define TCIC_SYSCFG_MPSENSE 0x2000 +#define TCIC_SYSCFG_AUTOBUSY 0x4000 +#define TCIC_SYSCFG_ACC 0x8000 + +#define TCIC_ILOCK_OUT 0x01 +#define TCIC_ILOCK_SENSE 0x02 +#define TCIC_ILOCK_CRESET 0x04 +#define TCIC_ILOCK_CRESENA 0x08 +#define TCIC_ILOCK_CWAIT 0x10 +#define TCIC_ILOCK_CWAITSNS 0x20 +#define TCIC_ILOCK_HOLD_MASK 0xc0 +#define TCIC_ILOCK_HOLD_CCLK 0xc0 + +#define TCIC_ILOCKTEST_ID_SH 8 +#define TCIC_ILOCKTEST_ID_MASK 0x7f00 +#define TCIC_ILOCKTEST_MCIC_1 0x8000 + +#define TCIC_ID_DB86082 0x02 +#define TCIC_ID_DB86082A 0x03 +#define TCIC_ID_DB86084 0x04 +#define TCIC_ID_DB86084A 0x08 +#define TCIC_ID_DB86072 0x15 +#define TCIC_ID_DB86184 0x14 +#define TCIC_ID_DB86082B 0x17 + +#define TCIC_TEST_DIAG 0x8000 + +/* + * Indirectly addressed registers + */ + +#define TCIC_SCF1(sock) ((sock)<<3) +#define TCIC_SCF2(sock) (((sock)<<3)+2) + +/* Flags for SCF1 */ +#define TCIC_SCF1_IRQ_MASK 0x000f +#define TCIC_SCF1_IRQ_OFF 0x0000 +#define TCIC_SCF1_IRQOC 0x0010 +#define TCIC_SCF1_PCVT 0x0020 +#define TCIC_SCF1_IRDY 0x0040 +#define TCIC_SCF1_ATA 0x0080 +#define TCIC_SCF1_DMA_SHIFT 8 +#define TCIC_SCF1_DMA_MASK 0x0700 +#define TCIC_SCF1_DMA_OFF 0 +#define TCIC_SCF1_DREQ2 2 +#define TCIC_SCF1_IOSTS 0x0800 +#define TCIC_SCF1_SPKR 0x1000 +#define TCIC_SCF1_FINPACK 0x2000 +#define TCIC_SCF1_DELWR 0x4000 +#define TCIC_SCF1_HD7IDE 0x8000 + +/* Flags for SCF2 */ +#define TCIC_SCF2_RI 0x0001 +#define TCIC_SCF2_IDBR 0x0002 +#define TCIC_SCF2_MDBR 0x0004 +#define TCIC_SCF2_MLBAT1 0x0008 +#define TCIC_SCF2_MLBAT2 0x0010 +#define TCIC_SCF2_MRDY 0x0020 +#define TCIC_SCF2_MWP 0x0040 +#define TCIC_SCF2_MCD 0x0080 +#define TCIC_SCF2_MALL 0x00f8 + +/* Indirect addresses for memory window registers */ +#define TCIC_MWIN(sock,map) (0x100+(((map)+((sock)<<2))<<3)) +#define TCIC_MBASE_X 2 +#define TCIC_MMAP_X 4 +#define TCIC_MCTL_X 6 + +#define TCIC_MBASE_4K_BIT 0x4000 +#define TCIC_MBASE_HA_SHFT 12 +#define TCIC_MBASE_HA_MASK 0x0fff + +#define TCIC_MMAP_REG 0x8000 +#define TCIC_MMAP_CA_SHFT 12 +#define TCIC_MMAP_CA_MASK 0x3fff + +#define TCIC_MCTL_WSCNT_MASK 0x001f +#define TCIC_MCTL_WCLK 0x0020 +#define TCIC_MCTL_WCLK_CCLK 0x0000 +#define TCIC_MCTL_WCLK_BCLK 0x0020 +#define TCIC_MCTL_QUIET 0x0040 +#define TCIC_MCTL_WP 0x0080 +#define TCIC_MCTL_ACC 0x0100 +#define TCIC_MCTL_KE 0x0200 +#define TCIC_MCTL_EDC 0x0400 +#define TCIC_MCTL_B8 0x0800 +#define TCIC_MCTL_SS_SHFT TCIC_SS_SHFT +#define TCIC_MCTL_SS_MASK TCIC_SS_MASK +#define TCIC_MCTL_ENA 0x8000 + +/* Indirect addresses for I/O window registers */ +#define TCIC_IWIN(sock,map) (0x200+(((map)+((sock)<<1))<<2)) +#define TCIC_IBASE_X 0 +#define TCIC_ICTL_X 2 + +#define TCIC_ICTL_WSCNT_MASK TCIC_MCTL_WSCNT_MASK +#define TCIC_ICTL_QUIET TCIC_MCTL_QUIET +#define TCIC_ICTL_1K 0x0080 +#define TCIC_ICTL_PASS16 0x0100 +#define TCIC_ICTL_ACC TCIC_MCTL_ACC +#define TCIC_ICTL_TINY 0x0200 +#define TCIC_ICTL_B16 0x0400 +#define TCIC_ICTL_B8 TCIC_MCTL_B8 +#define TCIC_ICTL_BW_MASK (TCIC_ICTL_B16|TCIC_ICTL_B8) +#define TCIC_ICTL_BW_DYN 0 +#define TCIC_ICTL_BW_8 TCIC_ICTL_B8 +#define TCIC_ICTL_BW_16 TCIC_ICTL_B16 +#define TCIC_ICTL_BW_ATA (TCIC_ICTL_B16|TCIC_ICTL_B8) +#define TCIC_ICTL_SS_SHFT TCIC_SS_SHFT +#define TCIC_ICTL_SS_MASK TCIC_SS_MASK +#define TCIC_ICTL_ENA TCIC_MCTL_ENA + +#endif /* _LINUX_TCIC_H */ diff --git a/pcmcia/version.h b/pcmcia/version.h new file mode 100644 index 0000000..dbba226 --- /dev/null +++ b/pcmcia/version.h @@ -0,0 +1,13 @@ +/* version.h 1.114 2002/11/06 05:23:52 (David Hinds) */ + +#define CS_PKG_RELEASE "3.2.4" +#define CS_PKG_RELEASE_CODE 0x3204 + +#define VERSION(v,p,s) (((v)<<16)+(p<<8)+s) + +#ifdef CONFIG_PCMCIA +#include_next +#else +#define CS_RELEASE CS_PKG_RELEASE +#define CS_RELEASE_CODE CS_PKG_RELEASE_CODE +#endif diff --git a/pcmcia/vg468.h b/pcmcia/vg468.h new file mode 100644 index 0000000..bb5faae --- /dev/null +++ b/pcmcia/vg468.h @@ -0,0 +1,112 @@ +/* + * vg468.h 1.13 2000/06/12 21:29:37 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#ifndef _LINUX_VG468_H +#define _LINUX_VG468_H + +/* Special bit in I365_IDENT used for Vadem chip detection */ +#define I365_IDENT_VADEM 0x08 + +/* Special definitions in I365_POWER */ +#define VG468_VPP2_MASK 0x0c +#define VG468_VPP2_5V 0x04 +#define VG468_VPP2_12V 0x08 + +/* Unique Vadem registers */ +#define VG469_VSENSE 0x1f /* Card voltage sense */ +#define VG469_VSELECT 0x2f /* Card voltage select */ +#define VG468_CTL 0x38 /* Control register */ +#define VG468_TIMER 0x39 /* Timer control */ +#define VG468_MISC 0x3a /* Miscellaneous */ +#define VG468_GPIO_CFG 0x3b /* GPIO configuration */ +#define VG469_EXT_MODE 0x3c /* Extended mode register */ +#define VG468_SELECT 0x3d /* Programmable chip select */ +#define VG468_SELECT_CFG 0x3e /* Chip select configuration */ +#define VG468_ATA 0x3f /* ATA control */ + +/* Flags for VG469_VSENSE */ +#define VG469_VSENSE_A_VS1 0x01 +#define VG469_VSENSE_A_VS2 0x02 +#define VG469_VSENSE_B_VS1 0x04 +#define VG469_VSENSE_B_VS2 0x08 + +/* Flags for VG469_VSELECT */ +#define VG469_VSEL_VCC 0x03 +#define VG469_VSEL_5V 0x00 +#define VG469_VSEL_3V 0x03 +#define VG469_VSEL_MAX 0x0c +#define VG469_VSEL_EXT_STAT 0x10 +#define VG469_VSEL_EXT_BUS 0x20 +#define VG469_VSEL_MIXED 0x40 +#define VG469_VSEL_ISA 0x80 + +/* Flags for VG468_CTL */ +#define VG468_CTL_SLOW 0x01 /* 600ns memory timing */ +#define VG468_CTL_ASYNC 0x02 /* Asynchronous bus clocking */ +#define VG468_CTL_TSSI 0x08 /* Tri-state some outputs */ +#define VG468_CTL_DELAY 0x10 /* Card detect debounce */ +#define VG468_CTL_INPACK 0x20 /* Obey INPACK signal? */ +#define VG468_CTL_POLARITY 0x40 /* VCCEN polarity */ +#define VG468_CTL_COMPAT 0x80 /* Compatibility stuff */ + +#define VG469_CTL_WS_COMPAT 0x04 /* Wait state compatibility */ +#define VG469_CTL_STRETCH 0x10 /* LED stretch */ + +/* Flags for VG468_TIMER */ +#define VG468_TIMER_ZEROPWR 0x10 /* Zero power control */ +#define VG468_TIMER_SIGEN 0x20 /* Power up */ +#define VG468_TIMER_STATUS 0x40 /* Activity timer status */ +#define VG468_TIMER_RES 0x80 /* Timer resolution */ +#define VG468_TIMER_MASK 0x0f /* Activity timer timeout */ + +/* Flags for VG468_MISC */ +#define VG468_MISC_GPIO 0x04 /* General-purpose IO */ +#define VG468_MISC_DMAWSB 0x08 /* DMA wait state control */ +#define VG469_MISC_LEDENA 0x10 /* LED enable */ +#define VG468_MISC_VADEMREV 0x40 /* Vadem revision control */ +#define VG468_MISC_UNLOCK 0x80 /* Unique register lock */ + +/* Flags for VG469_EXT_MODE_A */ +#define VG469_MODE_VPPST 0x03 /* Vpp steering control */ +#define VG469_MODE_INT_SENSE 0x04 /* Internal voltage sense */ +#define VG469_MODE_CABLE 0x08 +#define VG469_MODE_COMPAT 0x10 /* i82365sl B or DF step */ +#define VG469_MODE_TEST 0x20 +#define VG469_MODE_RIO 0x40 /* Steer RIO to INTR? */ + +/* Flags for VG469_EXT_MODE_B */ +#define VG469_MODE_B_3V 0x01 /* 3.3v for socket B */ + +/* Data structure for tracking vendor-specific state */ +typedef struct vg46x_state_t { + u_char ctl; /* VG468_CTL */ + u_char ema; /* VG468_EXT_MODE_A */ +} vg46x_state_t; + +#endif /* _LINUX_VG468_H */ diff --git a/pcmcia/yacc_config.c b/pcmcia/yacc_config.c new file mode 100644 index 0000000..f730417 --- /dev/null +++ b/pcmcia/yacc_config.c @@ -0,0 +1,1148 @@ +#ifndef lint +static char const +yyrcsid[] = "$FreeBSD: src/usr.bin/yacc/skeleton.c,v 1.28 2000/01/17 02:04:06 bde Exp $"; +#endif +#include +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define YYLEX yylex() +#define YYEMPTY -1 +#define yyclearin (yychar=(YYEMPTY)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING() (yyerrflag!=0) +static int yygrowstack(); +#define YYPREFIX "yy" +#line 2 "yacc_config.y" +/* + * yacc_config.y 1.57 2002/08/19 03:19:56 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "cardmgr.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; + +void yyerror(char *msg, ...); + +static int add_binding(card_info_t *card, char *name, char *class, int fn); +static int add_module(device_info_t *card, char *name); + +#line 65 "yacc_config.y" +typedef union { + char *str; + u_long num; + struct device_info_t *device; + struct card_info_t *card; + struct mtd_ident_t *mtd; + struct adjust_list_t *adjust; +} YYSTYPE; +#line 82 "y.tab.c" +#define YYERRCODE 256 +#define DEVICE 257 +#define CARD 258 +#define ANONYMOUS 259 +#define TUPLE 260 +#define MANFID 261 +#define VERSION 262 +#define FUNCTION 263 +#define PCI 264 +#define BIND 265 +#define CIS 266 +#define TO 267 +#define NEEDS_MTD 268 +#define MODULE 269 +#define OPTS 270 +#define CLASS 271 +#define REGION 272 +#define JEDEC 273 +#define DTYPE 274 +#define DEFAULT 275 +#define MTD 276 +#define INCLUDE 277 +#define EXCLUDE 278 +#define RESERVE 279 +#define IRQ_NO 280 +#define PORT 281 +#define MEMORY 282 +#define STRING 283 +#define NUMBER 284 +#define SOURCE 285 +const short yylhs[] = { -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, + 9, 10, 11, 12, 12, 13, 15, 14, 14, 14, + 14, 14, 14, 14, 14, 4, 21, 5, 5, 5, + 6, 16, 16, 16, 16, 18, 17, 19, 20, 20, + 22, +}; +const short yylen[] = { 2, + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 3, 2, 4, 4, 2, 1, 1, 1, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 7, 5, 5, 3, 3, 3, 3, 3, 5, 5, + 7, 3, 5, 5, 7, 2, 4, 3, 3, 3, + 3, 2, 1, 1, 1, 3, 4, 2, 3, 3, + 4, +}; +const short yydefred[] = { 1, + 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 0, 0, 18, 0, 20, 0, 22, 23, 24, + 25, 0, 27, 0, 29, 0, 54, 53, 55, 0, + 6, 7, 17, 21, 0, 52, 0, 0, 0, 0, + 10, 11, 12, 0, 46, 0, 0, 0, 0, 30, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 58, 0, 0, 0, 0, 14, 0, 0, 13, + 48, 51, 49, 50, 0, 0, 34, 36, 0, 0, + 37, 35, 0, 0, 56, 59, 60, 47, 61, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 57, 15, + 16, 0, 32, 33, 40, 0, 44, 0, 0, 0, + 0, 31, 41, 45, +}; +const short yydgoto[] = { 1, + 12, 41, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, +}; +const short yysindex[] = { 0, + -251, 0, -283, -275, -266, -261, -240, -245, -245, -245, + 0, -11, -239, 0, -42, 0, -250, 0, 0, 0, + 0, 2, 0, 3, 0, -234, 0, 0, 0, -226, + 0, 0, 0, 0, -222, 0, -221, -233, -232, -231, + 0, 0, 0, -245, 0, -229, -228, -227, -225, 0, + -224, -220, -218, -217, -216, -214, -213, -212, -211, -210, + -208, 0, -206, -205, -204, -203, 0, 5, 12, 0, + 0, 0, 0, 0, 15, 18, 0, 0, 19, -248, + 0, 0, -247, -202, 0, 0, 0, 0, 0, -201, + -200, -199, -198, -197, -196, -194, -192, -193, 0, 0, + 0, 22, 0, 0, 0, -186, 0, -174, -189, -188, + -187, 0, 0, 0, +}; +const short yyrindex[] = { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 192, 243, 0, 175, 0, 209, 0, 0, 0, + 0, 121, 0, 151, 0, 0, 0, 0, 0, 226, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 61, 0, 91, 0, 0, + 0, 0, 0, 0, +}; +const short yygindex[] = { 0, + 0, -6, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, +}; +#define YYTABLESIZE 528 +const short yytable[] = { 33, + 38, 49, 42, 43, 2, 3, 4, 34, 50, 51, + 52, 53, 54, 55, 56, 57, 35, 5, 95, 97, + 6, 36, 96, 98, 7, 8, 9, 10, 45, 46, + 42, 47, 44, 11, 38, 39, 40, 70, 60, 61, + 62, 63, 37, 64, 38, 58, 59, 65, 66, 90, + 67, 68, 69, 71, 72, 73, 91, 74, 92, 75, + 39, 93, 94, 76, 77, 109, 78, 79, 80, 81, + 82, 83, 0, 84, 42, 85, 86, 87, 88, 89, + 110, 99, 100, 101, 102, 103, 104, 105, 106, 108, + 43, 107, 111, 112, 0, 113, 114, 0, 0, 0, + 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 4, 0, 48, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 0, 0, 38, + 0, 0, 38, 0, 0, 0, 38, 38, 38, 38, + 0, 0, 0, 0, 0, 38, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 0, 0, 42, + 0, 0, 42, 0, 0, 0, 42, 42, 42, 42, + 0, 0, 0, 0, 0, 42, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 0, 0, 39, + 0, 0, 39, 0, 0, 0, 39, 39, 39, 39, + 0, 0, 0, 0, 0, 39, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 0, 0, 43, + 0, 0, 43, 0, 0, 0, 43, 43, 43, 43, + 0, 0, 0, 0, 0, 43, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 0, 0, 26, + 0, 0, 26, 0, 0, 0, 26, 26, 26, 26, + 0, 0, 0, 0, 0, 26, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 0, 0, 28, + 0, 0, 28, 0, 0, 0, 28, 28, 28, 28, + 19, 19, 19, 0, 0, 28, 0, 0, 0, 0, + 0, 0, 19, 19, 0, 19, 19, 2, 2, 2, + 19, 19, 19, 19, 0, 0, 0, 0, 0, 19, + 2, 0, 0, 2, 5, 5, 5, 2, 2, 2, + 2, 0, 0, 0, 0, 0, 2, 5, 0, 0, + 5, 4, 4, 4, 5, 5, 5, 5, 0, 0, + 0, 0, 0, 5, 4, 0, 0, 4, 3, 3, + 3, 4, 4, 4, 4, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 3, 0, 0, 0, 3, 3, + 3, 3, 0, 0, 0, 0, 0, 3, +}; +const short yycheck[] = { 283, + 0, 44, 9, 10, 256, 257, 258, 283, 259, 260, + 261, 262, 263, 264, 265, 266, 283, 269, 267, 267, + 272, 283, 271, 271, 276, 277, 278, 279, 268, 269, + 0, 271, 44, 285, 280, 281, 282, 44, 273, 274, + 275, 276, 283, 270, 44, 44, 44, 270, 270, 45, + 284, 284, 284, 283, 283, 283, 45, 283, 44, 284, + 0, 44, 44, 284, 283, 44, 284, 284, 283, 283, + 283, 283, -1, 284, 44, 284, 283, 283, 283, 283, + 267, 284, 284, 284, 284, 284, 284, 284, 283, 283, + 0, 284, 267, 283, -1, 284, 284, -1, -1, -1, + -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 0, -1, 270, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, -1, -1, 269, + -1, -1, 272, -1, -1, -1, 276, 277, 278, 279, + -1, -1, -1, -1, -1, 285, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, -1, -1, 269, + -1, -1, 272, -1, -1, -1, 276, 277, 278, 279, + -1, -1, -1, -1, -1, 285, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, -1, -1, 269, + -1, -1, 272, -1, -1, -1, 276, 277, 278, 279, + -1, -1, -1, -1, -1, 285, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, -1, -1, 269, + -1, -1, 272, -1, -1, -1, 276, 277, 278, 279, + -1, -1, -1, -1, -1, 285, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, -1, -1, 269, + -1, -1, 272, -1, -1, -1, 276, 277, 278, 279, + -1, -1, -1, -1, -1, 285, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, -1, -1, 269, + -1, -1, 272, -1, -1, -1, 276, 277, 278, 279, + 256, 257, 258, -1, -1, 285, -1, -1, -1, -1, + -1, -1, 268, 269, -1, 271, 272, 256, 257, 258, + 276, 277, 278, 279, -1, -1, -1, -1, -1, 285, + 269, -1, -1, 272, 256, 257, 258, 276, 277, 278, + 279, -1, -1, -1, -1, -1, 285, 269, -1, -1, + 272, 256, 257, 258, 276, 277, 278, 279, -1, -1, + -1, -1, -1, 285, 269, -1, -1, 272, 256, 257, + 258, 276, 277, 278, 279, -1, -1, -1, -1, -1, + 285, -1, -1, -1, 272, -1, -1, -1, 276, 277, + 278, 279, -1, -1, -1, -1, -1, 285, +}; +#define YYFINAL 1 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 285 +#if YYDEBUG +const char * const yyname[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,"','","'-'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"DEVICE","CARD", +"ANONYMOUS","TUPLE","MANFID","VERSION","FUNCTION","PCI","BIND","CIS","TO", +"NEEDS_MTD","MODULE","OPTS","CLASS","REGION","JEDEC","DTYPE","DEFAULT","MTD", +"INCLUDE","EXCLUDE","RESERVE","IRQ_NO","PORT","MEMORY","STRING","NUMBER", +"SOURCE", +}; +const char * const yyrule[] = { +"$accept : list", +"list :", +"list : list adjust", +"list : list device", +"list : list mtd", +"list : list card", +"list : list opts", +"list : list mtd_opts", +"list : list SOURCE", +"list : list error", +"adjust : INCLUDE resource", +"adjust : EXCLUDE resource", +"adjust : RESERVE resource", +"adjust : adjust ',' resource", +"resource : IRQ_NO NUMBER", +"resource : PORT NUMBER '-' NUMBER", +"resource : MEMORY NUMBER '-' NUMBER", +"device : DEVICE STRING", +"device : needs_mtd", +"device : module", +"device : class", +"card : CARD STRING", +"card : anonymous", +"card : tuple", +"card : manfid", +"card : pci", +"card : version", +"card : function", +"card : bind", +"card : cis", +"anonymous : card ANONYMOUS", +"tuple : card TUPLE NUMBER ',' NUMBER ',' STRING", +"manfid : card MANFID NUMBER ',' NUMBER", +"pci : card PCI NUMBER ',' NUMBER", +"version : card VERSION STRING", +"version : version ',' STRING", +"function : card FUNCTION NUMBER", +"cis : card CIS STRING", +"bind : card BIND STRING", +"bind : card BIND STRING CLASS STRING", +"bind : card BIND STRING TO NUMBER", +"bind : card BIND STRING CLASS STRING TO NUMBER", +"bind : bind ',' STRING", +"bind : bind ',' STRING CLASS STRING", +"bind : bind ',' STRING TO NUMBER", +"bind : bind ',' STRING CLASS STRING TO NUMBER", +"needs_mtd : device NEEDS_MTD", +"opts : MODULE STRING OPTS STRING", +"module : device MODULE STRING", +"module : module OPTS STRING", +"module : module ',' STRING", +"class : device CLASS STRING", +"region : REGION STRING", +"region : dtype", +"region : jedec", +"region : default", +"dtype : region DTYPE NUMBER", +"jedec : region JEDEC NUMBER NUMBER", +"default : region DEFAULT", +"mtd : region MTD STRING", +"mtd : mtd OPTS STRING", +"mtd_opts : MTD STRING OPTS STRING", +}; +#endif +#if YYDEBUG +#include +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 10000 +#define YYMAXDEPTH 10000 +#endif +#endif +#define YYINITSTACKSIZE 200 +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short *yyss; +short *yysslim; +YYSTYPE *yyvs; +int yystacksize; +#line 490 "yacc_config.y" +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); +} + +static int add_binding(card_info_t *card, char *name, char *class, int fn) +{ + device_info_t *dev = root_device; + if (card->bindings == MAX_BINDINGS) { + yyerror("too many bindings\n"); + return -1; + } + for (; dev; dev = dev->next) + if (strcmp((char *)dev->dev_info, name) == 0) break; + if (dev == NULL) { + yyerror("unknown device '%s'", name); + return -1; + } + card->device[card->bindings] = dev; + card->dev_fn[card->bindings] = fn; + if (class) + card->class[card->bindings] = strdup(class); + card->bindings++; + free(name); + return 0; +} + +static int add_module(device_info_t *dev, char *name) +{ + if (dev->modules == MAX_MODULES) { + yyerror("too many modules for '%s'", dev->dev_info); + return -1; + } + dev->module[dev->modules] = name; + dev->opts[dev->modules] = NULL; + dev->modules++; + return 0; +} + +#if YYDEBUG +adjust_list_t *root_adjust = NULL; +device_info_t *root_device = NULL; +card_info_t *root_card = NULL, *blank_card = NULL, *root_func = NULL; +mtd_ident_t *root_mtd = NULL, *default_mtd = NULL; + +void main(int argc, char *argv[]) +{ + yydebug = 1; + if (argc > 1) + parse_configfile(argv[1]); +} +#endif +#line 470 "y.tab.c" +/* allocate initial stack or double stack size, up to YYMAXDEPTH */ +static int yygrowstack() +{ + int newsize, i; + short *newss; + YYSTYPE *newvs; + + if ((newsize = yystacksize) == 0) + newsize = YYINITSTACKSIZE; + else if (newsize >= YYMAXDEPTH) + return -1; + else if ((newsize *= 2) > YYMAXDEPTH) + newsize = YYMAXDEPTH; + i = yyssp - yyss; + newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) : + (short *)malloc(newsize * sizeof *newss); + if (newss == NULL) + return -1; + yyss = newss; + yyssp = newss + i; + newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) : + (YYSTYPE *)malloc(newsize * sizeof *newvs); + if (newvs == NULL) + return -1; + yyvs = newvs; + yyvsp = newvs + i; + yystacksize = newsize; + yysslim = yyss + newsize - 1; + return 0; +} + +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab + +#ifndef YYPARSE_PARAM +#if defined(__cplusplus) || __STDC__ +#define YYPARSE_PARAM_ARG void +#define YYPARSE_PARAM_DECL +#else /* ! ANSI-C/C++ */ +#define YYPARSE_PARAM_ARG +#define YYPARSE_PARAM_DECL +#endif /* ANSI-C/C++ */ +#else /* YYPARSE_PARAM */ +#ifndef YYPARSE_PARAM_TYPE +#define YYPARSE_PARAM_TYPE void * +#endif +#if defined(__cplusplus) || __STDC__ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM_TYPE YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#else /* ! ANSI-C/C++ */ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM +#define YYPARSE_PARAM_DECL YYPARSE_PARAM_TYPE YYPARSE_PARAM; +#endif /* ANSI-C/C++ */ +#endif /* ! YYPARSE_PARAM */ + +int +yyparse (YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + register int yym, yyn, yystate; +#if YYDEBUG + register const char *yys; + + if ((yys = getenv("YYDEBUG"))) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + if (yyss == NULL && yygrowstack()) goto yyoverflow; + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if ((yyn = yydefred[yystate])) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#if defined(lint) || defined(__GNUC__) + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#if defined(lint) || defined(__GNUC__) + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 2: +#line 84 "yacc_config.y" +{ + adjust_list_t **tail = &root_adjust; + while (*tail != NULL) tail = &(*tail)->next; + *tail = yyvsp[0].adjust; + } +break; +case 3: +#line 90 "yacc_config.y" +{ + yyvsp[0].device->next = root_device; + root_device = yyvsp[0].device; + } +break; +case 4: +#line 95 "yacc_config.y" +{ + if (yyvsp[0].mtd->mtd_type == 0) { + yyerror("no ID method for '%s'", yyvsp[0].mtd->name); + YYERROR; + } + if (yyvsp[0].mtd->module == NULL) { + yyerror("no MTD module for '%s'", yyvsp[0].mtd->name); + YYERROR; + } + yyvsp[0].mtd->next = root_mtd; + root_mtd = yyvsp[0].mtd; + } +break; +case 5: +#line 108 "yacc_config.y" +{ + if (yyvsp[0].card->ident_type == 0) { + yyerror("no ID method for '%s'", yyvsp[0].card->name); + YYERROR; + } + if (yyvsp[0].card->bindings == 0) { + yyerror("no driver bindings for '%s'", yyvsp[0].card->name); + YYERROR; + } + if (yyvsp[0].card->ident_type == FUNC_IDENT) { + yyvsp[0].card->next = root_func; + root_func = yyvsp[0].card; + } else { + yyvsp[0].card->next = root_card; + root_card = yyvsp[0].card; + } + } +break; +case 10: +#line 132 "yacc_config.y" +{ + yyvsp[0].adjust->adj.Action = ADD_MANAGED_RESOURCE; + yyval.adjust = yyvsp[0].adjust; + } +break; +case 11: +#line 137 "yacc_config.y" +{ + yyvsp[0].adjust->adj.Action = REMOVE_MANAGED_RESOURCE; + yyval.adjust = yyvsp[0].adjust; + } +break; +case 12: +#line 142 "yacc_config.y" +{ + yyvsp[0].adjust->adj.Action = ADD_MANAGED_RESOURCE; + yyvsp[0].adjust->adj.Attributes |= RES_RESERVED; + yyval.adjust = yyvsp[0].adjust; + } +break; +case 13: +#line 148 "yacc_config.y" +{ + yyvsp[0].adjust->adj.Action = yyvsp[-2].adjust->adj.Action; + yyvsp[0].adjust->adj.Attributes = yyvsp[-2].adjust->adj.Attributes; + yyvsp[0].adjust->next = yyvsp[-2].adjust; + yyval.adjust = yyvsp[0].adjust; + } +break; +case 14: +#line 157 "yacc_config.y" +{ + yyval.adjust = calloc(sizeof(adjust_list_t), 1); + yyval.adjust->adj.Resource = RES_IRQ; + yyval.adjust->adj.resource.irq.IRQ = yyvsp[0].num; + } +break; +case 15: +#line 163 "yacc_config.y" +{ + if ((yyvsp[0].num < yyvsp[-2].num) || (yyvsp[0].num > 0xffff)) { + yyerror("invalid port range 0x%x-0x%x", yyvsp[-2].num, yyvsp[0].num); + YYERROR; + } + yyval.adjust = calloc(sizeof(adjust_list_t), 1); + yyval.adjust->adj.Resource = RES_IO_RANGE; + yyval.adjust->adj.resource.io.BasePort = yyvsp[-2].num; + yyval.adjust->adj.resource.io.NumPorts = yyvsp[0].num - yyvsp[-2].num + 1; + } +break; +case 16: +#line 174 "yacc_config.y" +{ + if (yyvsp[0].num < yyvsp[-2].num) { + yyerror("invalid address range 0x%x-0x%x", yyvsp[-2].num, yyvsp[0].num); + YYERROR; + } + yyval.adjust = calloc(sizeof(adjust_list_t), 1); + yyval.adjust->adj.Resource = RES_MEMORY_RANGE; + yyval.adjust->adj.resource.memory.Base = yyvsp[-2].num; + yyval.adjust->adj.resource.memory.Size = yyvsp[0].num - yyvsp[-2].num + 1; + } +break; +case 17: +#line 187 "yacc_config.y" +{ + yyval.device = calloc(sizeof(device_info_t), 1); + yyval.device->refs = 1; + strcpy(yyval.device->dev_info, yyvsp[0].str); + free(yyvsp[0].str); + } +break; +case 21: +#line 199 "yacc_config.y" +{ + yyval.card = calloc(sizeof(card_info_t), 1); + yyval.card->refs = 1; + yyval.card->name = yyvsp[0].str; + } +break; +case 30: +#line 215 "yacc_config.y" +{ + if (yyvsp[-1].card->ident_type) { + yyerror("ID method already defined for '%s'", yyvsp[-1].card->name); + YYERROR; + } + if (blank_card) { + yyerror("Anonymous card already defined"); + YYERROR; + } + yyvsp[-1].card->ident_type = BLANK_IDENT; + blank_card = yyvsp[-1].card; + } +break; +case 31: +#line 230 "yacc_config.y" +{ + if (yyvsp[-6].card->ident_type) { + yyerror("ID method already defined for '%s'", yyvsp[-6].card->name); + YYERROR; + } + yyvsp[-6].card->ident_type = TUPLE_IDENT; + yyvsp[-6].card->id.tuple.code = yyvsp[-4].num; + yyvsp[-6].card->id.tuple.ofs = yyvsp[-2].num; + yyvsp[-6].card->id.tuple.info = yyvsp[0].str; + } +break; +case 32: +#line 243 "yacc_config.y" +{ + if (yyvsp[-4].card->ident_type & (EXCL_IDENT|MANFID_IDENT)) { + yyerror("ID method already defined for '%s'", yyvsp[-4].card->name); + YYERROR; + } + yyvsp[-4].card->ident_type |= MANFID_IDENT; + yyvsp[-4].card->manfid.manf = yyvsp[-2].num; + yyvsp[-4].card->manfid.card = yyvsp[0].num; + } +break; +case 33: +#line 254 "yacc_config.y" +{ + if (yyvsp[-4].card->ident_type) { + yyerror("ID method already defined for '%s'", yyvsp[-4].card->name); + YYERROR; + } + yyvsp[-4].card->ident_type = PCI_IDENT; + yyvsp[-4].card->manfid.manf = yyvsp[-2].num; + yyvsp[-4].card->manfid.card = yyvsp[0].num; + } +break; +case 34: +#line 265 "yacc_config.y" +{ + if (yyvsp[-2].card->ident_type & (EXCL_IDENT|VERS_1_IDENT)) { + yyerror("ID method already defined for '%s'", yyvsp[-2].card->name); + YYERROR; + } + yyvsp[-2].card->ident_type |= VERS_1_IDENT; + yyvsp[-2].card->id.vers.ns = 1; + yyvsp[-2].card->id.vers.pi[0] = yyvsp[0].str; + } +break; +case 35: +#line 275 "yacc_config.y" +{ + if (yyvsp[-2].card->id.vers.ns == 4) { + yyerror("too many version strings for '%s'", yyvsp[-2].card->name); + YYERROR; + } + yyvsp[-2].card->id.vers.pi[yyvsp[-2].card->id.vers.ns] = yyvsp[0].str; + yyvsp[-2].card->id.vers.ns++; + } +break; +case 36: +#line 286 "yacc_config.y" +{ + if (yyvsp[-2].card->ident_type) { + yyerror("ID method already defined for '%s'", yyvsp[-2].card->name); + YYERROR; + } + yyvsp[-2].card->ident_type = FUNC_IDENT; + yyvsp[-2].card->id.func.funcid = yyvsp[0].num; + } +break; +case 37: +#line 297 "yacc_config.y" +{ yyvsp[-2].card->cis_file = strdup(yyvsp[0].str); } +break; +case 38: +#line 301 "yacc_config.y" +{ + if (add_binding(yyvsp[-2].card, yyvsp[0].str, NULL, 0) != 0) + YYERROR; + } +break; +case 39: +#line 306 "yacc_config.y" +{ + if (add_binding(yyvsp[-4].card, yyvsp[-2].str, yyvsp[0].str, 0) != 0) + YYERROR; + } +break; +case 40: +#line 311 "yacc_config.y" +{ + if (add_binding(yyvsp[-4].card, yyvsp[-2].str, NULL, yyvsp[0].num) != 0) + YYERROR; + } +break; +case 41: +#line 316 "yacc_config.y" +{ + if (add_binding(yyvsp[-6].card, yyvsp[-4].str, yyvsp[-2].str, yyvsp[0].num) != 0) + YYERROR; + } +break; +case 42: +#line 321 "yacc_config.y" +{ + if (add_binding(yyvsp[-2].card, yyvsp[0].str, NULL, 0) != 0) + YYERROR; + } +break; +case 43: +#line 326 "yacc_config.y" +{ + if (add_binding(yyvsp[-4].card, yyvsp[-2].str, yyvsp[0].str, 0) != 0) + YYERROR; + } +break; +case 44: +#line 331 "yacc_config.y" +{ + if (add_binding(yyvsp[-4].card, yyvsp[-2].str, NULL, yyvsp[0].num) != 0) + YYERROR; + } +break; +case 45: +#line 336 "yacc_config.y" +{ + if (add_binding(yyvsp[-6].card, yyvsp[-4].str, yyvsp[-2].str, yyvsp[0].num) != 0) + YYERROR; + } +break; +case 46: +#line 343 "yacc_config.y" +{ + yyvsp[-1].device->needs_mtd = 1; + } +break; +case 47: +#line 349 "yacc_config.y" +{ + device_info_t *d; + int i, found = 0; + for (d = root_device; d; d = d->next) { + for (i = 0; i < d->modules; i++) + if (strcmp(yyvsp[-2].str, d->module[i]) == 0) break; + if (i < d->modules) { + if (d->opts[i]) + free(d->opts[i]); + d->opts[i] = strdup(yyvsp[0].str); + found = 1; + } + } + free(yyvsp[-2].str); free(yyvsp[0].str); + if (!found) { + yyerror("module name '%s' not found", yyvsp[-2].str); + YYERROR; + } + } +break; +case 48: +#line 371 "yacc_config.y" +{ + if (add_module(yyvsp[-2].device, yyvsp[0].str) != 0) + YYERROR; + } +break; +case 49: +#line 376 "yacc_config.y" +{ + if (yyvsp[-2].device->opts[yyvsp[-2].device->modules-1] == NULL) { + yyvsp[-2].device->opts[yyvsp[-2].device->modules-1] = yyvsp[0].str; + } else { + yyerror("too many module options for '%s'", + yyvsp[-2].device->module[yyvsp[-2].device->modules-1]); + YYERROR; + } + } +break; +case 50: +#line 386 "yacc_config.y" +{ + if (add_module(yyvsp[-2].device, yyvsp[0].str) != 0) + YYERROR; + } +break; +case 51: +#line 393 "yacc_config.y" +{ + if (yyvsp[-2].device->class != NULL) { + yyerror("extra class string '%s'", yyvsp[0].str); + YYERROR; + } + yyvsp[-2].device->class = yyvsp[0].str; + } +break; +case 52: +#line 403 "yacc_config.y" +{ + yyval.mtd = calloc(sizeof(mtd_ident_t), 1); + yyval.mtd->refs = 1; + yyval.mtd->name = yyvsp[0].str; + } +break; +case 56: +#line 414 "yacc_config.y" +{ + if (yyvsp[-2].mtd->mtd_type) { + yyerror("ID method already defined for '%s'", yyvsp[-2].mtd->name); + YYERROR; + } + yyvsp[-2].mtd->mtd_type = DTYPE_MTD; + yyvsp[-2].mtd->dtype = yyvsp[0].num; + } +break; +case 57: +#line 425 "yacc_config.y" +{ + if (yyvsp[-3].mtd->mtd_type) { + yyerror("ID method already defined for '%s'", yyvsp[-3].mtd->name); + YYERROR; + } + yyvsp[-3].mtd->mtd_type = JEDEC_MTD; + yyvsp[-3].mtd->jedec_mfr = yyvsp[-1].num; + yyvsp[-3].mtd->jedec_info = yyvsp[0].num; + } +break; +case 58: +#line 437 "yacc_config.y" +{ + if (yyvsp[-1].mtd->mtd_type) { + yyerror("ID method already defined for '%s'", yyvsp[-1].mtd->name); + YYERROR; + } + if (default_mtd) { + yyerror("Default MTD already defined"); + YYERROR; + } + yyvsp[-1].mtd->mtd_type = DEFAULT_MTD; + default_mtd = yyvsp[-1].mtd; + } +break; +case 59: +#line 452 "yacc_config.y" +{ + if (yyvsp[-2].mtd->module != NULL) { + yyerror("extra MTD entry for '%s'", yyvsp[-2].mtd->name); + YYERROR; + } + yyvsp[-2].mtd->module = yyvsp[0].str; + } +break; +case 60: +#line 460 "yacc_config.y" +{ + if (yyvsp[-2].mtd->opts == NULL) { + yyvsp[-2].mtd->opts = yyvsp[0].str; + } else { + yyerror("too many module options for '%s'", yyvsp[-2].mtd->module); + YYERROR; + } + } +break; +case 61: +#line 471 "yacc_config.y" +{ + mtd_ident_t *m; + int found = 0; + for (m = root_mtd; m; m = m->next) + if (strcmp(yyvsp[-2].str, m->module) == 0) break; + if (m) { + if (m->opts) free(m->opts); + m->opts = strdup(yyvsp[0].str); + found = 1; + } + free(yyvsp[-2].str); free(yyvsp[0].str); + if (!found) { + yyerror("MTD name '%s' not found", yyvsp[-2].str); + YYERROR; + } + } +break; +#line 1093 "y.tab.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/pcmcia/yacc_config.h b/pcmcia/yacc_config.h new file mode 100644 index 0000000..f83d931 --- /dev/null +++ b/pcmcia/yacc_config.h @@ -0,0 +1,42 @@ +#ifndef YYERRCODE +#define YYERRCODE 256 +#endif + +#define DEVICE 257 +#define CARD 258 +#define ANONYMOUS 259 +#define TUPLE 260 +#define MANFID 261 +#define VERSION 262 +#define FUNCTION 263 +#define PCI 264 +#define BIND 265 +#define CIS 266 +#define TO 267 +#define NEEDS_MTD 268 +#define MODULE 269 +#define OPTS 270 +#define CLASS 271 +#define REGION 272 +#define JEDEC 273 +#define DTYPE 274 +#define DEFAULT 275 +#define MTD 276 +#define INCLUDE 277 +#define EXCLUDE 278 +#define RESERVE 279 +#define IRQ_NO 280 +#define PORT 281 +#define MEMORY 282 +#define STRING 283 +#define NUMBER 284 +#define SOURCE 285 +typedef union { + char *str; + u_long num; + struct device_info_t *device; + struct card_info_t *card; + struct mtd_ident_t *mtd; + struct adjust_list_t *adjust; +} YYSTYPE; +extern YYSTYPE yylval; diff --git a/pcmcia/yacc_config.y b/pcmcia/yacc_config.y new file mode 100644 index 0000000..1b5b1be --- /dev/null +++ b/pcmcia/yacc_config.y @@ -0,0 +1,553 @@ +%{ +/* + * yacc_config.y 1.57 2002/08/19 03:19:56 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "cardmgr.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; + +void yyerror(char *msg, ...); + +static int add_binding(card_info_t *card, char *name, char *class, int fn); +static int add_module(device_info_t *card, char *name); + +%} + +%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 device_info_t *device; + struct card_info_t *card; + struct mtd_ident_t *mtd; + struct adjust_list_t *adjust; +} + +%type STRING +%type NUMBER +%type adjust resource +%type device needs_mtd module class +%type card anonymous tuple manfid pci version function bind cis +%type region jedec dtype default mtd +%% + +list: /* nothing */ + | list adjust + { + adjust_list_t **tail = &root_adjust; + while (*tail != NULL) tail = &(*tail)->next; + *tail = $2; + } + | list device + { + $2->next = root_device; + root_device = $2; + } + | list mtd + { + if ($2->mtd_type == 0) { + yyerror("no ID method for '%s'", $2->name); + YYERROR; + } + if ($2->module == NULL) { + yyerror("no MTD module for '%s'", $2->name); + YYERROR; + } + $2->next = root_mtd; + root_mtd = $2; + } + | list card + { + if ($2->ident_type == 0) { + yyerror("no ID method for '%s'", $2->name); + YYERROR; + } + if ($2->bindings == 0) { + yyerror("no driver bindings for '%s'", $2->name); + YYERROR; + } + if ($2->ident_type == FUNC_IDENT) { + $2->next = root_func; + root_func = $2; + } else { + $2->next = root_card; + root_card = $2; + } + } + | list opts + | list mtd_opts + | list SOURCE + | list error + ; + +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; + } + ; + +device: DEVICE STRING + { + $$ = calloc(sizeof(device_info_t), 1); + $$->refs = 1; + strcpy($$->dev_info, $2); + free($2); + } + | needs_mtd + | module + | class + ; + +card: CARD STRING + { + $$ = calloc(sizeof(card_info_t), 1); + $$->refs = 1; + $$->name = $2; + } + | anonymous + | tuple + | manfid + | pci + | version + | function + | bind + | cis + ; + +anonymous: card ANONYMOUS + { + if ($1->ident_type) { + yyerror("ID method already defined for '%s'", $1->name); + YYERROR; + } + if (blank_card) { + yyerror("Anonymous card already defined"); + YYERROR; + } + $1->ident_type = BLANK_IDENT; + blank_card = $1; + } + ; + +tuple: card TUPLE NUMBER ',' NUMBER ',' STRING + { + if ($1->ident_type) { + yyerror("ID method already defined for '%s'", $1->name); + YYERROR; + } + $1->ident_type = TUPLE_IDENT; + $1->id.tuple.code = $3; + $1->id.tuple.ofs = $5; + $1->id.tuple.info = $7; + } + ; + +manfid: card MANFID NUMBER ',' NUMBER + { + if ($1->ident_type & (EXCL_IDENT|MANFID_IDENT)) { + yyerror("ID method already defined for '%s'", $1->name); + YYERROR; + } + $1->ident_type |= MANFID_IDENT; + $1->manfid.manf = $3; + $1->manfid.card = $5; + } + +pci: card PCI NUMBER ',' NUMBER + { + if ($1->ident_type) { + yyerror("ID method already defined for '%s'", $1->name); + YYERROR; + } + $1->ident_type = PCI_IDENT; + $1->manfid.manf = $3; + $1->manfid.card = $5; + } + +version: card VERSION STRING + { + if ($1->ident_type & (EXCL_IDENT|VERS_1_IDENT)) { + yyerror("ID method already defined for '%s'", $1->name); + YYERROR; + } + $1->ident_type |= VERS_1_IDENT; + $1->id.vers.ns = 1; + $1->id.vers.pi[0] = $3; + } + | version ',' STRING + { + if ($1->id.vers.ns == 4) { + yyerror("too many version strings for '%s'", $1->name); + YYERROR; + } + $1->id.vers.pi[$1->id.vers.ns] = $3; + $1->id.vers.ns++; + } + ; + +function: card FUNCTION NUMBER + { + if ($1->ident_type) { + yyerror("ID method already defined for '%s'", $1->name); + YYERROR; + } + $1->ident_type = FUNC_IDENT; + $1->id.func.funcid = $3; + } + ; + +cis: card CIS STRING + { $1->cis_file = strdup($3); } + ; + +bind: card BIND STRING + { + if (add_binding($1, $3, NULL, 0) != 0) + YYERROR; + } + | card BIND STRING CLASS STRING + { + if (add_binding($1, $3, $5, 0) != 0) + YYERROR; + } + | card BIND STRING TO NUMBER + { + if (add_binding($1, $3, NULL, $5) != 0) + YYERROR; + } + | card BIND STRING CLASS STRING TO NUMBER + { + if (add_binding($1, $3, $5, $7) != 0) + YYERROR; + } + | bind ',' STRING + { + if (add_binding($1, $3, NULL, 0) != 0) + YYERROR; + } + | bind ',' STRING CLASS STRING + { + if (add_binding($1, $3, $5, 0) != 0) + YYERROR; + } + | bind ',' STRING TO NUMBER + { + if (add_binding($1, $3, NULL, $5) != 0) + YYERROR; + } + | bind ',' STRING CLASS STRING TO NUMBER + { + if (add_binding($1, $3, $5, $7) != 0) + YYERROR; + } + ; + +needs_mtd: device NEEDS_MTD + { + $1->needs_mtd = 1; + } + ; + +opts: MODULE STRING OPTS STRING + { + device_info_t *d; + int i, found = 0; + for (d = root_device; d; d = d->next) { + for (i = 0; i < d->modules; i++) + if (strcmp($2, d->module[i]) == 0) break; + if (i < d->modules) { + if (d->opts[i]) + free(d->opts[i]); + d->opts[i] = strdup($4); + found = 1; + } + } + free($2); free($4); + if (!found) { + yyerror("module name '%s' not found", $2); + YYERROR; + } + } + ; + +module: device MODULE STRING + { + if (add_module($1, $3) != 0) + YYERROR; + } + | module OPTS STRING + { + if ($1->opts[$1->modules-1] == NULL) { + $1->opts[$1->modules-1] = $3; + } else { + yyerror("too many module options for '%s'", + $1->module[$1->modules-1]); + YYERROR; + } + } + | module ',' STRING + { + if (add_module($1, $3) != 0) + YYERROR; + } + ; + +class: device CLASS STRING + { + if ($1->class != NULL) { + yyerror("extra class string '%s'", $3); + YYERROR; + } + $1->class = $3; + } + ; + +region: REGION STRING + { + $$ = calloc(sizeof(mtd_ident_t), 1); + $$->refs = 1; + $$->name = $2; + } + | dtype + | jedec + | default + ; + +dtype: region DTYPE NUMBER + { + if ($1->mtd_type) { + yyerror("ID method already defined for '%s'", $1->name); + YYERROR; + } + $1->mtd_type = DTYPE_MTD; + $1->dtype = $3; + } + ; + +jedec: region JEDEC NUMBER NUMBER + { + if ($1->mtd_type) { + yyerror("ID method already defined for '%s'", $1->name); + YYERROR; + } + $1->mtd_type = JEDEC_MTD; + $1->jedec_mfr = $3; + $1->jedec_info = $4; + } + ; + +default: region DEFAULT + { + if ($1->mtd_type) { + yyerror("ID method already defined for '%s'", $1->name); + YYERROR; + } + if (default_mtd) { + yyerror("Default MTD already defined"); + YYERROR; + } + $1->mtd_type = DEFAULT_MTD; + default_mtd = $1; + } + ; + +mtd: region MTD STRING + { + if ($1->module != NULL) { + yyerror("extra MTD entry for '%s'", $1->name); + YYERROR; + } + $1->module = $3; + } + | mtd OPTS STRING + { + if ($1->opts == NULL) { + $1->opts = $3; + } else { + yyerror("too many module options for '%s'", $1->module); + YYERROR; + } + } + ; + +mtd_opts: MTD STRING OPTS STRING + { + mtd_ident_t *m; + int found = 0; + for (m = root_mtd; m; m = m->next) + if (strcmp($2, m->module) == 0) break; + if (m) { + if (m->opts) free(m->opts); + m->opts = strdup($4); + found = 1; + } + free($2); free($4); + if (!found) { + yyerror("MTD name '%s' not found", $2); + YYERROR; + } + } + ; + +%% +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); +} + +static int add_binding(card_info_t *card, char *name, char *class, int fn) +{ + device_info_t *dev = root_device; + if (card->bindings == MAX_BINDINGS) { + yyerror("too many bindings\n"); + return -1; + } + for (; dev; dev = dev->next) + if (strcmp((char *)dev->dev_info, name) == 0) break; + if (dev == NULL) { + yyerror("unknown device '%s'", name); + return -1; + } + card->device[card->bindings] = dev; + card->dev_fn[card->bindings] = fn; + if (class) + card->class[card->bindings] = strdup(class); + card->bindings++; + free(name); + return 0; +} + +static int add_module(device_info_t *dev, char *name) +{ + if (dev->modules == MAX_MODULES) { + yyerror("too many modules for '%s'", dev->dev_info); + return -1; + } + dev->module[dev->modules] = name; + dev->opts[dev->modules] = NULL; + dev->modules++; + return 0; +} + +#if YYDEBUG +adjust_list_t *root_adjust = NULL; +device_info_t *root_device = NULL; +card_info_t *root_card = NULL, *blank_card = NULL, *root_func = NULL; +mtd_ident_t *root_mtd = NULL, *default_mtd = NULL; + +void main(int argc, char *argv[]) +{ + yydebug = 1; + if (argc > 1) + parse_configfile(argv[1]); +} +#endif diff --git a/pcmcia_config.patch b/pcmcia_config.patch new file mode 100644 index 0000000..ab70ae0 --- /dev/null +++ b/pcmcia_config.patch @@ -0,0 +1,46 @@ +--- pcmcia/config~ Thu Aug 31 00:05:25 2000 ++++ pcmcia/config Fri Sep 17 17:25:35 1999 +@@ -34,7 +34,7 @@ + class "cdrom" module "oti12_cs" + + device "pcnet_cs" +- class "network" module "net/8390", "pcnet_cs" ++ class "network" module "8390", "pcnet_cs" + + device "axnet_cs" + class "network" module "net/8390", "axnet_cs" +@@ -64,25 +64,25 @@ + class "ftl" module "ftl_cs" + + device "serial_cs" +- class "serial" module "serial_cs" ++ class "serial" module "serial", "serial_cs" + + device "parport_cs" + class "parport" module "parport_cs" + + device "qlogic_cs" +- class "scsi" module "qlogic_cs" +- ++ class "scsi" module "scsi_mod", "qlogic_cs" ++ + device "aha152x_cs" +- class "scsi" module "aha152x_cs" +- ++ class "scsi" module "scsi_mod", "aha152x_cs" ++ + device "fdomain_cs" +- class "scsi" module "fdomain_cs" +- ++ class "scsi" module "scsi_mod", "fdomain_cs" ++ + device "sym53c500_cs" +- class "scsi" module "sym53c500_cs" ++ class "scsi" module "scsi_mod", "sym53c500_cs" + + device "ide-cs" +- class "ide" module "ide-cs" ++ class "ide" module "ide-mod", "ide-probe", "ide-cs" + + device "fmvj18x_cs" + class "network" module "fmvj18x_cs" diff --git a/probing.c b/probing.c new file mode 100644 index 0000000..ca2b73f --- /dev/null +++ b/probing.c @@ -0,0 +1,658 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + + +/* + * This contains stuff related to probing: + * (1) any (actually only SCSI, NET, CPQ, USB Controllers) devices (autoprobe for PCI and USB) + * (2) IDE media + * (3) SCSI media + * (4) ETH devices + */ + + +#include +#include +#include +#include +#include +#include +#include +// #include +#include +#include +#include +#include "stage1.h" + +#include "log.h" +#include "frontend.h" +#include "modules.h" +#include "pci-resource/pci-ids.h" +#ifdef ENABLE_USB +#include "usb-resource/usb-ids.h" +#endif + +#include "probing.h" + + +struct media_info { + char * name; + char * model; + enum media_type type; +}; + + +static void warning_insmod_failed(enum insmod_return r) +{ + if (IS_AUTOMATIC && r == INSMOD_FAILED_FILE_NOT_FOUND) + return; + if (r != INSMOD_OK) { + if (r == INSMOD_FAILED_FILE_NOT_FOUND) + stg1_error_message("This floppy doesn't contain the driver."); + else + stg1_error_message("Warning, installation of driver failed. (please include msg from for bugreports)"); + } +} + +#ifndef DISABLE_NETWORK +struct net_description_elem +{ + char * intf_name; + char * intf_description; +}; +static struct net_description_elem net_descriptions[50]; +static int net_descr_number = 0; +static char * intf_descr_for_discover = NULL; +static char * net_intf_too_early_name[50]; /* for modules providing more than one net intf */ +static int net_intf_too_early_number = 0; +static int net_intf_too_early_ptr = 0; + +void prepare_intf_descr(const char * intf_descr) +{ + intf_descr_for_discover = strdup(intf_descr); +} + +void net_discovered_interface(char * intf_name) +{ + if (!intf_descr_for_discover) { + net_intf_too_early_name[net_intf_too_early_number++] = strdup(intf_name); + return; + } + if (!intf_name) { + if (net_intf_too_early_ptr >= net_intf_too_early_number) { + log_message("NET: was expecting another network interface (broken net module?)"); + return; + } + net_descriptions[net_descr_number].intf_name = net_intf_too_early_name[net_intf_too_early_ptr++]; + } + else + net_descriptions[net_descr_number].intf_name = strdup(intf_name); + net_descriptions[net_descr_number].intf_description = strdup(intf_descr_for_discover); + intf_descr_for_discover = NULL; + net_descr_number++; +} + +char * get_net_intf_description(char * intf_name) +{ + int i; + for (i = 0; i < net_descr_number ; i++) + if (!strcmp(net_descriptions[i].intf_name, intf_name)) + return net_descriptions[i].intf_description; + return strdup("unknown"); +} +#endif + +static void probe_that_type(enum driver_type type) +{ + if (IS_EXPERT) { + ask_insmod(type); + return; + } + + + /* ---- PCI probe ---------------------------------------------- */ + { + FILE * f; + int len = 0; + char buf[200]; + struct pci_module_map * pcidb = NULL; + + switch (type) { +#ifndef DISABLE_MEDIAS + case SCSI_ADAPTERS: + pcidb = medias_pci_ids; + len = medias_num_ids; + break; +#endif +#ifndef DISABLE_NETWORK +#ifndef DISABLE_PCINET + case NETWORK_DEVICES: + pcidb = network_pci_ids; + len = network_num_ids; + break; +#endif +#endif +#ifdef ENABLE_USB + case USB_CONTROLLERS: + pcidb = usb_pci_ids; + len = usb_num_ids; + break; +#endif + default: + goto end_pci_probe; + } + + if (!(f = fopen("/proc/bus/pci/devices", "rb"))) { + log_message("PCI: could not open proc file"); + goto end_pci_probe; + } + + while (1) { + int i, garb, vendor, device; + + if (!fgets(buf, sizeof(buf), f)) break; + + sscanf(buf, "%x %x", &garb, &vendor); + device = vendor & 0xFFFF; /* because scanf from dietlibc does not support %4f */ + vendor = (vendor >> 16) & 0xFFFF; + log_message("PCI-test: device %04x %04x\n", vendor, device); + + for (i = 0; i < len; i++) { + if (pcidb[i].vendor == vendor && pcidb[i].device == device) { + log_message("PCI: device %04x %04x is \"%s\" (%s)", vendor, device, pcidb[i].name, pcidb[i].module); +#ifndef DISABLE_MEDIAS + if (type == SCSI_ADAPTERS) { + int wait_msg = 0; + enum insmod_return failed; + if (IS_AUTOMATIC) { + wait_message("Loading driver for SCSI adapter:\n \n%s", pcidb[i].name); + wait_msg = 1; + } else + stg1_info_message("About to load driver for SCSI adapter:\n \n%s", pcidb[i].name); + failed = my_insmod(pcidb[i].module, SCSI_ADAPTERS, NULL); + if (wait_msg) + remove_wait_message(); + warning_insmod_failed(failed); + + } +#endif +#ifndef DISABLE_NETWORK + if (type == NETWORK_DEVICES) { + stg1_info_message("About to load driver for network device:\n \n%s", pcidb[i].name); + prepare_intf_descr(pcidb[i].name); + warning_insmod_failed(my_insmod(pcidb[i].module, NETWORK_DEVICES, NULL)); + if (intf_descr_for_discover) /* for modules providing more than one net intf */ + net_discovered_interface(NULL); + } +#endif +#ifdef ENABLE_USB + if (type == USB_CONTROLLERS) + my_insmod(pcidb[i].module, USB_CONTROLLERS, NULL); +#endif + } + } + } + fclose(f); + end_pci_probe: + } + + +#ifdef ENABLE_USB + /* ---- USB probe ---------------------------------------------- */ + { + static int already_probed_usb_controllers = 0; + static int already_mounted_usbdev = 0; + + FILE * f; + int len = 0; + char buf[200]; + struct usb_module_map * usbdb = NULL; + + switch (type) { +#ifdef ENABLE_USBNET + case NETWORK_DEVICES: + usbdb = usbnet_usb_ids; + len = usbnet_usb_num_ids; + break; +#endif + default: + goto end_usb_probe; + } + + if (!already_probed_usb_controllers) { + already_probed_usb_controllers = 1; + probe_that_type(USB_CONTROLLERS); + } + + if (!already_mounted_usbdev) { + already_mounted_usbdev = 1; + if (mount("/proc/bus/usb", "/proc/bus/usb", "usbdevfs", 0, NULL)) { + log_message("USB: couldn't mount /proc/bus/usb"); + goto end_usb_probe; + } + wait_message("Waiting for USB stuff to show up."); + sleep(2); /* sucking background work */ + remove_wait_message(); + } + + if (!(f = fopen("/proc/bus/usb/devices", "rb"))) { + log_message("USB: could not open proc file"); + goto end_usb_probe; + } + + while (1) { + int i, vendor, id; + + if (!fgets(buf, sizeof(buf), f)) break; + + if (strstr(buf, "Keyboard")) { + my_insmod("usbkbd", ANY_DRIVER_TYPE, NULL); + my_insmod("keybdev", ANY_DRIVER_TYPE, NULL); + } + + if (sscanf(buf, "P: Vendor=%x ProdID=%x", &vendor, &id) != 2) + continue; + + for (i = 0; i < len; i++) { + if (usbdb[i].vendor == vendor && usbdb[i].id == id) { + log_message("USB: device %04x %04x is \"%s\" (%s)", vendor, id, usbdb[i].name, usbdb[i].module); +#ifdef ENABLE_USBNET + if (type == NETWORK_DEVICES) { + stg1_info_message("About to load driver for usb network device:\n \n%s", usbdb[i].name); + prepare_intf_descr(usbdb[i].name); + warning_insmod_failed(my_insmod(usbdb[i].module, NETWORK_DEVICES, NULL)); + if (intf_descr_for_discover) /* for modules providing more than one net intf */ + net_discovered_interface(NULL); + } +#endif + + } + } + } + fclose(f); + end_usb_probe: + } +#endif +} + + +#ifndef DISABLE_MEDIAS +static struct media_info * medias = NULL; + +static void find_media(void) +{ + char b[50]; + char buf[5000]; + struct media_info tmp[50]; + int count; + int fd; + + if (!medias) + probe_that_type(SCSI_ADAPTERS); + else + free(medias); /* that does not free the strings, by the way */ + + /* ----------------------------------------------- */ + log_message("looking for ide media"); + + count = 0; + strcpy(b, "/proc/ide/hd"); + for (b[12] = 'a'; b[12] <= 'h'; b[12]++) { + int i; + char ide_disk[] = "disk"; + char ide_cdrom[] = "cdrom"; + char ide_tape[] = "tape"; + char ide_floppy[] = "floppy"; + + /* first, test if file exists (will tell if attached medium exists) */ + b[13] = '\0'; + if (access(b, R_OK)) + continue; + + tmp[count].name = strdup("hda"); + tmp[count].name[2] = b[12]; + + /* media type */ + strcpy(b + 13, "/media"); + fd = open(b, O_RDONLY); + if (fd == -1) { + log_message("failed to open %s for reading", b); + continue; + } + + i = read(fd, buf, sizeof(buf)); + if (i == -1) { + log_message("failed to read %s", b); + continue; + } + buf[i] = '\0'; + close(fd); + + if (ptr_begins_static_str(buf, ide_disk)) + tmp[count].type = DISK; + else if (ptr_begins_static_str(buf, ide_cdrom)) + tmp[count].type = CDROM; + else if (ptr_begins_static_str(buf, ide_tape)) + tmp[count].type = TAPE; + else if (ptr_begins_static_str(buf, ide_floppy)) + tmp[count].type = FLOPPY; + else + tmp[count].type = UNKNOWN_MEDIA; + + /* media model */ + strcpy(b + 13, "/model"); + fd = open(b, O_RDONLY); + if (fd == -1) { + log_message("failed to open %s for reading", b); + continue; + } + + i = read(fd, buf, sizeof(buf)); + if (i <= 0) { + log_message("failed to read %s", b); + tmp[count].model = strdup("(none)"); + } + else { + buf[i-1] = '\0'; /* eat the \n */ + tmp[count].model = strdup(buf); + } + close(fd); + + log_message("IDE/%d: %s is a %s", tmp[count].type, tmp[count].name, tmp[count].model); + count++; + } + + + /* ----------------------------------------------- */ + log_message("looking for scsi media"); + + fd = open("/proc/scsi/scsi", O_RDONLY); + if (fd != -1) { + enum { SCSI_TOP, SCSI_HOST, SCSI_VENDOR, SCSI_TYPE } state = SCSI_TOP; + char * start, * chptr, * next, * end; + char scsi_disk_count = 'a'; + char scsi_cdrom_count = '0'; + char scsi_tape_count = '0'; + + char scsi_no_devices[] = "Attached devices: none"; + char scsi_some_devices[] = "Attached devices: "; + char scsi_host[] = "Host: "; + char scsi_vendor[] = " Vendor: "; + + int i = read(fd, &buf, sizeof(buf)-1); + if (i < 1) { + close(fd); + goto end_scsi; + } + close(fd); + buf[i] = '\0'; + + if (ptr_begins_static_str(buf, scsi_no_devices)) + goto end_scsi; + + start = buf; + while (*start) { + char tmp_model[50]; + char tmp_name[10]; + + chptr = start; + while (*chptr != '\n') chptr++; + *chptr = '\0'; + next = chptr + 1; + + switch (state) { + case SCSI_TOP: + if (!ptr_begins_static_str(start, scsi_some_devices)) + goto end_scsi; + state = SCSI_HOST; + break; + + case SCSI_HOST: + if (!ptr_begins_static_str(start, scsi_host)) + goto end_scsi; + state = SCSI_VENDOR; + break; + + case SCSI_VENDOR: + if (!ptr_begins_static_str(start, scsi_vendor)) + goto end_scsi; + + /* (1) Grab Vendor info */ + start += 10; + end = chptr = strstr(start, "Model:"); + if (!chptr) + goto end_scsi; + + chptr--; + while (*chptr == ' ') + chptr--; + if (*chptr == ':') { + chptr++; + *(chptr + 1) = '\0'; + strcpy(tmp_model,"(unknown)"); + } else { + *(chptr + 1) = '\0'; + strcpy(tmp_model, start); + } + + /* (2) Grab Model info */ + start = end; + start += 7; + + chptr = strstr(start, "Rev:"); + if (!chptr) + goto end_scsi; + + chptr--; + while (*chptr == ' ') chptr--; + *(chptr + 1) = '\0'; + + strcat(tmp_model, " "); + strcat(tmp_model, start); + + tmp[count].model = strdup(tmp_model); + + state = SCSI_TYPE; + + break; + + case SCSI_TYPE: + if (strncmp(" Type:", start, 7)) + goto end_scsi; + *tmp_name = '\0'; + + if (strstr(start, "Direct-Access")) { + sprintf(tmp_name, "sd%c", scsi_disk_count++); + tmp[count].type = DISK; + } else if (strstr(start, "Sequential-Access")) { + sprintf(tmp_name, "st%c", scsi_tape_count++); + tmp[count].type = TAPE; + } else if (strstr(start, "CD-ROM")) { + sprintf(tmp_name, "sr%c", scsi_cdrom_count++); + tmp[count].type = CDROM; + } + + if (*tmp_name) { + tmp[count].name = strdup(tmp_name); + log_message("SCSI/%d: %s is a %s", tmp[count].type, tmp[count].name, tmp[count].model); + count++; + } + + state = SCSI_HOST; + } + + start = next; + } + + end_scsi: + } + + /* ----------------------------------------------- */ + log_message("looking for Compaq Smart Array media"); + { + char * procfiles[] = { "/proc/driver/cpqarray/ida0", "/proc/driver/cciss/cciss0", // 2.4 style + "/proc/array/ida", "/proc/cciss/cciss", // 2.2 style + NULL }; + static char cpq_descr[] = "Compaq RAID logical disk"; + char ** procfile = procfiles; + FILE * f; + while (procfile && *procfile && (f = fopen(*procfile, "rb"))) { + while (fgets(buf, sizeof(buf), f)) { + if (ptr_begins_static_str(buf, "ida/") || ptr_begins_static_str(buf, "cciss/")) { + char * end = strchr(buf, ':'); + if (!end) + log_message("Inconsistency in %s, line:\n%s", *procfile, buf); + else { + *end = '\0'; + tmp[count].name = strdup(buf); + tmp[count].type = DISK; + tmp[count].model = cpq_descr; + log_message("CPQ: found %s", tmp[count].name); + count++; + } + } + } + fclose(f); + procfile++; + } + } + + /* ----------------------------------------------- */ + log_message("looking for DAC960"); + { + FILE * f; + if ((f = fopen("/tmp/syslog", "rb"))) { + while (fgets(buf, sizeof(buf), f)) { + char * start; + if ((start = strstr(buf, "/dev/rd/"))) { + char * end = strchr(start, ':'); + if (!end) + log_message("Inconsistency in syslog, line:\n%s", buf); + else { + *end = '\0'; + tmp[count].name = strdup(start+5); + tmp[count].type = DISK; + start = end + 2; + end = strchr(start, ','); + if (end) { + *end = '\0'; + tmp[count].model = strdup(start); + } else + tmp[count].model = "(unknown)"; + log_message("DAC960: found %s (%s)", tmp[count].name, tmp[count].model); + count++; + } + } + } + fclose(f); + } + } + + /* ----------------------------------------------- */ + tmp[count].name = NULL; + count++; + + medias = memdup(tmp, sizeof(struct media_info) * count); +} + + +/* Finds by media */ +void get_medias(enum media_type media, char *** names, char *** models) +{ + struct media_info * m; + char * tmp_names[50]; + char * tmp_models[50]; + int count; + + find_media(); + + m = medias; + + count = 0; + while (m && m->name) { + if (m->type == media) { + tmp_names[count] = strdup(m->name); + tmp_models[count++] = strdup(m->model); + } + m++; + } + tmp_names[count] = NULL; + tmp_models[count++] = NULL; + + *names = memdup(tmp_names, sizeof(char *) * count); + *models = memdup(tmp_models, sizeof(char *) * count); +} +#endif /* DISABLE_MEDIAS */ + + +#ifndef DISABLE_NETWORK +int net_device_available(char * device) { + struct ifreq req; + int s; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + log_perror(device); + return 0; + } + strcpy(req.ifr_name, device); + if (ioctl(s, SIOCGIFFLAGS, &req)) { + /* if we can't get the flags, the networking device isn't available */ + close(s); + return 0; + } + close(s); + return 1; +} + + +char ** get_net_devices(void) +{ + char * devices[] = { + "eth0", "eth1", "eth2", "eth3", "eth4", "eth5", + "tr0", + "plip0", "plip1", "plip2", + "fddi0", +#ifdef ENABLE_USBNET + "usb0", "usb1", "usb2", "usb3", +#endif + NULL + }; + char ** ptr = devices; + char * tmp[50]; + int i = 0; + static int already_probed = 0; + + if (!already_probed) { + already_probed = 1; /* cut off loop brought by: probe_that_type => my_insmod => get_net_devices */ + probe_that_type(NETWORK_DEVICES); + } + + while (ptr && *ptr) { + if (net_device_available(*ptr)) + tmp[i++] = strdup(*ptr); + ptr++; + } + tmp[i++] = NULL; + + return memdup(tmp, sizeof(char *) * i); +} +#endif /* DISABLE_NETWORK */ diff --git a/probing.h b/probing.h new file mode 100644 index 0000000..d2bf1e5 --- /dev/null +++ b/probing.h @@ -0,0 +1,36 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#ifndef _PROBING_H_ +#define _PROBING_H_ + +enum media_type { CDROM, DISK, FLOPPY, TAPE, UNKNOWN_MEDIA }; + +enum driver_type { SCSI_ADAPTERS, NETWORK_DEVICES, USB_CONTROLLERS, ANY_DRIVER_TYPE }; + +void get_medias(enum media_type media, char *** names, char *** models); +char ** get_net_devices(void); +void net_discovered_interface(char * intf_name); +char * get_net_intf_description(char * intf_name); +void prepare_intf_descr(const char * intf_descr); + + +#endif diff --git a/stage1-data/stage1-with-busybox.tar.bz2 b/stage1-data/stage1-with-busybox.tar.bz2 new file mode 100644 index 0000000..337b136 Binary files /dev/null and b/stage1-data/stage1-with-busybox.tar.bz2 differ diff --git a/stage1-data/stage1-with-sash.tar.bz2 b/stage1-data/stage1-with-sash.tar.bz2 new file mode 100644 index 0000000..d2158dd Binary files /dev/null and b/stage1-data/stage1-with-sash.tar.bz2 differ diff --git a/stage1-data/stage1.tar.bz2 b/stage1-data/stage1.tar.bz2 new file mode 100644 index 0000000..4f6f2b8 Binary files /dev/null and b/stage1-data/stage1.tar.bz2 differ diff --git a/stage1.c b/stage1.c new file mode 100644 index 0000000..007d4f9 --- /dev/null +++ b/stage1.c @@ -0,0 +1,439 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * View the homepage: http://us.mandrakesoft.com/~gc/html/stage1.html + * + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stage1.h" + +#include "log.h" +#include "probing.h" +#include "frontend.h" +#include "modules.h" +#include "tools.h" +#include "automatic.h" +#include "mount.h" +#include "insmod.h" + +#ifdef ENABLE_PCMCIA +#include "pcmcia/pcmcia.h" +#endif + +#ifndef DISABLE_CDROM +#include "cdrom.h" +#endif + +#ifndef DISABLE_NETWORK +#include "network.h" +#endif + +#ifndef DISABLE_DISK +#include "disk.h" +#endif + + +/************************************************************ + * globals */ + +char * method_name; + + +void fatal_error(char *msg) +{ + printf("FATAL ERROR IN STAGE1: %s\n\nI can't recover from this.\nYou may reboot your system.\n", msg); + while (1); +} + + +/************************************************************ + * special frontend functs + * (the principle is to not pollute frontend code with stage1-specific stuff) */ + +void stg1_error_message(char *msg, ...) +{ + va_list args; + va_start(args, msg); + log_message("unsetting automatic"); + unset_param(MODE_AUTOMATIC); + verror_message(msg, args); + va_end(args); +} + +void stg1_info_message(char *msg, ...) +{ + va_list args; + va_start(args, msg); + if (IS_AUTOMATIC) { + vlog_message(msg, args); + return; + } + vinfo_message(msg, args); + va_end(args); +} + + +/************************************************************ + * spawns a shell on console #2 */ +static void spawn_shell(void) +{ +#ifdef SPAWN_SHELL + int fd; + char * shell_name[] = { "/tmp/sh", NULL }; + + log_message("spawning a shell"); + + if (!IS_TESTING) { + fd = open("/dev/tty2", O_RDWR); + if (fd == -1) { + log_message("cannot open /dev/tty2 -- no shell will be provided"); + return; + } + else if (access(shell_name[0], X_OK)) { + log_message("cannot open shell - %s doesn't exist", shell_name[0]); + return; + } + + if (!fork()) { + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + + close(fd); + setsid(); + if (ioctl(0, TIOCSCTTY, NULL)) + log_perror("could not set new controlling tty"); + + execve(shell_name[0], shell_name, grab_env()); + log_message("execve of %s failed: %s", shell_name[0], strerror(errno)); + exit(-1); + } + + close(fd); + } +#endif +} + + +char * interactive_fifo = "/tmp/stage1-fifo"; +static pid_t interactive_pid = 0; + +/* spawns my small interactive on console #6 */ +static void spawn_interactive(void) +{ +#ifdef SPAWN_INTERACTIVE + int fd; + char * dev = "/dev/tty6"; + + printf("spawning my interactive on %s\n", dev); + + if (!IS_TESTING) { + fd = open(dev, O_RDWR); + if (fd == -1) { + printf("cannot open %s -- no interactive\n", dev); + return; + } + + if (mkfifo(interactive_fifo, O_RDWR)) { + printf("cannot create fifo -- no interactive\n"); + return; + } + + if (!(interactive_pid = fork())) { + int fif_out; + + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + + close(fd); + setsid(); + if (ioctl(0, TIOCSCTTY, NULL)) + perror("could not set new controlling tty"); + + fif_out = open(interactive_fifo, O_WRONLY); + printf("Please enter your command (availables: [+,-] [rescue,expert]).\n"); + + while (1) { + char s[50]; + int i = 0; + printf("? "); + fflush(stdout); + read(0, &(s[i++]), 1); + fcntl(0, F_SETFL, O_NONBLOCK); + while (read(0, &(s[i++]), 1) > 0 && i < sizeof(s)); + fcntl(0, F_SETFL, 0); + write(fif_out, s, i-2); + printf("Ok.\n"); + } + } + + close(fd); + } +#endif +} + + +/************************************************************ + */ + +static void expert_third_party_modules(void) +{ + enum return_type results; + char * floppy_mount_location = "/tmp/floppy"; + char ** modules; + char final_name[500]; + char * choice; + int rc; + char * questions[] = { "Options", NULL }; + static char ** answers = NULL; + + results = ask_yes_no("If you want to insert third-party kernel modules, insert " + "a Linux (ext2fs) formatted floppy containing the modules and confirm. Otherwise, select \"no\".");; + if (results != RETURN_OK) + return; + + my_insmod("floppy", ANY_DRIVER_TYPE, NULL); + + if (my_mount("/dev/fd0", floppy_mount_location, "ext2", 0) == -1) { + stg1_error_message("I can't find a Linux ext2 floppy in first floppy drive."); + return expert_third_party_modules(); + } + + modules = list_directory(floppy_mount_location); + + if (!modules || !*modules) { + stg1_error_message("No modules found on floppy disk."); + umount(floppy_mount_location); + return expert_third_party_modules(); + } + + results = ask_from_list("Which driver would you like to insmod?", modules, &choice); + if (results != RETURN_OK) { + umount(floppy_mount_location); + return; + } + + sprintf(final_name, "%s/%s", floppy_mount_location, choice); + + results = ask_from_entries("Please enter the options:", questions, &answers, 24, NULL); + if (results != RETURN_OK) { + umount(floppy_mount_location); + return expert_third_party_modules(); + } + + rc = insmod_call(final_name, answers[0]); + umount(floppy_mount_location); + + if (rc) { + log_message("\tfailed"); + stg1_error_message("Insmod failed."); + } + + return expert_third_party_modules(); +} + + +static void handle_pcmcia(char ** pcmcia_adapter) +{ +#ifdef ENABLE_PCMCIA + *pcmcia_adapter = pcmcia_probe(); + if (!*pcmcia_adapter) { + log_message("no pcmcia adapter found"); + return; + } + my_insmod("pcmcia_core", ANY_DRIVER_TYPE, "probe_io=0"); + my_insmod(*pcmcia_adapter, ANY_DRIVER_TYPE, NULL); + my_insmod("ds", ANY_DRIVER_TYPE, NULL); + + /* call to cardmgr takes time, let's use the wait message */ + wait_message("Enabling PCMCIA extension cards..."); + log_message("cardmgr rc: %d", cardmgr_call()); + remove_wait_message(); +#endif +} + + +/************************************************************ + */ + +static enum return_type method_select_and_prepare(void) +{ + enum return_type results; + char * choice; + char * means[10], * means_auto[10]; + int i; + +#ifndef DISABLE_DISK + char * disk_install = "Hard disk"; char * disk_install_auto = "disk"; +#endif +#ifndef DISABLE_CDROM + char * cdrom_install = "CDROM drive"; char * cdrom_install_auto = "cdrom"; +#endif +#ifndef DISABLE_NETWORK + char * network_nfs_install = "NFS server"; char * network_nfs_install_auto = "nfs"; + char * network_ftp_install = "FTP server"; char * network_ftp_install_auto = "ftp"; + char * network_http_install = "HTTP server"; char * network_http_install_auto = "http"; +#endif + + i = 0; +#ifndef DISABLE_NETWORK + means[i] = network_nfs_install; means_auto[i++] = network_nfs_install_auto; + means[i] = network_ftp_install; means_auto[i++] = network_ftp_install_auto; + means[i] = network_http_install; means_auto[i++] = network_http_install_auto; +#endif +#ifndef DISABLE_CDROM + means[i] = cdrom_install; means_auto[i++] = cdrom_install_auto; +#endif +#ifndef DISABLE_DISK + means[i] = disk_install; means_auto[i++] = disk_install_auto; +#endif + means[i] = NULL; + + results = ask_from_list_auto("Please choose the installation method.", means, &choice, "method", means_auto); + + if (results != RETURN_OK) + return method_select_and_prepare(); + + results = RETURN_ERROR; + +#ifndef DISABLE_CDROM + if (!strcmp(choice, cdrom_install)) + results = cdrom_prepare(); +#endif + +#ifndef DISABLE_DISK + if (!strcmp(choice, disk_install)) + results = disk_prepare(); +#endif + +#ifndef DISABLE_NETWORK + if (!strcmp(choice, network_nfs_install)) + results = nfs_prepare(); + + if (!strcmp(choice, network_ftp_install)) + results = ftp_prepare(); + + if (!strcmp(choice, network_http_install)) + results = http_prepare(); +#endif + + if (results != RETURN_OK) + return method_select_and_prepare(); + + return RETURN_OK; +} + + +int main(int argc, char **argv, char **env) +{ + enum return_type ret; + char ** argptr; + char * stage2_args[30]; + char * pcmcia_adapter = NULL; + + if (getpid() > 50) + set_param(MODE_TESTING); + + spawn_interactive(); + + open_log(); + log_message("welcome to the " DISTRIB_NAME " install (mdk-stage1, version " VERSION " built " __DATE__ " " __TIME__")"); + process_cmdline(); + handle_env(env); + spawn_shell(); + init_modules_insmoding(); + init_frontend("Welcome to " DISTRIB_NAME " (" VERSION ") " __DATE__ " " __TIME__); + + if (IS_EXPERT) + expert_third_party_modules(); + + if (IS_UPDATEMODULES) + update_modules(); + + handle_pcmcia(&pcmcia_adapter); + + if (IS_CHANGEDISK) + stg1_info_message("You are starting the installation with an alternate booting method. " + "Please change your disk, and insert the Installation disk."); + + if (IS_RESCUE && total_memory() < MEM_LIMIT_RESCUE) { + stg1_error_message("You are starting the rescue with a low memory configuration. " + "From that point, experience showed us that the program may stop " + "or crash at any point without immediate proper reason. Continue at " + "your own risk. Alternatively, you may reboot your system now."); + } + + ret = method_select_and_prepare(); + + finish_frontend(); + close_log(); + + if (ret != RETURN_OK) + fatal_error("could not select an installation method"); + + if (!IS_RAMDISK) { + if (symlink(IMAGE_LOCATION LIVE_LOCATION, STAGE2_LOCATION) != 0) { + printf("symlink from " IMAGE_LOCATION LIVE_LOCATION " to " STAGE2_LOCATION " failed"); + fatal_error(strerror(errno)); + } + } + + if (interactive_pid != 0) + kill(interactive_pid, 9); + + if (IS_RESCUE) + return 66; + if (IS_TESTING) + return 0; + + argptr = stage2_args; + *argptr++ = "/usr/bin/runinstall2"; + *argptr++ = "--method"; + *argptr++ = method_name; + if (pcmcia_adapter) { + *argptr++ = "--pcmcia"; + *argptr++ = pcmcia_adapter; + } + if (disable_modules) + *argptr++ = "--blank"; + *argptr++ = NULL; + + execve(stage2_args[0], stage2_args, grab_env()); + + printf("error in exec of stage2 :-(\n"); + fatal_error(strerror(errno)); + + return 0; /* shut up compiler (we can't get here anyway!) */ +} diff --git a/stage1.h b/stage1.h new file mode 100644 index 0000000..c3b74cf --- /dev/null +++ b/stage1.h @@ -0,0 +1,60 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#ifndef _STAGE1_H_ +#define _STAGE1_H_ + +#include "config-stage1.h" +#include "tools.h" + + +/* Some global stuff */ + +extern char * method_name; +extern char * interactive_fifo; + +#define MODE_TESTING (1 << 0) +#define MODE_EXPERT (1 << 1) +#define MODE_RESCUE (1 << 3) +#define MODE_AUTOMATIC (1 << 4) +#define MODE_LOWMEM (1 << 5) +#define MODE_SPECIAL_STAGE2 (1 << 8) +#define MODE_RAMDISK (1 << 9) +#define MODE_CHANGEDISK (1 << 10) +#define MODE_UPDATEMODULES (1 << 11) + +#define IS_TESTING (get_param(MODE_TESTING)) +#define IS_EXPERT (get_param(MODE_EXPERT)) +#define IS_RESCUE (get_param(MODE_RESCUE)) +#define IS_AUTOMATIC (get_param(MODE_AUTOMATIC)) +#define IS_LOWMEM (get_param(MODE_LOWMEM)) +#define IS_SPECIAL_STAGE2 (get_param(MODE_SPECIAL_STAGE2)) +#define IS_RAMDISK (get_param(MODE_RAMDISK)) +#define IS_CHANGEDISK (get_param(MODE_CHANGEDISK)) +#define IS_UPDATEMODULES (get_param(MODE_UPDATEMODULES)) + +void fatal_error(char *msg) __attribute__ ((noreturn)); + + +void stg1_error_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); +void stg1_info_message(char *msg, ...) __attribute__ ((format (printf, 1, 2))); + +#endif diff --git a/stdio-frontend.c b/stdio-frontend.c new file mode 100644 index 0000000..5b37eaf --- /dev/null +++ b/stdio-frontend.c @@ -0,0 +1,361 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + * Each different frontend must implement all functions defined in frontend.h + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "frontend.h" + + +void init_frontend(char * welcome_msg) +{ + printf(welcome_msg); +} + + +void finish_frontend(void) +{ +} + +static void get_any_response(void) +{ + unsigned char t; + printf("\n\t(press to proceed)"); + fflush(stdout); + read(0, &t, 1); + fcntl(0, F_SETFL, O_NONBLOCK); + while (read(0, &t, 1) > 0); + fcntl(0, F_SETFL, 0); +} + +static int get_int_response(void) +{ + char s[50]; + int j = 0, i = 0; /* (0) tied to Cancel */ + fflush(stdout); + read(0, &(s[i++]), 1); + fcntl(0, F_SETFL, O_NONBLOCK); + do { + int v = s[i-1]; + if (v >= '0' && v <= '9') + j = j*10 + (v - '0'); + } while (read(0, &(s[i++]), 1) > 0 && i < sizeof(s)); + fcntl(0, F_SETFL, 0); + return j; +} + +static char * get_string_response(char * initial_string) +{ + /* I won't use a scanf/%s since I also want the null string to be accepted -- also, I want the initial_string */ + char s[500]; + int i = 0; + char buf[10]; + int b_index = 0; + char b; + + struct termios t; + + memset(s, '\0', sizeof(s)); + + if (initial_string) { + printf(initial_string); + strcpy(s, initial_string); + i = strlen(s); + } + + /* from ncurses/tinfo/lib_raw.c:(cbreak) */ + tcgetattr(0, &t); + t.c_lflag &= ~ICANON; + t.c_lflag |= ISIG; + t.c_lflag &= ~ECHO; + t.c_iflag &= ~ICRNL; + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + tcsetattr(0, TCSADRAIN, &t); + + fflush(stdout); + + fcntl(0, F_SETFL, O_NONBLOCK); + + while (1) { + if (read(0, &b, 1) > 0) { + if (b_index == 1) { + if (b == 91) { + buf[b_index] = b; + b_index++; + continue; + } + else + b_index = 0; + } + if (b_index == 2) { + if (b == 67) { + if (s[i] != '\0') { + printf("\033[C"); + i++; + } + } + if (b == 68) { + if (i > 0) { + printf("\033[D"); + i--; + } + } + b_index = 0; + continue; + } + + if (b == 13) + break; + if (b == 127) { + if (i > 0) { + printf("\033[D"); + printf(" "); + printf("\033[D"); + if (s[i] == '\0') + s[i-1] = '\0'; + else + s[i-1] = ' '; + i--; + } + } else if (b == 27) { + buf[b_index] = b; + b_index++; + } else { + printf("%c", b); + s[i] = b; + i++; + } + } + } + + t.c_lflag |= ICANON; + t.c_lflag |= ECHO; + t.c_iflag |= ICRNL; + tcsetattr(0, TCSADRAIN, &t); + + fcntl(0, F_SETFL, 0); + + printf("\n"); + return strdup(s); +} + +static void blocking_msg(char *type, char *fmt, va_list ap) +{ + printf(type); + vprintf(fmt, ap); + get_any_response(); +} + +void verror_message(char *msg, va_list ap) +{ + blocking_msg("> Error! ", msg, ap); +} + +void vinfo_message(char *msg, va_list ap) +{ + blocking_msg("> Notice: ", msg, ap); +} + +void vwait_message(char *msg, va_list ap) +{ + printf("Please wait: "); + vprintf(msg, ap); + fflush(stdout); +} + +void remove_wait_message(void) +{ + printf("\n"); +} + + +static int size_progress; +static int actually_drawn; +#define PROGRESS_SIZE 45 +void init_progression(char *msg, int size) +{ + int i; + size_progress = size; + printf("%s ", msg); + if (size) { + actually_drawn = 0; + for (i=0; i size_progress) + current_size = size_progress; + while ((int)((current_size*PROGRESS_SIZE)/size_progress) > actually_drawn) { + printf("*"); + actually_drawn++; + } + } else + printf("\033[GStatus: [%8d] bytes loaded...", current_size); + + fflush(stdout); +} + +void end_progression(void) +{ + if (size_progress) { + update_progression(size_progress); + printf("]\n"); + } else + printf(" done.\n"); +} + + +enum return_type ask_from_list_comments(char *msg, char ** elems, char ** elems_comments, char ** choice) +{ + int justify_number = 1; + void print_choice_number(int i) { + char tmp[500]; + snprintf(tmp, sizeof(tmp), "[%%%dd]", justify_number); + printf(tmp, i); + } + char ** sav_elems = elems; + int i = 1; + int j = 0; + + while (elems && *elems) { + elems++; + i++; + } + if (i >= 10) + justify_number = 2; + + elems = sav_elems; + i = 1; + + printf("> %s\n", msg); + print_choice_number(0); + printf(" Cancel"); + + while (elems && *elems) { + if (elems_comments && *elems_comments) { + printf("\n"); + print_choice_number(i); + printf(" %s (%s)", *elems, *elems_comments); + j = 0; + } else { + if (j == 0) + printf("\n"); + print_choice_number(i); + printf(" %-14s ", *elems); + j++; + } + if (j == 4) + j = 0; + + if (elems_comments) + elems_comments++; + i++; + elems++; + } + + printf("\n? "); + + j = get_int_response(); + + if (j == 0) + return RETURN_BACK; + + if (j >= 1 && j <= i) { + *choice = strdup(sav_elems[j-1]); + return RETURN_OK; + } + + return RETURN_ERROR; +} + + +enum return_type ask_from_list(char *msg, char ** elems, char ** choice) +{ + return ask_from_list_comments(msg, elems, NULL, choice); +} + + +enum return_type ask_yes_no(char *msg) +{ + int j; + + printf("> %s\n[0] Yes [1] No [2] Back\n? ", msg); + + j = get_int_response(); + + if (j == 0) + return RETURN_OK; + else if (j == 2) + return RETURN_BACK; + else return RETURN_ERROR; +} + + +enum return_type ask_from_entries(char *msg, char ** questions, char *** answers, int entry_size, void (*callback_func)(char ** strings)) +{ + int j, i = 0; + char ** already_answers = NULL; + + printf("> %s\n", msg); + + while (questions && *questions) { + printf("(%c) %s\n", i + 'a', *questions); + i++; + questions++; + } + + if (*answers == NULL) + *answers = (char **) malloc(sizeof(char *) * i); + else + already_answers = *answers; + + while (1) { + int r; + for (j = 0 ; j < i ; j++) { + printf("(%c) ? ", j + 'a'); + if (already_answers && *already_answers) { + (*answers)[j] = get_string_response(*already_answers); + already_answers++; + } else + (*answers)[j] = get_string_response(NULL); + + } + printf("[0] Cancel [1] Accept [2] Re-enter answers\n? "); + r = get_int_response(); + if (r == 0) + return RETURN_BACK; + if (r == 1) + return RETURN_OK; + } +} diff --git a/tools.c b/tools.c new file mode 100644 index 0000000..81ccc0a --- /dev/null +++ b/tools.c @@ -0,0 +1,435 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "stage1.h" +#include "log.h" +#include "mount.h" +#include "frontend.h" +#include "automatic.h" + +#include "tools.h" + + +static struct param_elem params[50]; +static int param_number = 0; + +void process_cmdline(void) +{ + char buf[512]; + int fd, size, i; + + log_message("opening /proc/cmdline... "); + + if ((fd = open("/proc/cmdline", O_RDONLY)) == -1) + fatal_error("could not open /proc/cmdline"); + + size = read(fd, buf, sizeof(buf)); + buf[size-1] = '\0'; // -1 to eat the \n + close(fd); + + log_message("\t%s", buf); + + i = 0; + while (buf[i] != '\0') { + char *name, *value = NULL; + int j = i; + while (buf[i] != ' ' && buf[i] != '=' && buf[i] != '\0') + i++; + if (i == j) { + i++; + continue; + } + name = memdup(&buf[j], i-j + 1); + name[i-j] = '\0'; + + if (buf[i] == '=') { + int k = i+1; + i++; + while (buf[i] != ' ' && buf[i] != '\0') + i++; + value = memdup(&buf[k], i-k + 1); + value[i-k] = '\0'; + } + + params[param_number].name = name; + params[param_number].value = value; + param_number++; + if (!strcmp(name, "expert")) set_param(MODE_EXPERT); + if (!strcmp(name, "changedisk")) set_param(MODE_CHANGEDISK); + if (!strcmp(name, "updatemodules")) set_param(MODE_UPDATEMODULES); + if (!strcmp(name, "rescue")) set_param(MODE_RESCUE); + if (!strcmp(name, "special_stage2")) set_param(MODE_SPECIAL_STAGE2); + if (!strcmp(name, "lowmem")) set_param(MODE_LOWMEM); + if (!strcmp(name, "automatic")) { + set_param(MODE_AUTOMATIC); + grab_automatic_params(value); + } + if (buf[i] == '\0') + break; + i++; + } + + log_message("\tgot %d args", param_number); +} + + +int stage1_mode = 0; + +int get_param(int i) +{ +#ifdef SPAWN_INTERACTIVE + static int fd = 0; + char buf[5000]; + char * ptr; + int nb; + + if (fd <= 0) { + fd = open(interactive_fifo, O_RDONLY); + if (fd == -1) + return (stage1_mode & i); + fcntl(fd, F_SETFL, O_NONBLOCK); + } + + if (fd > 0) { + if ((nb = read(fd, buf, sizeof(buf))) > 0) { + buf[nb] = '\0'; + ptr = buf; + while ((ptr = strstr(ptr, "+ "))) { + if (!strncmp(ptr+2, "expert", 6)) set_param(MODE_EXPERT); + if (!strncmp(ptr+2, "rescue", 6)) set_param(MODE_RESCUE); + ptr++; + } + ptr = buf; + while ((ptr = strstr(ptr, "- "))) { + if (!strncmp(ptr+2, "expert", 6)) unset_param(MODE_EXPERT); + if (!strncmp(ptr+2, "rescue", 6)) unset_param(MODE_RESCUE); + ptr++; + } + } + } +#endif + + return (stage1_mode & i); +} + +char * get_param_valued(char *param_name) +{ + int i; + for (i = 0; i < param_number ; i++) + if (!strcmp(params[i].name, param_name)) + return params[i].value; + + return NULL; +} + +void set_param_valued(char *param_name, char *param_value) +{ + params[param_number].name = param_name; + params[param_number].value = param_value; + param_number++; +} + +void set_param(int i) +{ + stage1_mode |= i; + if (i == MODE_RESCUE) { + set_param_valued("special_stage2", "rescue"); + set_param(MODE_SPECIAL_STAGE2); + } +} + +void unset_param(int i) +{ + stage1_mode &= ~i; +} + +// warning, many things rely on the fact that: +// - when failing it returns 0 +// - it stops on first non-digit char +int charstar_to_int(char * s) +{ + int number = 0; + while (*s && isdigit(*s)) { + number = (number * 10) + (*s - '0'); + s++; + } + return number; +} + +int total_memory(void) +{ + int value; + struct stat statr; + if (stat("/proc/kcore", &statr)) + return 0; + + /* drakx powered: use /proc/kcore and rounds every 4 Mbytes */ + value = 4 * ((int)((float)statr.st_size / 1024 / 1024 / 4 + 0.5)); + log_message("Total Memory: %d Mbytes", value); + + return value; +} + + +int ramdisk_possible(void) +{ + if (total_memory() > (IS_RESCUE ? MEM_LIMIT_RESCUE : MEM_LIMIT_RAMDISK)) + return 1; + else { + log_message("warning, ramdisk is not possible due to low mem!"); + return 0; + } +} + + +static void save_stuff_for_rescue(void) +{ + void save_this_file(char * file) { + char buf[5000]; + int fd_r, fd_w, i; + char location[100]; + + if ((fd_r = open(file, O_RDONLY)) < 0) { + log_message("can't open %s for read", file); + return; + } + strcpy(location, STAGE2_LOCATION); + strcat(location, file); + if ((fd_w = open(location, O_WRONLY)) < 0) { + log_message("can't open %s for write", location); + close(fd_r); + return; + } + if ((i = read(fd_r, buf, sizeof(buf))) <= 0) { + log_message("can't read from %s", file); + close(fd_r); close(fd_w); + return; + } + if (write(fd_w, buf, i) != i) + log_message("can't write %d bytes to %s", i, location); + close(fd_r); close(fd_w); + log_message("saved file %s for rescue (%d bytes)", file, i); + } + save_this_file("/etc/resolv.conf"); +} + + +enum return_type load_ramdisk_fd(int ramdisk_fd, int size) +{ + BZFILE * st2; + char * ramdisk = "/dev/ram3"; /* warning, verify that this file exists in the initrd, and that root=/dev/ram3 is actually passed to the kernel at boot time */ + int ram_fd; + char buffer[32768]; + int z_errnum; + char * wait_msg = "Loading program into memory..."; + int bytes_read = 0; + int actually; + int seems_ok = 0; + + st2 = BZ2_bzdopen(ramdisk_fd, "r"); + + if (!st2) { + log_message("Opening compressed ramdisk: %s", BZ2_bzerror(st2, &z_errnum)); + stg1_error_message("Could not open compressed ramdisk file."); + return RETURN_ERROR; + } + + ram_fd = open(ramdisk, O_WRONLY); + if (ram_fd == -1) { + log_perror(ramdisk); + stg1_error_message("Could not open ramdisk device file."); + return RETURN_ERROR; + } + + init_progression(wait_msg, size); + + while ((actually = BZ2_bzread(st2, buffer, sizeof(buffer))) > 0) { + seems_ok = 1; + if (write(ram_fd, buffer, actually) != actually) { + log_perror("writing ramdisk"); + remove_wait_message(); + return RETURN_ERROR; + } + update_progression((int)((bytes_read += actually) / RAMDISK_COMPRESSION_RATIO)); + } + + if (!seems_ok) { + log_message("reading compressed ramdisk: %s", BZ2_bzerror(st2, &z_errnum)); + BZ2_bzclose(st2); /* opened by gzdopen, but also closes the associated fd */ + close(ram_fd); + remove_wait_message(); + stg1_error_message("Could not uncompress second stage ramdisk. " + "This is probably an hardware error while reading the data. " + "(this may be caused by a hardware failure or a Linux kernel bug)"); + return RETURN_ERROR; + } + + end_progression(); + + BZ2_bzclose(st2); /* opened by gzdopen, but also closes the associated fd */ + close(ram_fd); + + if (my_mount(ramdisk, STAGE2_LOCATION, "ext2", 1)) + return RETURN_ERROR; + + set_param(MODE_RAMDISK); + + if (IS_RESCUE) { + save_stuff_for_rescue(); + if (umount(STAGE2_LOCATION)) { + log_perror(ramdisk); + return RETURN_ERROR; + } + return RETURN_OK; /* fucksike, I lost several hours wondering why the kernel won't see the rescue if it is alreay mounted */ + } + + return RETURN_OK; +} + + +char * get_ramdisk_realname(void) +{ + char img_name[500]; + char * stg2_name = get_param_valued("special_stage2"); + char * begin_img = RAMDISK_LOCATION; + char * end_img = "_stage2.bz2"; + + if (!stg2_name) + stg2_name = "mdkinst"; + + if (IS_RESCUE) + stg2_name = "rescue"; + + strcpy(img_name, begin_img); + strcat(img_name, stg2_name); + strcat(img_name, end_img); + + return strdup(img_name); +} + + +enum return_type load_ramdisk(void) +{ + int st2_fd; + struct stat statr; + char img_name[500]; + + strcpy(img_name, IMAGE_LOCATION); + strcat(img_name, get_ramdisk_realname()); + + log_message("trying to load %s as a ramdisk", img_name); + + st2_fd = open(img_name, O_RDONLY); /* to be able to see the progression */ + + if (st2_fd == -1) { + log_message("open ramdisk file (%s) failed", img_name); + stg1_error_message("Could not open compressed ramdisk file (%s).", img_name); + return RETURN_ERROR; + } + + if (stat(img_name, &statr)) + return RETURN_ERROR; + else + return load_ramdisk_fd(st2_fd, statr.st_size); +} + +/* pixel's */ +void * memdup(void *src, size_t size) +{ + void * r; + r = malloc(size); + memcpy(r, src, size); + return r; +} + + +static char ** my_env = NULL; +static int env_size = 0; + +void handle_env(char ** env) +{ + char ** ptr = env; + while (ptr && *ptr) { + ptr++; + env_size++; + } + my_env = malloc(sizeof(char *) * 100); + memcpy(my_env, env, sizeof(char *) * (env_size+1)); +} + +char ** grab_env(void) { + return my_env; +} + +void add_to_env(char * name, char * value) +{ + char tmp[500]; + sprintf(tmp, "%s=%s", name, value); + my_env[env_size] = strdup(tmp); + env_size++; + my_env[env_size] = NULL; +} + + +char ** list_directory(char * direct) +{ + char * tmp[50000]; /* in /dev there can be many many files.. */ + int i = 0; + struct dirent *ep; + DIR *dp = opendir(direct); + while (dp && (ep = readdir(dp))) { + if (strcmp(ep->d_name, ".") && strcmp(ep->d_name, "..")) { + tmp[i] = strdup(ep->d_name); + i++; + } + } + if (dp) + closedir(dp); + tmp[i] = NULL; + return memdup(tmp, sizeof(char*) * (i+1)); +} + + +int string_array_length(char ** a) +{ + int i = 0; + if (!a) + return -1; + while (a && *a) { + a++; + i++; + } + return i; +} diff --git a/tools.h b/tools.h new file mode 100644 index 0000000..5d38b03 --- /dev/null +++ b/tools.h @@ -0,0 +1,53 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan (ewt@redhat.com) + * + * Copyright 1996 Red Hat Software + * + */ + +#ifndef _TOOLS_H_ +#define _TOOLS_H_ + +#include + +void process_cmdline(void); +int get_param(int i); +void set_param(int i); +void unset_param(int i); +int charstar_to_int(char * s); +int total_memory(void); +int ramdisk_possible(void); +char * get_ramdisk_realname(void); +enum return_type load_ramdisk(void); +enum return_type load_ramdisk_fd(int ramdisk_fd, int size); +void * memdup(void *src, size_t size); +void add_to_env(char * name, char * value); +void handle_env(char ** env); +char ** grab_env(void); +char ** list_directory(char * direct); +int string_array_length(char ** a); + +struct param_elem +{ + char * name; + char * value; +}; + +#define ptr_begins_static_str(pointer,static_str) (!strncmp(pointer,static_str,sizeof(static_str)-1)) +#define streq !strcmp + +#endif diff --git a/url.c b/url.c new file mode 100644 index 0000000..de14596 --- /dev/null +++ b/url.c @@ -0,0 +1,501 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan and Matt Wilson + * + * Copyright 1999 Red Hat, Inc. + * + */ + +#include +// #include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +// #include +#include +#include +#include +#include + +#include +#include +#include + +#include "dns.h" +#include "log.h" +#include "tools.h" + +#include "url.h" + + +#define TIMEOUT_SECS 60 +#define BUFFER_SIZE 4096 + + +static int ftp_check_response(int sock, char ** str) +{ + static char buf[BUFFER_SIZE + 1]; + int bufLength = 0; + struct pollfd polls; + char * chptr, * start; + int bytesRead, rc = 0; + int doesContinue = 1; + char errorCode[4]; + + errorCode[0] = '\0'; + + do { + polls.fd = sock; + polls.events = POLLIN; + if (poll(&polls, 1, TIMEOUT_SECS*1000) != 1) + return FTPERR_BAD_SERVER_RESPONSE; + + bytesRead = read(sock, buf + bufLength, sizeof(buf) - bufLength - 1); + + bufLength += bytesRead; + + buf[bufLength] = '\0'; + + /* divide the response into lines, checking each one to see if + we are finished or need to continue */ + + start = chptr = buf; + + do { + while (*chptr != '\n' && *chptr) chptr++; + + if (*chptr == '\n') { + *chptr = '\0'; + if (*(chptr - 1) == '\r') *(chptr - 1) = '\0'; + if (str) *str = start; + + if (errorCode[0]) { + if (!strncmp(start, errorCode, 3) && start[3] == ' ') + doesContinue = 0; + } else { + strncpy(errorCode, start, 3); + errorCode[3] = '\0'; + if (start[3] != '-') { + doesContinue = 0; + } + } + + start = chptr + 1; + chptr++; + } else { + chptr++; + } + } while (*chptr); + + if (doesContinue && chptr > start) { + memcpy(buf, start, chptr - start - 1); + bufLength = chptr - start - 1; + } else { + bufLength = 0; + } + } while (doesContinue); + + if (*errorCode == '4' || *errorCode == '5') { + if (!strncmp(errorCode, "550", 3)) { + return FTPERR_FILE_NOT_FOUND; + } + + return FTPERR_BAD_SERVER_RESPONSE; + } + + if (rc) return rc; + + return 0; +} + +static int ftp_command(int sock, char * command, char * param) +{ + char buf[500]; + int rc; + + strcpy(buf, command); + if (param) { + strcat(buf, " "); + strcat(buf, param); + } + + strcat(buf, "\r\n"); + + if (write(sock, buf, strlen(buf)) != strlen(buf)) { + return FTPERR_SERVER_IO_ERROR; + } + + if ((rc = ftp_check_response(sock, NULL))) + return rc; + + return 0; +} + +static int get_host_address(char * host, struct in_addr * address) +{ + if (isdigit(host[0])) { + if (!inet_aton(host, address)) { + return FTPERR_BAD_HOST_ADDR; + } + } else { + if (mygethostbyname(host, address)) + return FTPERR_BAD_HOSTNAME; + } + + return 0; +} + +int ftp_open_connection(char * host, char * name, char * password, char * proxy) +{ + int sock; + struct in_addr serverAddress; + struct sockaddr_in destPort; + char * buf; + int rc; + int port = 21; + + if (!strcmp(name, "")) { + name = "anonymous"; + password = "-drakx@"; + } + + if (strcmp(proxy, "")) { + buf = alloca(strlen(name) + strlen(host) + 5); + sprintf(buf, "%s@%s", name, host); + name = buf; + host = proxy; + } + + if ((rc = get_host_address(host, &serverAddress))) return rc; + + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (sock < 0) { + return FTPERR_FAILED_CONNECT; + } + + destPort.sin_family = AF_INET; + destPort.sin_port = htons(port); + destPort.sin_addr = serverAddress; + + if (connect(sock, (struct sockaddr *) &destPort, sizeof(destPort))) { + close(sock); + return FTPERR_FAILED_CONNECT; + } + + /* ftpCheckResponse() assumes the socket is nonblocking */ + if (fcntl(sock, F_SETFL, O_NONBLOCK)) { + close(sock); + return FTPERR_FAILED_CONNECT; + } + + if ((rc = ftp_check_response(sock, NULL))) { + return rc; + } + + if ((rc = ftp_command(sock, "USER", name))) { + close(sock); + return rc; + } + + if ((rc = ftp_command(sock, "PASS", password))) { + close(sock); + return rc; + } + + if ((rc = ftp_command(sock, "TYPE", "I"))) { + close(sock); + return rc; + } + + return sock; +} + + +int ftp_data_command(int sock, char * command, char * param) +{ + int dataSocket; + struct sockaddr_in dataAddress; + int i, j; + char * passReply; + char * chptr; + char retrCommand[500]; + int rc; + + if (write(sock, "PASV\r\n", 6) != 6) { + return FTPERR_SERVER_IO_ERROR; + } + if ((rc = ftp_check_response(sock, &passReply))) + return FTPERR_PASSIVE_ERROR; + + chptr = passReply; + while (*chptr && *chptr != '(') chptr++; + if (*chptr != '(') return FTPERR_PASSIVE_ERROR; + chptr++; + passReply = chptr; + while (*chptr && *chptr != ')') chptr++; + if (*chptr != ')') return FTPERR_PASSIVE_ERROR; + *chptr-- = '\0'; + + while (*chptr && *chptr != ',') chptr--; + if (*chptr != ',') return FTPERR_PASSIVE_ERROR; + chptr--; + while (*chptr && *chptr != ',') chptr--; + if (*chptr != ',') return FTPERR_PASSIVE_ERROR; + *chptr++ = '\0'; + + /* now passReply points to the IP portion, and chptr points to the + port number portion */ + + dataAddress.sin_family = AF_INET; + if (sscanf(chptr, "%d,%d", &i, &j) != 2) { + return FTPERR_PASSIVE_ERROR; + } + dataAddress.sin_port = htons((i << 8) + j); + + chptr = passReply; + while (*chptr++) { + if (*chptr == ',') *chptr = '.'; + } + + if (!inet_aton(passReply, &dataAddress.sin_addr)) + return FTPERR_PASSIVE_ERROR; + + dataSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (dataSocket < 0) { + return FTPERR_FAILED_CONNECT; + } + + if (!param) + sprintf(retrCommand, "%s\r\n", command); + else + sprintf(retrCommand, "%s %s\r\n", command, param); + + i = strlen(retrCommand); + + if (write(sock, retrCommand, i) != i) { + return FTPERR_SERVER_IO_ERROR; + } + + if (connect(dataSocket, (struct sockaddr *) &dataAddress, + sizeof(dataAddress))) { + close(dataSocket); + return FTPERR_FAILED_DATA_CONNECT; + } + + if ((rc = ftp_check_response(sock, NULL))) { + close(dataSocket); + return rc; + } + + return dataSocket; +} + + +static int ftp_get_filesize(int sock, char * remotename) +{ + int size = 0; + char buf[2000]; + char file[500]; + char * ptr; + int fd, rc, tot; + int i; + + strcpy(buf, remotename); + ptr = strrchr(buf, '/'); + if (!*ptr) + return -1; + *ptr = '\0'; + + strcpy(file, ptr+1); + + if ((rc = ftp_command(sock, "CWD", buf))) { + return -1; + } + + fd = ftp_data_command(sock, "LIST", NULL); + if (fd <= 0) { + close(sock); + return -1; + } + + ptr = buf; + while ((tot = read(fd, ptr, sizeof(buf) - (ptr - buf))) != 0) + ptr += tot; + *ptr = '\0'; + close(fd); + + if (!(ptr = strstr(buf, file))) { + log_message("FTP/get_filesize: Bad mood, directory does not contain searched file (%s)", file); + if (ftp_end_data_command(sock)) + close(sock); + return -1; + } + + for (i=0; i<4; i++) { + while (*ptr && *ptr != ' ') + ptr--; + while (*ptr && *ptr == ' ') + ptr--; + } + while (*ptr && *ptr != ' ') + ptr--; + + if (ptr) + size = charstar_to_int(ptr+1); + else + size = 0; + + if (ftp_end_data_command(sock)) { + close(sock); + return -1; + } + + return size; +} + + +int ftp_start_download(int sock, char * remotename, int * size) +{ + if ((*size = ftp_get_filesize(sock, remotename)) == -1) { + log_message("FTP: could not get filesize (trying to continue)"); + *size = 0; + } + return ftp_data_command(sock, "RETR", remotename); +} + + +int ftp_end_data_command(int sock) +{ + if (ftp_check_response(sock, NULL)) + return FTPERR_BAD_SERVER_RESPONSE; + + return 0; +} + + +int http_download_file(char * hostname, char * remotename, int * size) +{ + char * buf; + char headers[4096]; + char * nextChar = headers; + int checkedCode; + struct in_addr serverAddress; + struct pollfd polls; + int sock; + int rc; + struct sockaddr_in destPort; + char * header_content_length = "Content-Length: "; + + if ((rc = get_host_address(hostname, &serverAddress))) return rc; + + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (sock < 0) { + return FTPERR_FAILED_CONNECT; + } + + destPort.sin_family = AF_INET; + destPort.sin_port = htons(80); + destPort.sin_addr = serverAddress; + + if (connect(sock, (struct sockaddr *) &destPort, sizeof(destPort))) { + close(sock); + return FTPERR_FAILED_CONNECT; + } + + buf = alloca(strlen(remotename) + 20); + sprintf(buf, "GET %s HTTP/0.9\r\n\r\n", remotename); + write(sock, buf, strlen(buf)); + + /* This is fun; read the response a character at a time until we: + + 1) Get our first \r\n; which lets us check the return code + 2) Get a \r\n\r\n, which means we're done */ + + *nextChar = '\0'; + checkedCode = 0; + while (!strstr(headers, "\r\n\r\n")) { + polls.fd = sock; + polls.events = POLLIN; + rc = poll(&polls, 1, TIMEOUT_SECS*1000); + + if (rc == 0) { + close(sock); + return FTPERR_SERVER_TIMEOUT; + } else if (rc < 0) { + close(sock); + return FTPERR_SERVER_IO_ERROR; + } + + if (read(sock, nextChar, 1) != 1) { + close(sock); + return FTPERR_SERVER_IO_ERROR; + } + + nextChar++; + *nextChar = '\0'; + + if (nextChar - headers == sizeof(headers)) { + close(sock); + return FTPERR_SERVER_IO_ERROR; + } + + if (!checkedCode && strstr(headers, "\r\n")) { + char * start, * end; + + checkedCode = 1; + start = headers; + while (!isspace(*start) && *start) start++; + if (!*start) { + close(sock); + return FTPERR_SERVER_IO_ERROR; + } + start++; + + end = start; + while (!isspace(*end) && *end) end++; + if (!*end) { + close(sock); + return FTPERR_SERVER_IO_ERROR; + } + + *end = '\0'; + if (!strcmp(start, "404")) { + close(sock); + return FTPERR_FILE_NOT_FOUND; + } else if (strcmp(start, "200")) { + close(sock); + return FTPERR_BAD_SERVER_RESPONSE; + } + + *end = ' '; + } + } + + if ((buf = strstr(headers, header_content_length))) + *size = charstar_to_int(buf + strlen(header_content_length)); + else + *size = 0; + + return sock; +} diff --git a/url.h b/url.h new file mode 100644 index 0000000..5a59bd8 --- /dev/null +++ b/url.h @@ -0,0 +1,44 @@ +/* + * Guillaume Cottenceau (gc@mandrakesoft.com) + * + * Copyright 2000 MandrakeSoft + * + * This software may be freely redistributed under the terms of the GNU + * public license. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Portions from Erik Troan and Matt Wilson + * + * Copyright 1999 Red Hat, Inc. + * + */ + +#ifndef _URL_H_ +#define _URL_H_ + +int ftp_open_connection(char * host, char * name, char * password, char * proxy); +int ftp_start_download(int sock, char * remotename, int * size); +int ftp_end_data_command(int sock); + +int http_download_file(char * hostname, char * remotename, int * size); + + +#define FTPERR_BAD_SERVER_RESPONSE -1 +#define FTPERR_SERVER_IO_ERROR -2 +#define FTPERR_SERVER_TIMEOUT -3 +#define FTPERR_BAD_HOST_ADDR -4 +#define FTPERR_BAD_HOSTNAME -5 +#define FTPERR_FAILED_CONNECT -6 +#define FTPERR_FILE_IO_ERROR -7 +#define FTPERR_PASSIVE_ERROR -8 +#define FTPERR_FAILED_DATA_CONNECT -9 +#define FTPERR_FILE_NOT_FOUND -10 +#define FTPERR_UNKNOWN -100 + +#endif diff --git a/usb-resource/.cvsignore b/usb-resource/.cvsignore new file mode 100644 index 0000000..a7d0cfa --- /dev/null +++ b/usb-resource/.cvsignore @@ -0,0 +1 @@ +usb-ids.h diff --git a/usb-resource/Makefile b/usb-resource/Makefile new file mode 100644 index 0000000..eb80ce6 --- /dev/null +++ b/usb-resource/Makefile @@ -0,0 +1,25 @@ + #****************************************************************************** + # + # $Id$ + # + # Guillaume Cottenceau (gc@mandrakesoft.com) + # + # Copyright 2000 MandrakeSoft + # + # This software may be freely redistributed under the terms of the GNU + # public license. + # + # You should have received a copy of the GNU General Public License + # along with this program; if not, write to the Free Software + # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + # + #***************************************************************************** + + +all: usb-ids.h + +usb-ids.h: /usr/share/ldetect-lst/usbtable update-usb-ids.pl + perl update-usb-ids.pl > $@ || rm -f $@ + +clean: + rm -f usb-ids.h diff --git a/usb-resource/update-usb-ids.pl b/usb-resource/update-usb-ids.pl new file mode 100755 index 0000000..2e66db6 --- /dev/null +++ b/usb-resource/update-usb-ids.pl @@ -0,0 +1,73 @@ +#!/usr/bin/perl + + +sub cat_ { local *F; open F, $_[0] or $_[1] ? die "cat of file $_[0] failed: $!\n" : return; my @l = ; wantarray ? @l : join '', @l } + + +-x "../mar/mar" or die "\t*FAILED* Sorry, need ../mar/mar binary\n"; + + +my @usbtable_tmp = cat_("/usr/share/ldetect-lst/usbtable"); +my @usbtable; +foreach (@usbtable_tmp) { + next if /\s*#/; + /\s*(\S+)\s+(\S+)\s+"(\S+)"\s+"([^"]*)"/ or next; + push @usbtable, { 'vendor' => $1, 'id' => $2, 'module' => $3, 'description' => $4 }; +} + + +print ' +struct usb_module_map { + unsigned short vendor; /* vendor */ + unsigned short id; /* device */ + const char *name; /* human readable name */ + const char *module; /* module to load */ +}; +'; + +print "#ifdef ENABLE_USB +struct pci_module_map usb_pci_ids[] = { + +"; + +require '/usr/bin/merge2pcitable.pl'; +my $drivers = read_pcitable("/usr/share/ldetect-lst/pcitable"); + +while (my ($k, $v) = each %$drivers) { + $v->[0] =~ /^usb-/ or next; + $k =~ /^(....)(....)/; + printf qq|\t{ 0x%s, 0x%s, "", "%s" },\n|, + $1, $2, $v->[0]; +} + +print "}; +int usb_num_ids=sizeof(usb_pci_ids)/sizeof(struct pci_module_map); +#endif +"; + + +my @t = ('usbnet'); + + +foreach $type (@t) { + my $modulez; + foreach (glob("../../all.modules/*/${type}_modules.mar")) { + -f $_ or die "\t*FAILED* Sorry, need $_ mar file\n"; + push @$modulez, (`../mar/mar -l $_`); + } + + print "#ifdef ENABLE_".uc($type)." +struct usb_module_map ${type}_usb_ids[] = { +"; + foreach my $usbentry (@usbtable) { + grep(/^\t$usbentry->{'module'}\.o\s/, @$modulez) or next; + printf qq|\t{ %s, %s, "%s", "%s" },\n|, + $usbentry->{'vendor'}, $usbentry->{'id'}, $usbentry->{'description'}, $usbentry->{'module'}; + } + + print "}; +int ${type}_usb_num_ids=sizeof(${type}_usb_ids)/sizeof(struct usb_module_map); +#endif +"; + +}