isdn4k-utils/pcbit/pcbitctl.c

606 lines
10 KiB
C

/*
* Copyright (C) 1996 Universidade de Lisboa
*
* Writen by Pedro Roque Marques (roque@di.fc.ul.pt)
*
* This software may be used and distributed according to the terms of
* the GNU Public License, incorporated herein by reference.
*/
/*
* PCBIT-D firmware loader
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <getopt.h>
#include <linux/isdn.h>
#include <pcbit.h>
#define MAXLINEHEX 80
#define NUM_LIN 32
#define MAXSUPERLINE 3000
static void usage(char *);
static int loadfw(int, char *, int);
static int writefw(int, char*);
static int bitd_read(unsigned char* buf, int *len, int nlines, FILE* fp);
static int issue_ioctl(int board, int cmd);
extern int convhexbin (char *filename, unsigned char *buf, int size);
int main(int argc, char *argv[])
{
int option_index = 0;
char fwfile[FILENAME_MAX];
int force = 0;
int board = 0;
char c, choice = 0; /* {ping,stop,load} */
static struct option long_options[] =
{
{"ping", 0, 0, 'p'},
{"stop", 0, 0, 's'},
{"force", 0, 0, 'f'},
{"load", 1, 0, 'l'},
{"board", 1, 0, 'b'},
{0, 0, 0, 0}
};
while (1) {
c = getopt_long(argc, argv, "psfl:b:", long_options,
&option_index);
if ( c == -1 )
break;
switch(c) {
case 'p':
case 's':
choice = c;
break;
case 'l':
choice = c;
strcpy(fwfile, optarg);
break;
case 'b':
board = atoi(optarg);
break;
case 'f':
force = 1;
break;
default:
fprintf(stderr, "unkown option %c\n", c);
break;
}
if (choice)
break;
}
switch (choice) {
case 's':
issue_ioctl(board, PCBIT_STOP);
break;
case 'p':
issue_ioctl(board, PCBIT_PING188);
break;
case 'l':
return loadfw(board, fwfile, force);
break;
default:
usage(argv[0]);
return 1;
}
return 0;
}
static void usage(char *name){
fprintf(stderr, "usage:"
"\t%s ping\n"
"\t%s stop\n"
"\t%s load [-f] <firmware>\n",
name, name, name);
}
static int getrdp_byte(int fd, int board, ushort addr, unsigned short * value)
{
isdn_ioctl_struct io_cmd;
struct pcbit_ioctl * pcbit_cmd;
strcpy(io_cmd.drvid, "pcbitX");
io_cmd.drvid[5] = '0' + board;
pcbit_cmd = (struct pcbit_ioctl *) &io_cmd.arg;
pcbit_cmd->info.rdp_byte.addr = addr;
pcbit_cmd->info.rdp_byte.value = 0x0000;
if (ioctl(fd, PCBIT_GETBYTE, &io_cmd) == -1)
{
fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
return errno;
}
*value = pcbit_cmd->info.rdp_byte.value;
return 0;
}
static int setrdp_byte(int fd, int board, ushort addr, unsigned char value)
{
isdn_ioctl_struct io_cmd;
struct pcbit_ioctl * pcbit_cmd;
strcpy(io_cmd.drvid, "pcbitX");
io_cmd.drvid[5] = '0' + board;
pcbit_cmd = (struct pcbit_ioctl *) &io_cmd.arg;
pcbit_cmd->info.rdp_byte.addr = addr;
pcbit_cmd->info.rdp_byte.value = value;
if (ioctl(fd, PCBIT_SETBYTE, &io_cmd) == -1)
{
fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
return errno;
}
return 0;
}
static int testrdp(int fd, int board)
{
int retv;
unsigned short value;
retv = setrdp_byte(fd, board, 0x0000, 0x55);
if (!retv)
return retv;
value = 0x00;
retv = getrdp_byte(fd, board, 0x0000, &value);
if (!retv)
return retv;
if (value != 0x55)
{
fprintf(stderr, "test_board: values don't match\n");
return -1;
}
retv = setrdp_byte(fd, board, 0x0000, 0xaa);
if (!retv)
return retv;
value = 0x00;
retv = getrdp_byte(fd, board, 0x0000, &value);
if (!retv)
return retv;
if (value != 0xaa)
{
fprintf(stderr, "test_board: values don't match\n");
return -1;
}
return 0;
}
int issue_ioctl(int board, int cmd)
{
int fd;
isdn_ioctl_struct io_cmd;
struct pcbit_ioctl * pcbit_cmd;
if ( (fd = open("/dev/isdnctrl", O_RDWR)) == -1) {
fprintf(stderr, "error opening /dev/isdnctl: %s\n",
strerror(errno));
return errno;
}
strcpy(io_cmd.drvid, "pcbitX");
io_cmd.drvid[5] = '0' + board;
pcbit_cmd = (struct pcbit_ioctl *) &io_cmd.arg;
if (ioctl(fd, cmd, &io_cmd) < 0) {
fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
return errno;
}
return 0;
}
static int loadfw(int board, char *fname, int force)
{
int fd;
int attempt, retv, i, j;
unsigned short value;
isdn_ioctl_struct io_cmd;
struct pcbit_ioctl * pcbit_cmd;
unsigned char stpd1[1024], stpd2[1024], zerobuf[1024];
unsigned char execstr[7] = {
0x01,
0x04,
0x00,
0x00,
0x00,
0x00,
0x12
};
/*
* 1. get_status
* 2. load stpd.1
* 3. load stpd.2
* 4. test
* 5. firmware load
* 6. execute
* 7. set_protocol_running
*/
strcpy(io_cmd.drvid, "pcbitX");
io_cmd.drvid[5] = '0' + board;
pcbit_cmd = (struct pcbit_ioctl *) &io_cmd.arg;
if ( (fd = open("/dev/isdnctrl", O_RDWR)) == -1) {
fprintf(stderr, "error opening /dev/isdnctl: %s\n",
strerror(errno));
return errno;
}
if (ioctl(fd, PCBIT_GETSTAT, &io_cmd) < 0) {
fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
return errno;
}
if (pcbit_cmd->info.l2_status == L2_RUNNING) {
if (force) {
if (ioctl(fd, PCBIT_STOP, &io_cmd) < 0) {
fprintf(stderr, "ioctl failed: %s\n",
strerror(errno));
return errno;
}
}
else {
fprintf(stderr, "PCBIT-D driver is up and running. no action nedded\n");
return 0;
}
}
#ifdef DEBUG
fprintf(stderr, "1. Status check OK\n");
#endif
/*
* load stpd.{1,2}
*/
memset(stpd1, 0, 1024);
memset(stpd2, 0, 1024);
if ( convhexbin("stpd.1", stpd1, 1024) < 0 )
{
fprintf(stderr, "error reading stpd.1\n");
return -1;
}
if ( convhexbin("stpd.2", stpd2, 1024) < 0 )
{
fprintf(stderr, "error reading stpd.2\n");
return -1;
}
#ifdef DEBUG
fprintf(stderr, "2. stpd.{1,2} loaded \n");
#endif
if (ioctl(fd, PCBIT_STRLOAD, &io_cmd) < 0)
{
fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
return errno;
}
if (ioctl(fd, PCBIT_WATCH188, &io_cmd) < 0) {
fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
return errno;
}
if (ioctl(fd, PCBIT_LWMODE, &io_cmd) < 0)
{
fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
return errno;
}
memset(zerobuf, 0, 1024);
testrdp(fd, board);
#ifdef DEBUG
fprintf(stderr, "3.a linear write mode\n");
#endif
write(fd, zerobuf, 1024);
sleep(1);
if (testrdp(fd, board))
{
fprintf(stderr, "error: testrdp\n");
return -1;
}
write(fd, stpd1, 1024);
sleep(1);
for (j=0; j<2; j++) {
for (i=0; i<60; i++)
{
getrdp_byte(fd, board, 0x03fd, &value);
if (value == 0x55)
break;
if (write(fd, stpd1, 1021) < 0)
{
printf("error in write\n");
return -1;
}
usleep(200000);
/*
setrdp_byte(fd, board, 0x03fd, 0x00);
setrdp_byte(fd, board, 0x03ff, 0x00);
*/
}
if (i == 60)
{
printf("error in stpd.1 load\n");
return -1;
}
for (i=0; i<180; i++)
{
getrdp_byte(fd, board, 0x03ff, &value);
if (value == 0x55)
break;
usleep(20000);
}
if (i == 180)
{
printf("error in stpd.1 load - 2 val \n");
return -1;
}
getrdp_byte(fd, board, 0x03fe, &value);
if (value == 0x1f)
{
printf("1f\n");
break;
}
setrdp_byte(fd, board, 0x03fe, 0x00);
setrdp_byte(fd, board, 0x03ff, 0x00);
}
#ifdef DEBUG
fprintf(stderr, "3.c stpd.1 writen\n");
#endif
memcpy(stpd2 + 0x3e0, stpd1 + 0x3e0, 0x10);
if (write(fd, stpd2, 1023) < 0)
{
fprintf(stderr, "write failed: %s\n", strerror(errno));
return errno;
}
value = 0x00;
attempt = 0;
while(1)
{
if ((retv = getrdp_byte(fd, board, 0x03ff, &value)))
{
fprintf(stderr, "read_byte: error\n");
return retv;
}
if (value == 0x55)
break;
setrdp_byte(fd, board, 0x03ff, 0x00);
if (attempt==120)
{
fprintf(stderr, "Communication error\n");
return -1;
}
else
attempt++;
usleep(50);
}
#ifdef DEBUG
fprintf(stderr, "3.d stpd.2 writen\n");
#endif
if (ioctl(fd, PCBIT_FWMODE, &io_cmd) == -1)
{
fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
return errno;
}
#ifdef DEBUG
fprintf(stderr, "4.a load mode\n");
#endif
if (writefw(fd, fname))
return -1;
/* execute */
if (write(fd, execstr, 7) < 0)
{
fprintf(stderr, "write failed: %s\n", strerror(errno));
return errno;
}
#ifdef DEBUG
fprintf(stderr, "4.b execute\n");
#endif
/*
sleep(10);
if (ioctl(fd, PCBIT_STRLOAD, &io_cmd) == -1)
{
fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
return errno;
}
if (ioctl(fd, PCBIT_APION, &io_cmd) == -1)
{
fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
return errno;
}
if (ioctl(fd, PCBIT_PING188, &io_cmd) == -1)
{
fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
return errno;
}
sleep(5);
*/
if (ioctl(fd, PCBIT_ENDLOAD, &io_cmd) == -1)
{
fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
return errno;
}
#ifdef DEBUG
fprintf(stderr, "4.c load ok\n");
#endif
sleep(2);
if (ioctl(fd, PCBIT_RUNNING, &io_cmd) == -1)
{
fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
return errno;
}
#ifdef DEBUG
fprintf(stderr, "5. running\n");
#endif
return 0;
}
static int writefw(int fd, char* fname)
{
FILE *fp;
char shdr[80];
char buf[MAXSUPERLINE];
int i, len;
if ((fp=fopen(fname, "rb")) == NULL)
{
fprintf(stderr, "error in fopen %s:%s\n", fname, strerror(errno));
return -1;
}
fgets (shdr, 80, fp);
fprintf(stderr, "Loading %s \n", shdr);
len = MAXSUPERLINE;
while((i=bitd_read (buf + 3, &len, 80, fp))) {
buf[0]=0;
*((short *)&buf[1])=(short)(len);
if (write(fd, buf, len + 3) < 0)
{
fprintf(stderr, "load firmware - error in write:%s\n",strerror(errno));
return errno;
}
fprintf(stderr, ".");
fflush(stderr);
}
fprintf(stderr, "\n load complete\n");
fclose(fp);
fprintf(stderr, "Firmware loaded\n");
return 0;
}
/*
* Discard 1st char (':') and convert the rest to bin
*/
static int bitd_read(unsigned char* buf, int *len, int nlines, FILE* fp)
{
char line[80];
int i, j;
unsigned int val;
int aux = 0;
*len = 1;
for (i = 0; i < nlines; i++) {
if (fgets(line, 80, fp) == NULL)
break;
aux += strlen(line) - 1;
line[strlen(line) - 1] = 0;
for (j=1; line[j]; j+=2) {
sscanf(line + j, "%02x", &val);
buf[(*len)++] = val;
}
}
buf[0] = i;
return aux;
}