bbcrdrif.c 5.56 KB
#include "bbclocal.h"
#include "bbcr.h"

static void
__bbc_reader_close(void *f)
{
    bbcr_t *crp = (bbcr_t *)f;
    BBC_LOG(MSG_DEBUG, "__bbc_reader_close\n");
    bbcr_close(crp);
    free(crp);
}


/* Map the LED selectors to BBCR commands */
int ledval[] = {
    BBCR_CLR_GRN|BBCR_CLR_RED,	/* BBC_LED_OFF */
    BBCR_SET_GRN|BBCR_CLR_RED,	/* BBC_LED_GREEN */
    BBCR_CLR_GRN|BBCR_SET_RED,	/* BBC_LED_RED */
    BBCR_SET_GRN|BBCR_SET_RED,	/* BBC_LED_ORANGE */
};

static int
__bbc_reader_setled(void *f, int ledmask)
{
    int rv;
    rv = bbcr_ctrl((bbcr_t *)f, ledval[ledmask]);
    return (rv == 0 ? BBC_OK : BBC_ERROR);
}

static int
__bbc_reader_settime(void *f, time_t curtime)
{
    return BBC_NODEV;
}

#undef BBCR_DEBUG
#ifdef BBCR_DEBUG
static void
__save_debug_data(u32 blk, char *data, char *spare, int rv)
{
	static int errcount = 0;
	char fname[256];
	int pid = getpid();
	FILE *outfile;
	unsigned int *ip;
	unsigned char *cp;
	int i, j;

	sprintf(fname, "readblk.%d.%d", pid, errcount);
	if ((outfile = fopen(fname, "w")) == NULL) {
		BBC_LOG_SYSERROR("__save_debug_data: fopen failed ");
		exit(1);
	}
	fprintf(outfile, "read block %ld returns %d\n", blk, rv);
	fprintf(outfile, "spare address 0x%p, contents:\n", spare);
	for (i = 0, cp = spare; i < 16; i++, cp++)
		fprintf(outfile, "%02x ", *cp);
	fprintf(outfile, "\n");
	fprintf(outfile, "buffer address 0x%p, contents:\n", data);
	for (i = 0, ip = (int *)data; i < 512; i++) {
		fprintf(outfile, "%08x -> ", (int)ip - (int)data);
		for (j = 0; j < 8; j++) 
			fprintf(outfile, "%08x ", *ip++);
		fprintf(outfile, "\n");
	}
	fclose(outfile);
	errcount++;
}
#endif /* BBCR_DEBUG */

static int
__bbc_reader_read_blocks(void* f, u32 blk, int nblks, void* data, void* spare)
{
    unsigned char *sparep = (unsigned char *)spare;
    int rv, i;

    BBC_LOG(MSG_DEBUG, "rdr_read_blks %ld, ct %d\n", blk, nblks);
    memset(spare, 0xff, nblks * BB_FL_SPARE_SIZE);
    if ((rv = bbcr_read(f, blk, nblks, data, spare)) != 0) {
        BBC_LOG(MSG_ERR, "\nbbcr_read blk %ld nblks %d ret %d\n", blk, nblks, rv);
#ifdef BBCR_DEBUG
	__save_debug_data(blk, data, spare, rv);
#endif
    }
    for (i = 0; i < nblks; i++) {
	if (__bbc_zerobits(sparep[BB_FL_SPARE_SIZE*i + BB_FL_BLOCK_STATUS_OFF]) > 1) {
	    BBC_LOG(MSG_WARNING, "Blk %ld marked bad by MFG (status %d)\n", blk+i,
	        sparep[BB_FL_SPARE_SIZE*i + BB_FL_BLOCK_STATUS_OFF]);
	    return BBC_BADBLK;
	}
    }
    if (rv)
	return (rv == ENXIO) ? BBC_DATAERR : BBC_NOCARD;
    return BBC_OK;
}

/*
 * write blocks to the flash device.  if spare is non-zero, use it
 * as the spare area data for all pages in the block.
 */
static int
__bbc_reader_write_blocks(void* f, u32 blk, int nblks, const void* data, void* spare)
{
    char locspare[BB_FL_SPARE_SIZE*4];
    int rv;

    BBC_LOG(MSG_DEBUG, "rdr_write_blks %ld, ct %d\n", blk, nblks);
    if (spare == NULL) {
	memset(locspare, 0xff, sizeof(locspare));
	spare = locspare;
    }
    if (nblks > 4)
	nblks = 4;
    if ((rv = bbcr_write(f, blk, nblks, data, spare)) != 0) {
        BBC_LOG_BBCERROR("__bbc_reader_write_blocks: bbcr_write failed", rv);
	return BBC_DATAERR;
    }
    return BBC_OK;
}

extern int bbcr_card_init(bbcr_t *crp);
extern int bbcr_read_mfg(bbcr_t *crp);

int
__bbc_reader_card_status(bbc_hand *hp)
{
    flashif_t* f = hp->bh_flashif;
    bbcr_t *crp = f->f;
    int rv;

    BBC_LOG(MSG_DEBUG, "card_status: cp %d, cc %d, fv %d\n",
            hp->bh_card_present, hp->bh_card_change, hp->bh_fat_valid);
    if (hp->bh_card_present) {
	if (!bbcr_read_mfg(crp)) {
	    if (hp->bh_card_change) {
	        BBC_LOG(MSG_INFO, "card_status: new card there\n");
	        return BBC_CARDCHANGE;
	    }
	    BBC_LOG(MSG_DEBUG, "card_status: still there\n");
	    return BBC_OK;
	}
	BBC_LOG(MSG_INFO, "card_status: went away\n");
	hp->bh_card_change = 1;
        hp->bh_card_present = 0;
        hp->bh_fat_valid = 0;
        hp->bh_cardsize = 0;
	return BBC_NOCARD;
    }

    rv = bbcr_card_init(crp);
    BBC_LOG(MSG_DEBUG, "card_init ret %d\n", rv);
    if (rv == 0) {
        hp->bh_card_present = 1;
        hp->bh_cardsize = crp->dev->nblocks;
	if (!hp->bh_card_change) {
	    rv = __bbc_read_fat(hp);
	    BBC_LOG(MSG_ERR, "read_fat ret %d, fat valid %d\n", rv, hp->bh_fat_valid);
	    return rv;
	}
	return BBC_CARDCHANGE;
    }

    rv = (rv == EIO) ? BBC_NOCARD : BBC_NODEV;
    BBC_LOG((rv == BBC_NOCARD)? MSG_DEBUG: MSG_ERR, "card_status ret %d\n", rv);
    return rv;
}

int
__bbc_new_reader(bbc_hand *hp, const char *device)
{
    flashif_t* f;
    bbcr_t *crp;
    int rv;

    BBC_LOG(MSG_DEBUG, "new_reader %s\n", device);

    if ((crp = malloc(sizeof(bbcr_t))) == NULL) {
	BBC_LOG_SYSERROR("__bbc_new_reader: malloc failed");
	return BBC_NOMEM;
    }

    if ((rv = bbcr_open(crp, device)) != 0) {
        BBC_LOG(MSG_DEBUG, "__bbc_new_reader: bbcr_open %s fails (err %d)\n", device, rv);
	if (rv == ENODEV) {
	    free(crp);
	    return BBC_NODEV;
	}
    }

    if (crp->dev) {
        hp->bh_card_present = 1;
        hp->bh_cardsize = crp->dev->nblocks;
    } else {
        hp->bh_card_present = 0;
	hp->bh_cardsize = 0;
    }
    BBC_LOG(MSG_DEBUG, "%s: nblks %d\n", device, hp->bh_cardsize);

    if ((f = malloc(sizeof(flashif_t))) == NULL) {
	BBC_LOG_SYSERROR("__bbc_new_reader: malloc failed");
	bbcr_close(crp);
	free(crp);
	return BBC_NOMEM;
    }
    hp->bh_flashif = f;
    memset(f, 0, sizeof(flashif_t));
    f->f = (void *)crp;
    f->close = __bbc_reader_close;
    f->setled = __bbc_reader_setled;
    f->settime = __bbc_reader_settime;
    f->read_blocks = __bbc_reader_read_blocks;
    f->write_blocks = __bbc_reader_write_blocks;
    return BBC_OK;
}