Release of pcmciautils-009 (2005-09-13)

Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
diff --git a/Makefile b/Makefile
index 30ef605..ea93a75 100644
--- a/Makefile
+++ b/Makefile
@@ -40,7 +40,7 @@
 CBDUMP =			cbdump
 CISDUMP =			dump_cis
 
-VERSION =	008
+VERSION =	009
 #INSTALL_DIR =	/usr/local/sbin
 RELEASE_NAME =	pcmciautils-$(VERSION)
 
@@ -102,12 +102,12 @@
 # check if compiler option is supported
 cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;}
 
-WARNINGS := -Wall -fno-builtin -Wchar-subscripts -Wpointer-arith -Wsign-compare
+WARNINGS := -Wall -Wchar-subscripts -Wpointer-arith -Wsign-compare
 WARNINGS += $(call cc-supports,-Wno-pointer-sign)
 WARNINGS += $(call cc-supports,-Wdeclaration-after-statement)
 WARNINGS += -Wshadow
 
-CFLAGS := -pipe
+CFLAGS := -pipe -DVERSION=\"$(VERSION)\"
 YFLAGS := -d
 
 HEADERS = \
diff --git a/src/lex_config.l b/src/lex_config.l
index 746edc1..2d99966 100644
--- a/src/lex_config.l
+++ b/src/lex_config.l
@@ -15,6 +15,7 @@
  */
 
 #undef src
+#undef VERSION
 
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/src/pccardctl.c b/src/pccardctl.c
index a8ed681..02ad3ee 100644
--- a/src/pccardctl.c
+++ b/src/pccardctl.c
@@ -26,6 +26,37 @@
 #define MAX_SOCKET 8
 
 
+static int pccardctl_power_one(unsigned long socket_no, unsigned int device,
+			       unsigned int power)
+{
+	int ret;
+	char file[SYSFS_PATH_MAX];
+        struct sysfs_attribute *attr;
+
+	snprintf(file, SYSFS_PATH_MAX,
+		 "/sys/bus/pcmcia/devices/%lu.%u/power/state",
+		 socket_no, device);
+
+        attr = sysfs_open_attribute(file);
+        if (!attr)
+                return -ENODEV;
+
+        ret = sysfs_write_attribute(attr, power ? "3" : "0", 1);
+
+        sysfs_close_attribute(attr);
+
+	return (ret);
+}
+
+static int pccardctl_power(unsigned long socket_no, unsigned int power)
+{
+	unsigned int i;
+	for (i=0; i<2; i++) /* max 2 devices per socket */
+		pccardctl_power_one(socket_no, i, power);
+
+	return 0;
+}
+
 static int pccardctl_echo_one(unsigned long socket_no, const char *in_file)
 {
         int ret;
@@ -187,12 +218,31 @@
 }
 
 static void print_header(void) {
-	printf("pccardctl (C) 2004 Dominik Brodowski, (C) 1999 David A. Hinds\n");
+	printf("pcmciautils %s\n", VERSION);
+	printf("Copyright (C) 2004-2005 Dominik Brodowski, (C) 1999 David A. Hinds\n");
 	printf("Report errors and bugs to <linux-pcmcia@lists.infradead.org>, please.\n");
 }
 
+static char *cmdname[] = {
+	"insert",
+	"eject",
+	"suspend",
+	"resume",
+	"reset",
+	"info",
+	"status",
+	"config",
+	"ident",
+};
+
 static void print_help(void) {
-	/* TBD */
+	unsigned int i;
+
+	printf("Usage: pccardctl COMMAND\n");
+	printf("Supported commands are:\n");
+	for (i = 0; i < sizeof(cmdname)/sizeof(cmdname[0]); i++) {
+		printf("\t%s\n", cmdname[i]);
+	}
 }
 
 static void print_unknown_arg(void) {
@@ -221,18 +271,6 @@
 	NCMD
 };
 
-static char *cmdname[] = {
-	"insert",
-	"eject",
-	"suspend",
-	"resume",
-	"reset",
-	"info",
-	"status",
-	"config",
-	"ident",
-};
-
 
 int main(int argc, char **argv) {
 	extern char *optarg;
@@ -316,6 +354,17 @@
 		case PCCARDCTL_IDENT:
 			ret = pccardctl_ident(cont);
 			break;
+		case PCCARDCTL_SUSPEND:
+			ret = pccardctl_power(cont, 3);
+			break;
+		case PCCARDCTL_RESET:
+			ret = pccardctl_power(cont, 3);
+			if (ret && socket_is_set)
+				return (ret);
+			/* fall through */
+		case PCCARDCTL_RESUME:
+			ret = pccardctl_power(cont, 0);
+			break;
 		default:
 			fprintf(stderr, "command '%s' not yet handled by pccardctl\n", cmdname[cmd]);
 			return -EAGAIN;
diff --git a/src/pcmcia-check-broken-cis.c b/src/pcmcia-check-broken-cis.c
index 82d8f14..d5597fa 100644
--- a/src/pcmcia-check-broken-cis.c
+++ b/src/pcmcia-check-broken-cis.c
@@ -13,14 +13,25 @@
  * (C) 2005             Dominik Brodowski
  */
 
+#include <fcntl.h>
+#include <getopt.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 #include <errno.h>
 #include <syslog.h>
 
+#include <sys/types.h>
+#include <sys/stat.h>
+
 #include "cistpl.h"
 
+
+#define FIRMWARE_PATH	"/lib/firmware"
+#define CIS_PATH	"/etc/pcmcia/cis"
+#define SOCKET_PATH	"/sys/class/pcmcia_socket/pcmcia_socket%d/cis"
+
 struct needs_cis {
 	unsigned long code;
 	unsigned long ofs;
@@ -39,20 +50,140 @@
 	{ },
 };
 
+int device_has_driver() {
+	char *devpath, *path;
+	struct stat sbuf;
+	
+	devpath = getenv("DEVPATH");
+	if (!devpath)
+		return ENODEV;
+	path = alloca(strlen(devpath)+15);
+	sprintf(path,"/sys/%s/driver", devpath);
+	if (!stat(path,&sbuf)) {
+		return 1;
+	}
+	return 0;
+}
+
+char *read_cis(char *cis_file, int *size) {
+	char *cis_path;
+	char *ret;
+	int rc, cis_fd;
+	struct stat sbuf;
+	
+	cis_path = alloca(strlen(FIRMWARE_PATH) + strlen(cis_file) + 2);
+	sprintf(cis_path,"%s/%s", FIRMWARE_PATH, cis_file);
+	cis_fd = open(cis_path, O_RDONLY);
+	if (cis_fd == -1) {
+		cis_path = alloca(strlen(CIS_PATH) + strlen(cis_file) + 2);
+		sprintf(cis_path,"%s/%s", CIS_PATH, cis_file);
+		if (cis_fd == -1) {
+			rc = errno;
+			errno = rc;
+			return NULL;
+		}
+	}
+	fstat(cis_fd, &sbuf);
+	ret = malloc(sbuf.st_size);
+	if (!ret) {
+		rc = errno;
+		close(cis_fd);
+		errno = rc;
+		return NULL;
+	}
+	if (read(cis_fd, ret, sbuf.st_size) != sbuf.st_size) {
+		rc = errno;
+		free(ret);
+		close(cis_fd);
+		errno = rc;
+		return NULL;
+	}
+	close(cis_fd);
+	*size = sbuf.st_size;
+	return ret;
+}
+
+int write_cis(char *cis, int socket_no, int size) {
+	char *cis_path;
+	int cis_fd, count, rc;
+	
+	cis_path = alloca(strlen(SOCKET_PATH) + 2);
+	sprintf(cis_path,SOCKET_PATH, socket_no);
+	
+	cis_fd = open(cis_path, O_RDWR);
+	if (cis_fd == -1) {
+		return errno;
+	}
+	
+	count = 0;
+	while (count < size) {
+		int c;
+		
+		c = write(cis_fd, cis+count, size-count);
+		if (c <= 0) {
+			rc = errno;
+			close(cis_fd);
+			return rc;
+		}
+		count += c;
+	}
+	close(cis_fd);
+	return 0;
+}
+
+int repair_cis(char *cis_file, int socket_no) {
+	char *cis;
+	int rc, size;
+	
+	if (device_has_driver()) {
+		return 0;
+	}
+	
+	cis = read_cis(cis_file, &size);
+	if (!cis)
+		return errno;
+	
+	rc = write_cis(cis, socket_no, size);
+	free(cis);
+	return rc;
+}
+
+static void usage(const char *progname) {
+	fprintf(stderr,
+		"Usage: %s [-r|--repair] <socketname>\n", progname);
+	exit(1);
+}
+
+static struct option options[] = { { "repair", 0, NULL, 'r' },
+				   { NULL, 0, NULL, 0 } };
+
 int main(int argc, char **argv) {
 	int ret;
+	char *socket;
 	unsigned int socket_no;
 	struct needs_cis * entry = NULL;
 	tuple_t tuple;
 	unsigned char buf[256];
+	int opt;
+	int repair = 0;
 
-	if (argc != 2)
-		return -EINVAL;
-
-	ret = sscanf(argv[1], "%u", &socket_no);
-	if (ret != 1)
-		return -ENODEV;
-
+	while ((opt = getopt_long(argc, argv, "r", options, NULL)) != -1) {
+		switch (opt) {
+		case 'r':
+			repair = 1;
+			break;
+		default:
+			usage(argv[0]);
+		}
+	}
+	if ((socket = getenv("SOCKET_NO"))) {
+		socket_no = (unsigned int)strtoul(socket, NULL, 0);
+	} else {
+		if (argc < optind + 1)
+			usage(argv[0]);
+		socket_no = strtoul(argv[optind], NULL, 0);
+	}
+	
 	ret = read_out_cis(socket_no, NULL);
 	if (ret)
 		return (ret);
@@ -78,8 +209,12 @@
 			entry++;
 			continue;
 		}
-
-		printf("%s", entry->cisfile);
+		
+		if (repair) {
+			return repair_cis(entry->cisfile, socket_no);
+		} else {
+			printf("%s", entry->cisfile);
+		}
 	};
 
 	return 0;
diff --git a/src/startup.c b/src/startup.c
index 0dd5f38..0197f4c 100644
--- a/src/startup.c
+++ b/src/startup.c
@@ -223,22 +223,30 @@
 int main(int argc, char *argv[])
 {
 	char *socket_no;
-	unsigned long socket;
+	unsigned long socket, i;
+	unsigned int all_sockets = 0;
 
 
 	if ((socket_no = getenv("SOCKET_NO"))) {
 		socket = strtoul(socket_no, NULL, 0);
 	} else if (argc == 2) {
 		socket = strtoul(argv[1], NULL, 0);
+	} else if (argc == 1) {
+		socket = 0;
+		all_sockets = 1;
 	} else {
 		return -EINVAL;
 	}
 
 	load_config();
 
-	adjust_resources(socket);
+	for (i = 0; i < MAX_SOCKS; i++) {
+		if ((socket != i) && (!all_sockets))
+			continue;
 
-	setup_done(socket);
+		adjust_resources(i);
+		setup_done(i);
+	}
 
 	return 0;
 }
diff --git a/src/yacc_config.y b/src/yacc_config.y
index f6df721..23fc054 100644
--- a/src/yacc_config.y
+++ b/src/yacc_config.y
@@ -19,6 +19,7 @@
 #include <sys/types.h>
 
 #include "startup.h"
+#undef VERSION
 
 /* If bison: generate nicer error messages */ 
 #define YYERROR_VERBOSE 1