/* * $Id: capiinit.c,v 1.17 2005/02/21 17:52:00 keil Exp $ * * $Log: capiinit.c,v $ * Revision 1.17 2005/02/21 17:52:00 keil * * have a separate config directory for firmware * * have a separate config directory for card tools * * Revision 1.16 2004/01/19 09:15:57 calle * Always use capifs, don't trust devfs. * * Revision 1.15 2004/01/16 15:27:12 calle * remove several warnings. * * Revision 1.14 2004/01/16 12:33:16 calle * Modifications to let ist run with patched 2.6 kernel. * Pure 2.6.0/2.6.1 is not working. * * Revision 1.13 2003/03/31 09:50:52 calle * Bugfix: fixed problems with activate and deactivate subcommands, when * AVM B1 PCI V4 is used. * * Revision 1.12 2003/03/11 13:39:07 paul * Also search for firmware in /usr/share/isdn, which is more in line with LSB * * Revision 1.11 2003/01/14 13:47:15 calle * New Commands to only load modules, only initialize cards, * only reset cards, inititialize a single card or reset a single card. * * Revision 1.10 2002/10/25 13:50:44 calle * The protocol value was not tranfered to the patchinfo. Because of * this for example NI1 did not work ... * * Revision 1.9 2002/05/23 12:52:36 calle * - Uaah. Bugfix for c2 patchvalues. * * Revision 1.8 2001/04/18 10:21:42 calle * support for "AVM ISDN Controller C2" added. * * Revision 1.7 2000/08/31 08:23:35 calle * - produce an error message, if a driver could not be loaded. * * Revision 1.6 2000/07/24 14:15:10 calle * Bugfix: pci controllers were always by initialized first in multi * controller environment. * * Revision 1.5 2000/07/24 08:38:04 calle * - Bugfix: devfs mount was never detected, because an extra / in path. * * Revision 1.4 2000/06/30 14:08:45 calle * - creat /dev/capi if not exist, and mount capifs if available and devfs * not availabe or not mounted on /dev. * - better error messages * * Revision 1.3 2000/06/29 15:17:21 calle * Mount capifs on /dev/capi if available. * * Revision 1.2 2000/05/18 15:20:18 calle * Umount capifs on "stop". * * Revision 1.1 2000/03/17 16:19:43 calle * New command capiinit, this will replace avmcapictrl in the future, if * called as "capiinit start" ist will load all modules, add all cards * configured in "/etc/capi.conf" and load the firmware to all active * cards. When called as "capiinit stop", it will deinit all cards and * remove all modules. Sample config in capiinit/capi.conf. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define _LINUX_LIST_H #include #include #include #include #if defined(HAVE_CONFIG_H) # include "config.h" #else # define I4LCONFDIR "/etc/isdn" #endif #define MODPROBE "/sbin/modprobe" static char capidevnameold[] = "/dev/capi20"; static char capidevnamenew[] = "/dev/isdn/capi20"; static char *capidevname = capidevnameold; static char *firmwarepath[] = { "/lib/firmware/isdn", "/usr/share/isdn", "/usr/lib/isdn", "/lib/isdn", NULL }; /* ---------------- global variables --------------------------------- */ static int capifd = -1; static int patchdebug = 0; /* -d || -debug */ static int silent = 0; /* -s || -silent */ char *configfilename = I4LCONFDIR "/capi.conf"; /* ---------------- utils -------------------------------------------- */ #define STRUCTALLOC(type) (type *)malloc(sizeof(type)) static FILE *fopen_with_errmsg(const char *path, const char *mode) { FILE *fp; if ((fp = fopen(path, mode)) == NULL) { int serrno = errno; fprintf(stderr, "ERROR: fopen(%s,%s) failed - %s (%d)\n", path, mode, strerror(serrno), serrno); } return fp; } static char *skip_whitespace(char *s) { while (*s && isspace(*s)) s++; return s; } static char *skip_nonwhitespace(char *s) { while (*s && !isspace(*s)) s++; return s; } /* ---------------- load module -------------------------------------- */ static int is_module_loaded(char *module) { static char *fn = "/proc/modules"; char buf[4096]; FILE *fp; char *s; if ((fp = fopen_with_errmsg(fn, "r")) == NULL) return 0; while (fgets(buf,sizeof(buf),fp)) { s = skip_nonwhitespace(buf); if (s) { *s = 0; if (strcmp(module,buf) == 0) { fclose(fp); return 1; } } } fclose(fp); return 0; } static int load_module(char *module, int silently) { char buf[1024]; snprintf(buf, sizeof(buf), "%s %s %s", MODPROBE, module, silently ? "2>/dev/null" : ""); return system(buf); } static int unload_module(char *module) { char buf[1024]; if (is_module_loaded(module)) { snprintf(buf, sizeof(buf), "%s -r %s", MODPROBE, module); return system(buf); } return 0; } /* ---------------- /proc/capi/controller ---------------------------- */ /* 1 b1pciv4 detected b1pciv4-e400 - - 0xe400 19 0xea003000 r4 2 c4 detected c4-d800 - - 0xd800 17 0xea001000 3 c4 detected c4-d800 - - 0xd800 17 0xea001000 4 c4 detected c4-d800 - - 0xd800 17 0xea001000 5 c4 detected c4-d800 - - 0xd800 17 0xea001000 */ #define CARD_FREE 0 #define CARD_DETECTED 1 #define CARD_LOADING 2 #define CARD_RUNNING 3 struct cardstatemap { char *name; int state; } cardstatemap[] = { { "free", CARD_FREE }, { "detected", CARD_DETECTED }, { "loading", CARD_LOADING }, { "running", CARD_RUNNING }, { 0 } }; static char *cardstate2str(int state) { struct cardstatemap *p; for (p = cardstatemap; p->name; p++) { if (state == p->state) return p->name; } return cardstatemap[0].name; } static int str2cardstate(char *s) { struct cardstatemap *p; for (p = cardstatemap; p->name; p++) { if (strcmp(p->name, s) == 0) return p->state; } return cardstatemap[0].state; } struct contrprocinfo { struct contrprocinfo *next; int contr; char driver[32]; int state; char name[32]; char driverinfo[32]; }; static void free_contrprocinfo(struct contrprocinfo **pp) { struct contrprocinfo *p; while (*pp) { p = *pp; *pp = p->next; free(p); } } static struct contrprocinfo *load_contrprocinfo(int *lastcontrp) { static char *fn = "/proc/capi/controller"; struct contrprocinfo *list, *p, **pp; char buf[4096]; FILE *fp; int line = 0; if (lastcontrp) *lastcontrp = 0; list = 0; if ((fp = fopen_with_errmsg(fn, "r")) == NULL) return 0; while (fgets(buf,sizeof(buf),fp)) { char *s, *tmp, *target; line++; if ((p = STRUCTALLOC(struct contrprocinfo)) == 0) { fprintf(stderr, "ERROR: %s:%d: malloc failed\n", fn, line); goto error; } memset(p, 0, sizeof(*p)); s = buf; /* contr */ tmp = s; p->contr = strtol(s, &tmp, 10); if (tmp == s) goto parseerror; /* driver */ target = skip_whitespace(tmp); s = skip_nonwhitespace(target); if (!*s) goto parseerror; *s++ = 0; snprintf(p->driver, sizeof(p->driver), "%s", target); /* state */ target = skip_whitespace(s); s = skip_nonwhitespace(target); if (!*s) goto parseerror; *s++ = 0; p->state = str2cardstate(target); /* name */ target = skip_whitespace(s); s = skip_nonwhitespace(target); if (!*s) goto parseerror; *s++ = 0; snprintf(p->name, sizeof(p->name), "%s", target); /* driverinfo */ target = skip_whitespace(s); while (*s && *s != '\n') s++; if (*s) *s = 0; snprintf(p->driverinfo, sizeof(p->driverinfo), "%s", target); for (pp = &list; *pp; pp = &(*pp)->next) ; *pp = p; if (lastcontrp && *lastcontrp < p->contr) *lastcontrp = p->contr; } fclose(fp); return list; parseerror: fprintf(stderr, "ERROR: %s:%d: parse error\n", fn, line); error: fclose(fp); free_contrprocinfo(&list); return 0; } static struct contrprocinfo * find_contrprocinfo(struct contrprocinfo *cpinfo, int contr) { struct contrprocinfo *p; for (p = cpinfo; p; p = p->next) if (p->contr == contr) break; return p; } static void show_contrprocinfo(struct contrprocinfo *cpinfo, char *cardname) { struct contrprocinfo *p; for (p = cpinfo; p; p = p->next) { if (cardname && strcmp(cardname, p->name) != 0) continue; printf("%d %-10s %-8s %-16s %s\n", p->contr, p->driver, cardstate2str(p->state), p->name, p->driverinfo); } } /* ---------------- /proc/capi/driver -------------------------------- */ /* b1pci 0 1.20 b1pciv4 1 0.0 c4 4 1.4 */ static int driver_loaded(char *driver) { static char *fn = "/proc/capi/driver"; char buf[4096]; FILE *fp; if (strcmp(driver, "b1pciv4") == 0) driver = "b1pci"; if ((fp = fopen_with_errmsg(fn, "r")) == NULL) return 0; while (fgets(buf,sizeof(buf),fp)) { char *s = buf; while (*s && !isspace(*s)) s++; *s = 0; if (strcmp(buf, driver) == 0) { fclose(fp); return 1; } } fclose(fp); return 0; } static int load_driver(char *driver) { if (strcmp(driver, "b1pciv4") == 0) driver = "b1pci"; if (strcmp(driver, "c2") == 0) driver = "c4"; return load_module(driver, 0); } static int unload_driver(char *driver) { if (strcmp(driver, "b1pciv4") == 0) driver = "b1pci"; if (strcmp(driver, "c2") == 0) driver = "c4"; return unload_module(driver); } /* ---------------- /proc/filesystems -------------------------------- */ static int filesystem_available(char *fstype) { static char *fn = "/proc/filesystems"; char buf[4096]; FILE *fp; if ((fp = fopen_with_errmsg(fn, "r")) == NULL) return 0; while (fgets(buf,sizeof(buf),fp)) { char *t, *s; buf[strlen(buf)-1] = 0; t = skip_whitespace(buf); s = skip_nonwhitespace(t); if (*s) { t = skip_whitespace(s); s = skip_nonwhitespace(t); } if (strcmp(t, fstype) == 0) { fclose(fp); return 1; } } fclose(fp); return 0; } static int load_filesystem(char *fstype) { return load_module(fstype, 1); } static int unload_filesystem(char *fstype) { return unload_module(fstype); } /* ---------------- /proc/mounts ------------------------------------- */ /* /dev/root / ext2 rw 0 0 proc /proc proc rw 0 0 /dev/hda1 /boot ext2 rw 0 0 /dev/hda7 /src ext2 rw 0 0 devpts /dev/pts devpts rw 0 0 */ static char *mounted(char *fstype) { static char *fn = "/proc/mounts"; static char mpret[PATH_MAX]; char buf[4096]; FILE *fp; char *mp,*ftype; if ((fp = fopen_with_errmsg(fn, "r")) == NULL) return 0; while (fgets(buf,sizeof(buf),fp)) { char *t, *s; buf[strlen(buf)-1] = 0; s = skip_whitespace(buf); t = skip_nonwhitespace(s); mp = skip_whitespace(t); t = skip_nonwhitespace(mp); if (!*t) continue; *t++ = 0; strncpy(mpret, mp, sizeof(mpret)-1); mpret[sizeof(mpret)-1] = 0; ftype = skip_whitespace(t); t = skip_nonwhitespace(ftype); if (!*t) continue; *t++ = 0; if (strcmp(ftype, fstype) == 0) { fclose(fp); return mpret; } } fclose(fp); return 0; } /* ---------------- /etc/capi.conf ----------------------------------- */ /* # card file proto io irq mem cardnr options b1isa b1.t4 DSS1 0x150 7 - - P2P */ #define DP_ERROR -1 #define DP_NONE 0 #define DP_1TR6 0 #define DP_DSS1 0 #define DP_CT1 1 #define DP_VN3 2 #define DP_NI1 3 /* need SPID,SPID2,DN,DN2 */ #define DP_AUSTEL 4 #define DP_5ESS 5 /* need SPID,SPID2,DN,DN2 */ static struct pmap { char *name; int protocol; } pmap[] = { { "-", DP_NONE }, { "none", DP_NONE }, { "DSS1", DP_DSS1 }, { "1TR6", DP_1TR6 }, { "CT1", DP_CT1 }, { "VN3", DP_VN3 }, { "AUSTEL", DP_AUSTEL }, { "5ESS", DP_5ESS }, { "NI1", DP_NI1 }, { 0 }, }; static int dchan_protocol(char *pname) { struct pmap *p; for (p=pmap; p->name; p++) { if (strcasecmp(pname, p->name) == 0) return p->protocol; } return DP_ERROR; } struct patchinfo { int protocol; int p2p; char *dn1; char *spid1; char *dn2; char *spid2; }; struct capicard { struct capicard *next; int found; int line; char *driver; char *firmware; char *protoname; int proto; int ioaddr; int irq; unsigned long memaddr; int cardnr; char *optionstring; struct patchinfo patchinfo; }; static void free_config(struct capicard **pp) { struct capicard *p; while (*pp) { p = *pp; *pp = p->next; if (p->driver) free(p->driver); if (p->firmware) free(p->firmware); if (p->protoname) free(p->protoname); if (p->optionstring) free(p->optionstring); if (p->patchinfo.dn1) free(p->patchinfo.dn1); if (p->patchinfo.spid1) free(p->patchinfo.spid1); if (p->patchinfo.dn2) free(p->patchinfo.dn2); if (p->patchinfo.spid2) free(p->patchinfo.spid2); free(p); } } static int parse_cardoptions(char *opts, struct patchinfo *infop) { char buf[4096]; char *s, *option, *p; char save; strncpy(buf, opts, sizeof(buf)-1); buf[sizeof(buf)-1] = 0; s = buf; while (*s) { s = skip_whitespace(s); option = s; s = skip_nonwhitespace(option); save = *s; *s = 0; if (*option == 0 || *option == '#') break; if (strcasecmp(option, "p2p") == 0) { infop->p2p = 1; *s = save; if (*s) s++; continue; } if ((p = strchr(option, ':')) != 0) { /* DN:SPID */ char *dn, *spid; *p = 0; dn = strdup(option); spid = strdup(p+1); *p = ':'; if (infop->dn1 == 0) { infop->dn1 = dn; infop->spid1 = spid; } else { if (infop->dn2) free(infop->dn2); if (infop->spid2) free(infop->spid2); infop->dn2 = dn; infop->spid2 = spid; } *s = save; if (*s) s++; continue; } fprintf(stderr, "ERROR: cardoptions: unknown option \"%s\"\n", option); *s = save; return -1; } return 0; } struct capicard *load_config(char *fn) { struct capicard *list, *p, **pp; char buf[4096]; char *s, *t, *tmp; FILE *fp; int line = 0; list = 0; if ((fp = fopen_with_errmsg(fn, "r")) == NULL) return 0; while (fgets(buf,sizeof(buf),fp)) { line++; buf[strlen(buf)-1] = 0; if ((p = STRUCTALLOC(struct capicard)) == 0) { fprintf(stderr, "ERROR: %s:%d: malloc failed\n", fn, line); goto error; } memset(p, 0, sizeof(*p)); p->line = line; s = skip_whitespace(buf); if (*s == 0 || *s == '#') continue; /* driver */ t = s; s = skip_nonwhitespace(t); if (*s) *s++ = 0; p->driver = strdup(t); if (!p->driver) goto nomem; s = skip_whitespace(s); /* firmware */ t = s; s = skip_nonwhitespace(t); if (*s) *s++ = 0; p->firmware = strdup(t); if (!p->firmware) goto nomem; s = skip_whitespace(s); /* proto */ t = s; s = skip_nonwhitespace(t); if (*s) *s++ = 0; p->protoname = strdup(t); if (!p->protoname) goto nomem; p->proto = dchan_protocol(t); p->patchinfo.protocol = p->proto; s = skip_whitespace(s); /* ioaddr */ t = s; s = skip_nonwhitespace(t); if (*s) *s++ = 0; if (strcmp(t, "-") == 0 || strcmp(t, "none") == 0) { p->ioaddr = 0; } else { tmp = t; p->ioaddr = strtol(t, &tmp, 0); if (*tmp) { fprintf(stderr, "ERROR: %s:%d: illegal ioaddr \"%s\"\n", fn, line, t); goto error; } } s = skip_whitespace(s); /* irq */ t = s; s = skip_nonwhitespace(t); if (*s) *s++ = 0; if (strcmp(t, "-") == 0 || strcmp(t, "none") == 0) { p->irq = 0; } else { tmp = t; p->irq = strtol(t, &tmp, 0); if (*tmp) { fprintf(stderr, "ERROR: %s:%d: illegal irq \"%s\"\n", fn, line, t); goto error; } } s = skip_whitespace(s); /* memaddr */ t = s; s = skip_nonwhitespace(t); if (*s) *s++ = 0; if (strcmp(t, "-") == 0 || strcmp(t, "none") == 0) { p->memaddr = 0; } else { tmp = t; p->memaddr = strtoul(t, &tmp, 0); if (*tmp) { fprintf(stderr, "ERROR: %s:%d: illegal memaddr \"%s\"\n", fn, line, t); goto error; } } s = skip_whitespace(s); /* cardnr */ t = s; s = skip_nonwhitespace(t); if (*s) *s++ = 0; if (strcmp(t, "-") == 0 || strcmp(t, "none") == 0) { p->cardnr = 0; } else { tmp = t; p->cardnr = strtol(t, &tmp, 0); if (*tmp) { fprintf(stderr, "ERROR: %s:%d: illegal cardnr \"%s\"\n", fn, line, t); goto error; } } s = skip_whitespace(s); /* options */ p->optionstring = strdup(s); if (!p->optionstring) goto nomem; if (parse_cardoptions(p->optionstring, &p->patchinfo) < 0) { fprintf(stderr, "ERROR: %s:%d: illegal options \"%s\"\n", fn, line, p->optionstring); goto error; } /* append it to the list */ for (pp = &list; *pp; pp = &(*pp)->next) ; *pp = p; } fclose(fp); return list; nomem: fprintf(stderr, "ERROR: %s:%d: no memory\n", fn, line); error: fclose(fp); free_config(&list); return 0; } static void mark_unfound(struct capicard *cards) { struct capicard *card = cards; for (card = cards; card; card = card->next) card->found = 0; } static struct capicard *find_config(struct capicard *cards, char *driver) { struct capicard *card; for (card = cards; card; card = card->next) { if (card->found) continue; if (strcmp(card->driver,driver) == 0) break; } if (card) { card->found = 1; return card; } if (strcmp(driver, "b1pci") == 0) { for (card = cards; card; card = card->next) { if (card->found) continue; if (strcmp(card->driver, "b1pciv4") == 0) break; } } else if (strcmp(driver, "b1pciv4") == 0) { for (card = cards; card; card = card->next) { if (card->found) continue; if (strcmp(card->driver, "b1pci") == 0) break; } } else if (strcmp(driver, "c4") == 0) { for (card = cards; card; card = card->next) { if (card->found) continue; if (strcmp(card->driver, "c2") == 0) break; } } else if (strcmp(driver, "c2") == 0) { for (card = cards; card; card = card->next) { if (card->found) continue; if (strcmp(card->driver, "c4") == 0) break; } } if (card) card->found = 1; return card; } static void show_confighead(void) { printf("%s\t%-12s\t%s", "driver", "firmware", "proto"); printf("\tio"); printf("\tirq"); printf("\tmem"); printf("\tcardnr"); printf("\toptions"); printf("\n"); } static void show_configone(struct capicard *p) { printf("%s\t%-12s\t%s", p->driver, p->firmware, p->protoname); if (p->ioaddr) printf("\t0x%x", p->ioaddr); else printf("\t-"); if (p->irq) printf("\t%d", p->irq); else printf("\t-"); if (p->memaddr) printf("\t0x%lx", p->memaddr); else printf("\t-"); if (p->cardnr) printf("\t%d", p->cardnr); else printf("\t-"); printf("\t%s", p->optionstring); printf("\n"); } static void show_config(struct capicard *cards) { struct capicard *p; show_confighead(); for (p = cards; p; p = p->next) show_configone(p); } /* ---------------- add card ----------------------------------------- */ static int add_card(struct capicard *card) { capi_manufacturer_cmd ioctl_s; kcapi_carddef carddef; memset(&carddef, 0, sizeof(carddef)); strncpy(carddef.driver, card->driver, sizeof(carddef.driver)-1); carddef.port = card->ioaddr; carddef.irq = card->irq; carddef.irq = card->irq; carddef.membase = card->memaddr; carddef.cardnr = card->cardnr; ioctl_s.cmd = KCAPI_CMD_ADDCARD; ioctl_s.data = &carddef; if (ioctl(capifd, CAPI_MANUFACTURER_CMD, &ioctl_s) >= 0) return 0; fprintf(stderr, "ERROR: add_card(%s) failed - %s (%d)\n", card->driver, strerror(errno), errno); fprintf(stderr, "\n!! CHECK THE KERNEL MESSAGES BEFORE SENDING MAIL !!\n\n"); return -1; } /* ---------------- patchvalues for AVM active cards ----------------- */ static char patcharea[8192]; static int patchlen = 0; static char *getpatchdata(void) { return patcharea; } static int getpatchlen(void) { return patchlen; } static void clearpatcharea(void) { patchlen = 0; } static void addpatchvalue(char *name, char *value, int len) { int nlen = strlen(name); if (patchlen + nlen + len + 2 >= sizeof(patcharea)) { fprintf(stderr, "ERROR: addpatchvalue: patcharea overflow (%s)\n" , name); return; } patcharea[patchlen++] = ':'; memcpy(&patcharea[patchlen], name, nlen); patchlen += nlen; patcharea[patchlen++] = 0; memcpy(&patcharea[patchlen], value, len); patchlen += len; patcharea[patchlen++] = 0; patcharea[patchlen+1] = 0; } static void addpatchstring(char *name, char *value) { addpatchvalue(name, value, strlen(value)); } static void addpatchbyte(char *name, unsigned char value) { char buf[16]; sprintf(buf, "\\x%02x", value); addpatchvalue(name, buf, strlen(buf)); } static void addpatchvalues(struct patchinfo *p) { int p2p = p->p2p; addpatchstring("WATCHDOG", "1"); addpatchbyte("AutoFrame", 1); switch (p->protocol) { case DP_CT1: addpatchbyte("PROTOCOL", 1); break; case DP_VN3: addpatchbyte("PROTOCOL", 2); break; case DP_NI1: p2p = 0; addpatchbyte("PROTOCOL", 3); if (p->dn1 && p->spid1) { addpatchstring("DN", p->dn1); addpatchstring("SPID", p->spid1); } if (p->dn2 && p->spid2) { addpatchstring("DN2", p->dn2); addpatchstring("SPID2", p->spid2); } break; case DP_AUSTEL: addpatchbyte("PROTOCOL", 4); break; case DP_5ESS: p2p = 0; addpatchbyte("PROTOCOL", 5); if (p->dn1 && p->spid1) { addpatchstring("DN", p->dn1); addpatchstring("SPID", p->spid1); } if (p->dn2 && p->spid2) { addpatchstring("DN2", p->dn2); addpatchstring("SPID2", p->spid2); } break; } if (p2p) { addpatchbyte("P2P", 1); addpatchbyte("TEI", 0); } } static void savepatcharea(char *dir, int contr) { char fn[PATH_MAX]; int fd; snprintf(fn, sizeof(fn), "%s/capicontr%d.pvals", dir, contr); if (access(fn, 0)) unlink(fn); if ((fd = open(fn, O_WRONLY|O_CREAT, 0600)) < 0) { fprintf(stderr, "creation of %s failed - %s (%d)\n", fn, strerror(errno), errno); return; } if (write(fd, patcharea, patchlen) != patchlen) { fprintf(stderr, "write to %s failed - %s (%d)\n", fn, strerror(errno), errno); close(fd); return; } close(fd); printf("controller %d: patchvalues written to %s\n", contr, fn); } /* ---------------- firmware load ------------------------------------ */ static char *locate_firmware(struct capicard *card) { static char fn[PATH_MAX]; char **path; if (card->firmware[0] == '/') { snprintf(fn, sizeof(fn), "%s", card->firmware); return fn; } for (path = firmwarepath; *path; path++) { snprintf(fn, sizeof(fn), "%s/%s", path[0], card->firmware); if (access(fn, R_OK) == 0) return fn; } return 0; } static char signalinfo[PATH_MAX+64]; static void sigdummy(int sig) { fprintf(stderr, "ERROR: %s\n", signalinfo); } static struct capicard *load_firmware(int contr, struct capicard *card) { capi_manufacturer_cmd ioctl_s; avmb1_loadandconfigdef ldef; struct capicard *next = card->next; char *fn, *type; struct stat st; int codefd; clearpatcharea(); if (strcmp(card->driver, "c4") == 0) { struct capicard *cp; int i; for (i=0,cp=card; i < 4; i++) { addpatchbyte("CtlrNr", i); addpatchvalues(&cp->patchinfo); if (cp->next && strcmp(cp->next->driver, "c4") == 0) cp = cp->next; } next = cp->next; } else if (strcmp(card->driver, "c2") == 0) { struct capicard *cp; int i; for (i=0,cp=card; i < 2; i++) { addpatchbyte("CtlrNr", i); addpatchvalues(&cp->patchinfo); if (cp->next && strcmp(cp->next->driver, "c2") == 0) cp = cp->next; } next = cp->next; } else { addpatchvalues(&card->patchinfo); } if ((fn = locate_firmware(card)) == 0) { fprintf(stderr, "ERROR: controller %d: firmware file \"%s\" not found\n", contr, card->firmware); return next; } if (stat(fn, &st)) { fprintf(stderr, "ERROR: controller %d: stat failed for firmware file %s - %s (%d)\n", contr, fn, strerror(errno), errno); return next; } switch (st.st_mode & S_IFMT) { case S_IFREG: type = 0; break; case S_IFSOCK: type = "socket"; break; case S_IFLNK: type = "symbolic link"; break; case S_IFBLK: type = "block device"; break; case S_IFDIR: type = "directory"; break; case S_IFCHR: type = "character device"; break; case S_IFIFO: type = "named pipe"; break; default: type = "unknown file type"; break; } if (type != 0) { fprintf(stderr, "ERROR: controller %d: firmware file \"%s\" is a %s\n", contr, fn, type); return next; } if ((codefd = open(fn, O_RDONLY)) < 0) { fprintf(stderr, "ERROR: controller %d: failed to open firmware file \"%s\" - %s (%d)\n", contr, fn, strerror(errno), errno); return next; } ldef.contr = contr; ldef.t4file.len = st.st_size; ldef.t4file.data = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, codefd, 0); if (ldef.t4file.data == (unsigned char *) -1) { fprintf(stderr, "ERROR: controller %d: mmap of firmware failed - %s (%d)\n", contr, strerror(errno), errno); return next; } ldef.t4config.len = getpatchlen(); ldef.t4config.data = getpatchdata(); if (patchdebug) savepatcharea("/tmp", contr); ioctl_s.cmd = AVMB1_LOAD_AND_CONFIG; ioctl_s.data = &ldef; snprintf(signalinfo, sizeof(signalinfo), "controller %d: timeout while loading \"%s\"", contr, fn); signal(SIGALRM, sigdummy); alarm(10); if (ioctl(capifd, CAPI_MANUFACTURER_CMD, &ioctl_s) < 0) { if (errno != EINTR) { fprintf(stderr, "ERROR: controller %d: firmware load failed - %s (%d)\n", contr, strerror(errno), errno); fprintf(stderr, "\n!! CHECK THE KERNEL MESSAGES BEFORE SENDING MAIL !!\n\n"); } alarm(0); signal(SIGALRM, SIG_DFL); return next; } alarm(0); signal(SIGALRM, SIG_DFL); munmap(ldef.t4file.data, ldef.t4file.len); close(codefd); return next; } int reset_controller(int contr) { capi_manufacturer_cmd ioctl_s; avmb1_resetdef rdef; rdef.contr = contr; ioctl_s.cmd = AVMB1_RESETCARD; ioctl_s.data = &rdef; if (ioctl(capifd, CAPI_MANUFACTURER_CMD, &ioctl_s) < 0) return -1; return 0; } int remove_controller(int contr) { capi_manufacturer_cmd ioctl_s; avmb1_resetdef rdef; rdef.contr = contr; ioctl_s.cmd = AVMB1_REMOVECARD; ioctl_s.data = &rdef; if (ioctl(capifd, CAPI_MANUFACTURER_CMD, &ioctl_s) < 0) return -1; return 0; } /* ---------------- prechecks ---------------------------------------- */ static int check_superuser(void) { if (getuid() != 0) { fprintf(stderr, "ERROR: you must be super user\n"); return -1; } return 0; } static int check_procfs(void) { if (access("/proc/self", 0) < 0) { fprintf(stderr, "ERROR: proc filesystem not mounted\n"); return -1; } return 0; } static int check_for_kernelcapi(void) { if (access("/proc/capi/applications", 0) == 0) return 0; load_module("kernelcapi", 0); if (access("/proc/capi/applications", 0) == 0) return 0; fprintf(stderr, "ERROR: cannot load module kernelcapi\n"); return -1; } static int check_for_capi(void) { if (access("/proc/capi/capi20", 0) == 0) return 0; load_module("capi", 0); if (access("/proc/capi/capi20", 0) == 0) return 0; fprintf(stderr, "ERROR: cannot load module capi20\n"); return -1; } static int check_for_devcapi(void) { int fd; capidevname = capidevnameold; if ((fd = open(capidevname, O_RDWR)) < 0 && errno == ENOENT) { capidevname = capidevnamenew; fd = open(capidevname, O_RDWR); } if (fd < 0) { fprintf(stderr, "ERROR: cannot open %s nor %s - %s (%d)\n", capidevnameold, capidevnamenew, strerror(errno), errno); return -1; } close(fd); return 0; } static int check_for_capifs(void) { if (filesystem_available("capifs")) return 0; load_filesystem("capifs"); if (filesystem_available("capifs")) return 0; #ifdef WITH_DEVFS if (filesystem_available("devfs")) return 0; #endif return -1; } static int checkdir(char *dir) { struct stat st; if (stat(dir, &st) < 0) return -1; if (S_ISDIR(st.st_mode)) return 0; return -1; } static int check_for_capifs_mounted(void) { char *mp; #ifdef WITH_DEVFS if (filesystem_available("devfs")) { if ((mp = mounted("devfs")) != 0 && strcmp(mp, "/dev") == 0) return 0; } #endif if (filesystem_available("capifs")) { if ((mp = mounted("capifs")) != 0 && strcmp(mp, "/dev/capi") == 0) return 0; if (checkdir("/dev/capi") < 0) { unlink("/dev/capi"); if (mkdir("/dev/capi", 0755) < 0) { fprintf(stderr, "ERROR: mkdir(/dev/capi) failed - %s (%d)\n", strerror(errno), errno); return -1; } } system("mount -t capifs -omode=0666 capifs /dev/capi"); if ((mp = mounted("capifs")) != 0 && strcmp(mp, "/dev/capi") == 0) return 0; fprintf(stderr, "ERROR: cound't mount capifs on /dev/capi\n"); return -1; } return -1; } static int prestartcheck(void) { if (check_superuser() < 0) return -1; if (check_procfs() < 0) return -1; if (check_for_kernelcapi() < 0) return -1; if (check_for_capi() < 0) return -1; if (check_for_devcapi() < 0) return -1; if (check_for_capifs() < 0) return 0; /* only warning */ if (check_for_capifs_mounted() < 0) return -1; return 0; } static int prestopcheck(void) { if (check_superuser() < 0) return -1; if (check_procfs() < 0) return -1; if (check_for_kernelcapi() < 0) return -1; if (check_for_capi() < 0) return -1; if (check_for_devcapi() < 0) return -1; return 0; } /* ------------------------------------------------------------------- */ static int is_card_of_driver(char *cardname, struct contrprocinfo *p) { if (strcmp(cardname, p->driver) == 0) return 1; if ( strcmp(cardname, "b1pci") == 0 && strcmp(p->driver, "b1pciv4") == 0) return 1; if (strcmp(cardname, p->name) == 0) return 1; return 0; } static int card_exists(const char * driver, int ioaddr) { static char buf[64]; struct contrprocinfo *cp, *cpinfo; snprintf (buf, sizeof (buf), "%s-%x", driver, ioaddr); buf[sizeof (buf) - 1] = (char) 0; for (cp = cpinfo = load_contrprocinfo(0); cp; cp = cp->next) { if (strcmp (cp->name, buf) == 0) break; } free_contrprocinfo (&cpinfo); return cp != 0; } int main_start(int activate, char *cardname, int number) { struct capicard *cards, *card; struct contrprocinfo *cpinfo, *p; int contr, lastcontr; int ret = 0; char cname[32]; if (prestartcheck() < 0) return -1; cname[0] = 0; /* could not fail, tested by check_for_capi() */ capifd = open(capidevname, O_RDWR); cards = load_config(configfilename); for (card = cards; card; card = card->next) { if (!driver_loaded(card->driver)) load_driver(card->driver); if (!driver_loaded(card->driver)) { fprintf(stderr,"ERROR: failed to load driver %s\n", card->driver); continue; } if (card->ioaddr && !card_exists(card->driver, card->ioaddr)) add_card(card); } mark_unfound(cards); if (activate) { int act; act = 0; cpinfo = load_contrprocinfo(&lastcontr); for (contr = 1; contr <= lastcontr; contr++) { struct capicard *thiscard; cpinfo = load_contrprocinfo(0); p = find_contrprocinfo(cpinfo, contr); thiscard = find_config(cards, p->driver); if (cardname) { if (number == 0) { if (strcmp(cardname, p->name) != 0) { free_contrprocinfo(&cpinfo); continue; } } else if (is_card_of_driver(cardname, p)) { if (++act != number) { free_contrprocinfo(&cpinfo); continue; } } else { free_contrprocinfo(&cpinfo); continue; } strncpy(cname, p->name, sizeof(cname)); } if (p->state == CARD_LOADING) reset_controller(contr); if (p->state == CARD_DETECTED) { if (thiscard) { card = load_firmware(contr, thiscard); } else { fprintf(stderr,"ERROR: missing config entry for controller %d driver %s name %s\n", p->contr, p->driver, p->name); } } free_contrprocinfo(&cpinfo); } mark_unfound(cards); act = 0; cpinfo = load_contrprocinfo(&lastcontr); for (contr = 1; contr <= lastcontr; contr++) { struct capicard *thiscard; cpinfo = load_contrprocinfo(0); p = find_contrprocinfo(cpinfo, contr); thiscard = find_config(cards, p->driver); if (cardname && cname[0]) { if (strcmp(cname, p->name) != 0) { free_contrprocinfo(&cpinfo); continue; } } if (p->state == CARD_DETECTED && thiscard) { fprintf(stderr,"ERROR: failed to load firmware for controller %d driver %s name %s\n", p->contr, p->driver, p->name); ret = 3; } free_contrprocinfo(&cpinfo); } } if (cardname && cname[0] == 0) { fprintf(stderr,"ERROR: card \"%s\" not found\n", cardname); ret = 4; } if (!silent) { cpinfo = load_contrprocinfo(0); show_contrprocinfo(cpinfo, cardname ? cname: ""); free_contrprocinfo(&cpinfo); } free_config(&cards); close(capifd); return ret; } /* ------------------------------------------------------------------- */ int main_stop(int unload, char *cardname, int number) { struct capicard *cards, *card; struct contrprocinfo *cpinfo, *p; int contr, lastcontr; char *mp; int act; char cname[32]; if (prestopcheck() < 0) return -1; cname[0] = 0; /* could not fail, tested by check_for_capi() */ capifd = open(capidevname, O_RDWR); act = 0; cpinfo = load_contrprocinfo(&lastcontr); if (cardname) { for (contr = 1; contr <= lastcontr; contr++) { cpinfo = load_contrprocinfo(0); p = find_contrprocinfo(cpinfo, contr); if (number == 0) { if (strcmp(cardname, p->name) != 0) { free_contrprocinfo(&cpinfo); continue; } } else if (is_card_of_driver(cardname, p)) { if (++act != number) { free_contrprocinfo(&cpinfo); continue; } } else { free_contrprocinfo(&cpinfo); continue; } strncpy(cname, p->name, sizeof(cname)); if (p && p->state != CARD_DETECTED) reset_controller(contr); free_contrprocinfo(&cpinfo); } } else { for (contr = lastcontr; contr > 0; contr--) { cpinfo = load_contrprocinfo(0); p = find_contrprocinfo(cpinfo, contr); if (p && p->state != CARD_DETECTED) reset_controller(contr); free_contrprocinfo(&cpinfo); } } if (unload) { cpinfo = load_contrprocinfo(&lastcontr); for (contr = lastcontr; contr > 0; contr--) { cpinfo = load_contrprocinfo(0); p = find_contrprocinfo(cpinfo, contr); if (p) remove_controller(contr); free_contrprocinfo(&cpinfo); } } if (unload && !cardname) { cards = load_config(configfilename); for (card = cards; card; card = card->next) { if (driver_loaded(card->driver)) unload_driver(card->driver); } for (card = cards; card; card = card->next) { if (driver_loaded(card->driver)) unload_driver(card->driver); } } if (!silent) { cpinfo = load_contrprocinfo(0); show_contrprocinfo(cpinfo, cardname ? cname: 0); free_contrprocinfo(&cpinfo); } close(capifd); if (unload && !cardname) { unload_module("capi"); unload_module("capidrv"); unload_module("kernelcapi"); unload_module("capiutil"); if ((mp = mounted("capifs")) != 0 && strcmp(mp, "/dev/capi") == 0) system("umount /dev/capi"); if (filesystem_available("capifs")) unload_filesystem("capifs"); } if (cardname && cname[0] == 0) { fprintf(stderr,"ERROR: card \"%s\" not found\n", cardname); return 4; } return 0; } int main_show(void) { struct capicard *cards; cards = load_config(configfilename); if (cards == 0) { fprintf(stderr,"ERROR: no cards configured in %s\n", configfilename); return -1; } show_config(cards); return 0; } /* ------------------------------------------------------------------- */ int main_status(void) { struct contrprocinfo *cpinfo; cpinfo = load_contrprocinfo(0); show_contrprocinfo(cpinfo, 0); free_contrprocinfo(&cpinfo); return 0; } /* ------------------------------------------------------------------- */ static void usage(void) { fprintf(stderr, "Usage: capiinit [OPTION]\n"); fprintf(stderr, " or: capiinit [OPTION] start\n"); fprintf(stderr, " - load all modules and inititialize all cards\n"); fprintf(stderr, " or: capiinit [OPTION] stop\n"); fprintf(stderr, " - reset all cards and unload modules\n"); fprintf(stderr, " or: capiinit [OPTION] show\n"); fprintf(stderr, " - show current config\n"); fprintf(stderr, " or: capiinit [OPTION] status\n"); fprintf(stderr, " - show current status\n"); fprintf(stderr, " or: capiinit [OPTION] prepare\n"); fprintf(stderr, " - load all modules\n"); fprintf(stderr, " or: capiinit [OPTION] activate\n"); fprintf(stderr, " - inititialize all cards \n"); fprintf(stderr, " or: capiinit [OPTION] activate cardname\n"); fprintf(stderr, " - inititialize one cards (i.e.: c4-ec00) \n"); fprintf(stderr, " or: capiinit [OPTION] activate driver [cardnumber]\n"); fprintf(stderr, " - inititialize one card \n"); fprintf(stderr, " or: capiinit [OPTION] deactivate\n"); fprintf(stderr, " - reset all cards \n"); fprintf(stderr, " or: capiinit [OPTION] deactivate cardname\n"); fprintf(stderr, " - reset one card (i.e.: c4-ec00) \n"); fprintf(stderr, " or: capiinit [OPTION] deactivate driver [cardnumber]\n"); fprintf(stderr, " - reset one cards \n"); fprintf(stderr, " or: capiinit [OPTION] reload\n"); fprintf(stderr, " - reset all cards and initialize them again\n"); fprintf(stderr, "Setup or unsetup CAPI2.0 Controllers\n"); fprintf(stderr, " -c, --config filename (default %s)\n", configfilename); fprintf(stderr, " -d, --debug save patchvalues for debugging\n"); fprintf(stderr, " -s, --silent don't show status\n"); } int main(int ac, char *av[]) { int c; for (;;) { int option_index = 0; static struct option long_options[] = { {"config", 1, 0, 'c'}, {"debug", 1, 0, 'd'}, {"silent", 1, 0, 's'}, {0, 0, 0, 0} }; c = getopt_long (ac, av, "c:ds", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case 'c': configfilename = optarg; break; case 'd': patchdebug = 1; break; case 's': silent = 1; break; case '?': usage(); return 1; } } if (optind == ac) { return main_start(1, 0, 0); } else if (optind+1 == ac) { if (strcmp(av[optind], "start") == 0) { return main_start(1, 0, 0); } else if (strcmp(av[optind], "activate") == 0) { return main_start(1, 0, 0); } else if (strcmp(av[optind], "prepare") == 0) { return main_start(0, 0, 0); } else if (strcmp(av[optind], "stop") == 0) { return main_stop(1, 0, 0); } else if (strcmp(av[optind], "deactivate") == 0) { return main_stop(0, 0, 0); } else if (strcmp(av[optind], "show") == 0) { return main_show(); } else if (strcmp(av[optind], "status") == 0) { return main_status(); } else if (strcmp(av[optind], "reload") == 0) { if (main_stop(0, 0, 0) == 0) return main_start(1, 0, 0); } } else if (optind+2 == ac) { int number = strchr(av[optind+1], '-') == 0 ? 1 : 0; if (strcmp(av[optind], "activate") == 0) return main_start(1, av[optind+1], number); else if (strcmp(av[optind], "deactivate") == 0) return main_stop(0, av[optind+1], number); } else if (optind+3 == ac) { if (strcmp(av[optind], "activate") == 0) return main_start(1, av[optind+1], atoi(av[optind+2])); else if (strcmp(av[optind], "deactivate") == 0) return main_stop(0, av[optind+1], atoi(av[optind+2])); } usage(); return 1; }