From 4412ca091e6379def8bc836163c6b580df76619c Mon Sep 17 00:00:00 2001 From: crunchy Date: Wed, 23 Apr 2003 08:34:01 +0000 Subject: start restructuring --- libmpio/src/io.c | 1213 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1213 insertions(+) create mode 100644 libmpio/src/io.c (limited to 'libmpio/src/io.c') diff --git a/libmpio/src/io.c b/libmpio/src/io.c new file mode 100644 index 0000000..eaaadd4 --- /dev/null +++ b/libmpio/src/io.c @@ -0,0 +1,1213 @@ +/* -*- linux-c -*- */ + +/* + * + * $Id: io.c,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * uses code from mpio_stat.c by + * Yuji Touya (salmoon@users.sourceforge.net) + * + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * */ + +/* + * + * low level I/O + * + * + */ + +#include +#include +#include +#include + +#include "io.h" +#include "debug.h" +#include "ecc.h" + +BYTE model2externalmem(mpio_model_t); +DWORD blockaddress_encode(DWORD); +DWORD blockaddress_decode(BYTE *); +void fatentry2hw(mpio_fatentry_t *, BYTE *, DWORD *); + +/* small hack to handle external addressing on different MPIO models */ +BYTE +model2externalmem(mpio_model_t model) +{ + BYTE m; + + switch(model) + { + case MPIO_MODEL_DMG: + case MPIO_MODEL_DMG_PLUS: + m = 0x80; + break; + default: + m = 0x10; + } + + return m; +} + +/* encoding and decoding of blockaddresses */ + +DWORD +blockaddress_encode(DWORD ba) +{ + WORD addr; + BYTE p = 0, c = 0; + BYTE high, low; + + high = 0x10 | ((ba / 0x80) & 0x07); + low = (ba * 2) & 0xff; + + c = high; + while (c) + { + if (c & 0x01) + p ^= 1; + c /= 2; + } + + c = low; + while (c) + { + if (c & 0x01) + p ^= 0x01; + c /= 2; + } + + addr = (high * 0x100) + low + p; + + return addr; +} + + +DWORD +blockaddress_decode(BYTE *entry) +{ + WORD ba; + WORD value; + BYTE p=0, high, low; + int i, t; + + /* check for "easy" defect block */ + t=1; + for(i=0; i<0x10; i++) + if (entry[i] != 0) + t=0; + if (t) + return MPIO_BLOCK_DEFECT; + + /* check for "easy" defect block */ + t=1; + for(i=0; i<0x10; i++) + if (entry[i] != 0xff) + t=0; + if (t) + return MPIO_BLOCK_FREE; + + /* check for "strange" errors */ + if ((entry[6] != entry[11]) || + (entry[7] != entry[12])) + { + debug("error: different block addresses found:\n"); + hexdumpn(1, entry, 0x10); + return MPIO_BLOCK_DEFECT; + } + + ba = entry[6] * 0x100 + entry[7]; + + /* special values */ + if (ba == 0xffff) + return MPIO_BLOCK_DEFECT; + if (ba == 0x0000) + return MPIO_BLOCK_CIS; + + /* check parity */ + value = ba; + while (value) + { + if (value & 0x01) + p ^= 0x01; + + value /= 2; + } + if (p) + { + debug("parity error found in block address: %2x\n", ba); + return MPIO_BLOCK_DEFECT; + } + + high = ((ba / 0x100) & 0x07); + low = ((ba & 0x0ff) / 2); + + return (high * 0x80 + low); +} + +/* foobar */ + +void +fatentry2hw(mpio_fatentry_t *f, BYTE *chip, DWORD *address) +{ + mpio_smartmedia_t *sm; + + if (f->mem == MPIO_INTERNAL_MEM) + { + sm = &f->m->internal; + /* hexdump((char *)&f->entry, 4); */ + /* hexdump((char *)&f->hw_address, 4); */ + *chip = f->hw_address / 0x1000000; + *address = f->hw_address & 0x0ffffff; + } + if (f->mem == MPIO_EXTERNAL_MEM) + { + sm = &f->m->external; + *chip = MPIO_EXTERNAL_MEM; + *address = mpio_zone_block_find_log(f->m, f->mem, f->entry); + debugn(3, "mager: %06x (logical: %04x)\n", *address, f->entry); + } + return; +} + +/* + * zone management + */ + +int +mpio_zone_init(mpio_t *m, mpio_cmd_t mem) +{ + mpio_smartmedia_t *sm; + int i; + int zone, block, e; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return -1; + } + sm = &m->external; + + for(i=0; imax_blocks; i++) + { + zone = i / MPIO_ZONE_PBLOCKS; + block= i % MPIO_ZONE_PBLOCKS; + + e = i * 0x10; + + sm->zonetable[zone][block]=blockaddress_decode(sm->spare+e); + + hexdumpn(4, sm->spare+e, 0x10); + debugn(2, "decoded: %04x\n", sm->zonetable[zone][block]); + } + +} + +DWORD +mpio_zone_block_find_log(mpio_t *m, mpio_cmd_t mem, DWORD lblock) +{ + mpio_smartmedia_t *sm; + int v; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return -1; + } + sm = &m->external; + + /* OK, I can't explain this right now, but it does work, + * see Software Driver v3.0, page 31 + */ + v = lblock + (sm->size/64); + + return (mpio_zone_block_find_seq(m, mem, v)); +} + +DWORD +mpio_zone_block_find_seq(mpio_t *m, mpio_cmd_t mem, DWORD lblock) +{ + mpio_smartmedia_t *sm; + int i, f, v; + int zone, block; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return -1; + } + sm = &m->external; + + if ((lblock>=MPIO_BLOCK_CIS) && (lblock<(MPIO_BLOCK_CIS + BLOCK_SECTORS))) + { + zone = 0; + block = MPIO_BLOCK_CIS; + } else { + zone = lblock / MPIO_ZONE_LBLOCKS; + block = lblock % MPIO_ZONE_LBLOCKS; + } + + f=0; + for (i=(MPIO_ZONE_PBLOCKS-1); i >=0; i--) + { + + if (sm->zonetable[zone][i]==block) + { + f++; + v=i; + } + } + + if (f>1) + debug("found more than one block, using first one\n"); + + if (!f) + { + debugn(2, "block not found\n"); + return MPIO_BLOCK_NOT_FOUND; + } + + return ((zone * BLOCK_SECTORS * MPIO_ZONE_PBLOCKS ) + v * BLOCK_SECTORS); +} + +DWORD +mpio_zone_block_set_free(mpio_t *m, mpio_cmd_t mem, DWORD lblock) +{ + DWORD value; + int zone, block; + mpio_smartmedia_t *sm; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return -1; + } + sm = &m->external; + + value = mpio_zone_block_find_log(m, mem, lblock); + + mpio_zone_block_set_free_phys(m, mem, value); + + return value; +} + +void +mpio_zone_block_set_free_phys(mpio_t *m, mpio_cmd_t mem, DWORD value) +{ + int zone, block; + mpio_smartmedia_t *sm; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return; + } + sm = &m->external; + + zone = value / BLOCK_SECTORS; + block = zone % MPIO_ZONE_PBLOCKS; + zone = zone / MPIO_ZONE_PBLOCKS; + + sm->zonetable[zone][block] = MPIO_BLOCK_FREE; + + return; +} + +void +mpio_zone_block_set_defect_phys(mpio_t *m, mpio_cmd_t mem, DWORD value) +{ + int zone, block; + mpio_smartmedia_t *sm; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return; + } + sm = &m->external; + + zone = value / BLOCK_SECTORS; + block = zone % MPIO_ZONE_PBLOCKS; + zone = zone / MPIO_ZONE_PBLOCKS; + + sm->zonetable[zone][block] = MPIO_BLOCK_DEFECT; + + return; +} + +void +mpio_zone_block_set(mpio_t *m, mpio_cmd_t mem, DWORD pblock) +{ + int zone, block, pb; + + pb = pblock / BLOCK_SECTORS; + zone = pb / MPIO_ZONE_PBLOCKS; + block = pb % MPIO_ZONE_PBLOCKS; + + m->external.zonetable[zone][block] = MPIO_BLOCK_FREE ; + +} + +DWORD +mpio_zone_block_find_free_log(mpio_t *m, mpio_cmd_t mem, DWORD lblock) +{ + mpio_smartmedia_t *sm; + int v; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return -1; + } + sm = &m->external; + + /* OK, I can't explain this right now, but it does work, + * see Software Driver v3.0, page 31 + */ + v = lblock + (sm->size/64); + + return (mpio_zone_block_find_free_seq(m, mem, v)); +} + +DWORD +mpio_zone_block_find_free_seq(mpio_t *m, mpio_cmd_t mem, DWORD lblock) +{ + DWORD value; + int zone, block, i; + mpio_smartmedia_t *sm; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return -1; + } + sm = &m->external; + + value = mpio_zone_block_find_seq(m, mem, lblock); + + if (value != MPIO_BLOCK_NOT_FOUND) + { + debug("logical block numbers is already assigned! (%4x)\n", lblock); + exit (-1); + } + + if ((lblock>=MPIO_BLOCK_CIS) && (lblock<(MPIO_BLOCK_CIS + BLOCK_SECTORS))) + { + zone = 0; + block = MPIO_BLOCK_CIS; + } else { + zone = lblock / MPIO_ZONE_LBLOCKS; + block = lblock % MPIO_ZONE_LBLOCKS; + } + + i=0; + while ((sm->zonetable[zone][i]!=MPIO_BLOCK_FREE) && (izonetable[zone][i] = block; + + return ((zone * BLOCK_SECTORS * MPIO_ZONE_PBLOCKS ) + i * BLOCK_SECTORS); +} + + +WORD +mpio_zone_block_get_logical(mpio_t *m, mpio_cmd_t mem, DWORD pblock) +{ + int zone, block, pb; + + pb = pblock / BLOCK_SECTORS; + zone = pb / MPIO_ZONE_PBLOCKS; + block = pb % MPIO_ZONE_PBLOCKS; + + return m->external.zonetable[zone][block]; +} + + + + + +/* + * low-low level functions + */ + +/* + * Set command packet + * + * parameter: + * + * cmd: commando code + * mem: internal/external + * index: sector/block + * size: size of used memory chip + * wsize: write size, only for PUT_BLOCK + * buffer: output buffer of command packet + * + */ + +int +mpio_io_set_cmdpacket(mpio_t *m, mpio_cmd_t cmd, mpio_mem_t mem, DWORD index, + WORD size, BYTE wsize, BYTE *buffer) +{ + BYTE memory; + + /* clear cmdpacket*/ + memset(buffer, 0, 0x40); + + *buffer = cmd; + memory = mem; + if (mem == MPIO_EXTERNAL_MEM) + memory = model2externalmem(m->model); + + *(buffer + 0x01) = memory; + *(buffer + 0x03) = (BYTE) (index & 0x00ff); + *(buffer + 0x04) = (BYTE)((index & 0xff00) >> 8); + /* SM cards with less or equal 32 MB only need 2 Bytes + * to address sectors or blocks. + * The highest byte has to be 0xff in that case! + */ + if (size <= 32) + { + *(buffer + 0x05) = 0xff; + } else { + *(buffer + 0x05) = (BYTE) (index >> 16); + } + /* is this always 0x48 in case of a block write ?? */ + *(buffer + 0x06) = wsize; + + memcpy((buffer + 0x3b), "jykim", 5); + + return (0); +} + +/* + * write chunk of data to MPIO filedescriptor + * + * parameter: + * + * fd: filedescriptor + * block: data buffer (has to be num_bytes) + * num_bytes: size of data buffer + * + */ +int +mpio_io_bulk_write(int fd, BYTE *block, int num_bytes) +{ + BYTE *p; + int count, bytes_left, bytes_written; + + bytes_left = num_bytes; + bytes_written = 0; + p = block; + + do + { + count = write (fd, p, bytes_left); + if (count > 0) + { + p += count; + bytes_written += count; + bytes_left -= count; + } + } while (bytes_left > 0 && count > 0); + + return bytes_written; +} + +/* + * read chunk of data from MPIO filedescriptor + * + * parameter: + * + * fd: filedescriptor + * block: return buffer (has to be num_bytes) + * num_bytes: size of return buffer + * + */ +int +mpio_io_bulk_read (int fd, BYTE *block, int num_bytes) +{ + int total_read, count, bytes_left; + BYTE *p; + + total_read = 0; + bytes_left = num_bytes; + p = block; + + do + { + count = read (fd, p, bytes_left); + + if (count > 0) + { + total_read += count; + bytes_left -= count; + p += count; + } + } while (total_read < num_bytes && count > 0); + + return total_read; +} + +/* + * low level functions + */ + +/* + * read version block from MPIO + * + * parameter: + * + * m: mpio context + * buffer: return buffer (has to be CMD_SIZE) + * + */ +int +mpio_io_version_read(mpio_t *m, BYTE *buffer) +{ + int nwrite, nread; + BYTE cmdpacket[CMD_SIZE], status[CMD_SIZE]; + + /* Send command packet to MPIO */ + mpio_io_set_cmdpacket (m, GET_VERSION, 0, 0, 0xff, 0, cmdpacket); + + debugn (5, ">>> MPIO\n"); + hexdump (cmdpacket, sizeof(cmdpacket)); + + nwrite = mpio_io_bulk_write (m->fd, cmdpacket, 0x40); + + if (nwrite != CMD_SIZE) + { + debug ("Failed to send command.\n\n"); + close (m->fd); + return 0; + } + + /* Receive packet from MPIO */ + nread = mpio_io_bulk_read (m->fd, status, 0x40); + + if (nread == -1 || nread != 0x40) + { + debug ("Failed to read Sector.\n%x\n",nread); + close (m->fd); + return 0; + } + + debugn (5, "<<< MPIO\n"); + hexdump (status, 0x40); + + memcpy(buffer, status, 0x40); + + return CMD_SIZE; +} + +/* + * read sector from SmartMedia + * + * parameter: + * + * m: mpio context + * mem: MPIO_{INTERNAL,EXTERNAL}_MEM + * index: index number of sector to read + * output: return buffer (has to be SECTOR_SIZE) + * + */ + +/* right now we assume we only want to read single sectors from + * the _first_ internal memory chip + */ + +int +mpio_io_sector_read(mpio_t *m, BYTE mem, DWORD index, BYTE *output) +{ + mpio_smartmedia_t *sm=0; + DWORD sector; + int nwrite, nread; + BYTE cmdpacket[CMD_SIZE], recvbuff[SECTOR_TRANS]; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + if (!sm) + { + debug("error in memory selection, aborting\n"); + exit (-1); + } + + if (mem == MPIO_INTERNAL_MEM) + { + sector = index; + } else { + /* find the correct physical block first! */ + if ((index>=MPIO_BLOCK_CIS) && (index<(MPIO_BLOCK_CIS + BLOCK_SECTORS))) + { + sector = mpio_zone_block_find_seq(m, mem, MPIO_BLOCK_CIS); + sector+= (index % MPIO_BLOCK_CIS); + } else { + sector = mpio_zone_block_find_seq(m, mem, (index / 0x20)); + sector+= (index % 0x20); + } + } + + debugn (2, "sector: %8x (%06x)\n", index, sector); + + mpio_io_set_cmdpacket (m, GET_SECTOR, mem, sector, sm->size, 0, cmdpacket); + + debugn (5, "\n>>> MPIO\n"); + hexdump (cmdpacket, sizeof(cmdpacket)); + + nwrite = mpio_io_bulk_write (m->fd, cmdpacket, 0x40); + + if(nwrite != CMD_SIZE) + { + debug ("\nFailed to send command.\n\n"); + close (m->fd); + return 1; + } + + /* Receive packet from MPIO */ + nread = mpio_io_bulk_read (m->fd, recvbuff, SECTOR_TRANS); + + if(nread != SECTOR_TRANS) + { + debug ("\nFailed to read Sector.\n%x\n", nread); + close (m->fd); + return 1; + } + + /* check ECC Area information */ + if (mem==MPIO_EXTERNAL_MEM) + { + if (mpio_ecc_256_check (recvbuff, + (recvbuff + SECTOR_SIZE + 13)) || + mpio_ecc_256_check ((recvbuff + (SECTOR_SIZE / 2)), + (recvbuff + SECTOR_SIZE + 8)) ) + debug ("ECC error @ (%02x : %06x)\n", mem, index); + } + + /* This should not be needed: + * we don't have ECC information for the internal memory + * we only read the directory through this function + */ + /* if (mem==MPIO_INTERNAL_MEM) */ + /* { */ + /* debugn(2, "WARNING, code for internal FAT entry (in ECC area)" */ + /* " not yet in place!!\n"); */ + /* } */ + + debugn (5, "\n<<< MPIO\n"); + hexdump (recvbuff, SECTOR_TRANS); + + memcpy(output, recvbuff, SECTOR_SIZE); + + return 0; +} + +/* + * write sector to SmartMedia + * + * parameter: + * + * m: mpio context + * mem: MPIO_{INTERNAL,EXTERNAL}_MEM + * index: index number of sector to read + * input: data buffer (has to be SECTOR_SIZE) + * + */ + +/* right now we assume we only want to write single sectors from + * the _first_ internal memory chip + */ + +int +mpio_io_sector_write(mpio_t *m, BYTE mem, DWORD index, BYTE *input) +{ + int nwrite; + mpio_smartmedia_t *sm; + DWORD pvalue; + DWORD block_address, ba; + BYTE cmdpacket[CMD_SIZE], sendbuff[SECTOR_TRANS]; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + if (!sm) + { + debug("error in memory selection, aborting\n"); + exit (-1); + } + + /* we have to: + * - find the physical block (or allocate a new one) + * - calculate the logical block for zone management + */ + + if (mem == MPIO_EXTERNAL_MEM) + { + if (index==MPIO_BLOCK_DEFECT) + { + block_address = 0; + pvalue = 0; + } else { + if ((index>=MPIO_BLOCK_CIS) && + (index<(MPIO_BLOCK_CIS + BLOCK_SECTORS))) + { + block_address = 0; + if (index==MPIO_BLOCK_CIS) + { + pvalue=mpio_zone_block_find_free_seq(m, mem, index); + } else { + /* find the block from the block list! */ + pvalue=mpio_zone_block_find_seq(m, mem, MPIO_BLOCK_CIS); + } + if (pvalue != MPIO_BLOCK_NOT_FOUND) + pvalue = pvalue + index - MPIO_BLOCK_CIS; + + } else { + block_address = blockaddress_encode(index / BLOCK_SECTORS); + if ((index % BLOCK_SECTORS) == 0) + { + /* this is the first write to the block: allocate a new one */ + /* ... and mark it with the block_address */ + pvalue=mpio_zone_block_find_free_seq(m, mem, + (index / BLOCK_SECTORS)); + } else { + /* find the block from the block list! */ + pvalue=mpio_zone_block_find_seq(m, mem, (index / BLOCK_SECTORS)); + } + if (pvalue != MPIO_BLOCK_NOT_FOUND) + pvalue = pvalue + (index % BLOCK_SECTORS); + + } + + if (pvalue == MPIO_BLOCK_NOT_FOUND) + { + debug ("Oops, this should never happen! (%6x : %6x)\n", + index, block_address); + exit (-1); + } + } + } else { + pvalue = index; + } + + mpio_io_set_cmdpacket(m, PUT_SECTOR, mem, pvalue, sm->size, 0, cmdpacket); + + debugn (5, "\n>>> MPIO\n"); + hexdump (cmdpacket, sizeof(cmdpacket)); + + nwrite = mpio_io_bulk_write(m->fd, cmdpacket, 0x40); + + if(nwrite != CMD_SIZE) + { + debug ("\nFailed to send command.\n\n"); + close (m->fd); + return 1; + } + + memset(sendbuff, 0, SECTOR_TRANS); + memset(sendbuff + SECTOR_SIZE, 0xff, 0x10); + memcpy(sendbuff, input, SECTOR_SIZE); + + if (mem==MPIO_EXTERNAL_MEM) + { + if (index == MPIO_BLOCK_DEFECT) { + memset(sendbuff + SECTOR_SIZE, 0, 0x10); + mpio_zone_block_set_defect_phys(m, mem, pvalue); + } else { + + /* generate ECC information for spare area ! */ + mpio_ecc_256_gen(sendbuff, + sendbuff + SECTOR_SIZE + 0x0d); + mpio_ecc_256_gen(sendbuff + (SECTOR_SIZE / 2), + sendbuff + SECTOR_SIZE + 0x08); + if (index == MPIO_BLOCK_DEFECT) { + memset(sendbuff + SECTOR_SIZE, 0, 0x10); + } else { + if (index == MPIO_BLOCK_CIS) { + memset(sendbuff + SECTOR_SIZE + 0x06, 0, 2); + memset(sendbuff + SECTOR_SIZE + 0x0b, 0, 2); + } else { + ba = (block_address / 0x100) & 0xff; + sendbuff[SECTOR_SIZE + 0x06] = ba; + sendbuff[SECTOR_SIZE + 0x0b] = ba; + + ba = block_address & 0xff; + sendbuff[SECTOR_SIZE + 0x07] = ba; + sendbuff[SECTOR_SIZE + 0x0c] = ba; + } + } + + } + } + + /* easy but working, we write back the FAT info we read before */ + if (mem==MPIO_INTERNAL_MEM) + memcpy((sendbuff+SECTOR_SIZE), sm->fat, 0x10); + + debugn (5, "\n>>> MPIO\n"); + hexdump(sendbuff, SECTOR_TRANS); + + /* write sector MPIO */ + nwrite = mpio_io_bulk_write(m->fd, sendbuff, SECTOR_TRANS); + + if(nwrite != SECTOR_TRANS) + { + debug ("\nFailed to read Sector.\n%x\n", nwrite); + close (m->fd); + return 1; + } + + return 0; +} + +/* + * read/write of blocks + */ +int +mpio_io_block_read(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f, BYTE *output) +{ + int i=0; + int nwrite, nread; + mpio_smartmedia_t *sm; + BYTE chip; + DWORD address; + BYTE cmdpacket[CMD_SIZE], recvbuff[BLOCK_TRANS]; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + fatentry2hw(f, &chip, &address); + + mpio_io_set_cmdpacket(m, GET_BLOCK, chip, address, sm->size, 0, cmdpacket); + + debugn(5, "\n>>> MPIO\n"); + hexdump(cmdpacket, sizeof(cmdpacket)); + + nwrite = mpio_io_bulk_write(m->fd, cmdpacket, CMD_SIZE); + + if(nwrite != CMD_SIZE) + { + debug ("\nFailed to send command.\n\n"); + close (m->fd); + return 1; + } + + /* Receive packet from MPIO */ + nread = mpio_io_bulk_read(m->fd, recvbuff, BLOCK_TRANS); + + if(nread != BLOCK_TRANS) + { + debug ("\nFailed to read Block.\n%x\n",nread); + close (m->fd); + return 1; + } + + debugn(5, "\n<<< MPIO\n"); + hexdump(recvbuff, BLOCK_TRANS); + + for (i = 0; i < BLOCK_SECTORS; i++) + { + /* check ECC Area information */ + if (mem==MPIO_EXTERNAL_MEM) { + if (mpio_ecc_256_check ((recvbuff + (i * SECTOR_TRANS)), + ((recvbuff +(i * SECTOR_TRANS) + + SECTOR_SIZE +13))) || + mpio_ecc_256_check ((recvbuff + (i * SECTOR_TRANS) + + (SECTOR_SIZE / 2)), + ((recvbuff +(i * SECTOR_TRANS) + + SECTOR_SIZE + 8)))) + debug ("ECC error @ (%02x : %06x)\n", chip, address); + } + + memcpy(output + (i * SECTOR_SIZE), + recvbuff + (i * SECTOR_TRANS), + SECTOR_SIZE); + } + + return 0; +} + +/* Read spare is only usefull for the internal memory, + * the FAT lies there. It is updated during the + * mpio_io_{sector,block}_{read,write} operations. + * + * For external SmartMedia cards we have a "seperate" FAT + * which is read and updated just like on a regular floppy + * disc or hard drive. + * + */ + +int +mpio_io_spare_read(mpio_t *m, BYTE mem, DWORD index, WORD size, + BYTE wsize, BYTE *output, int toread, + mpio_callback_init_t progress_callback) +{ + mpio_smartmedia_t *sm; + int i; + int nwrite, nread; + int chip = 0; + int chips = 0; + BYTE cmdpacket[CMD_SIZE]; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + chips = sm->chips; + + for (chip = 1; chip <= chips; chip++) + { + if (mem == MPIO_INTERNAL_MEM) + mpio_io_set_cmdpacket(m, GET_SPARE_AREA, (1 << (chip-1)), + index, (size / sm->chips), + wsize, cmdpacket); + if (mem == MPIO_EXTERNAL_MEM) + mpio_io_set_cmdpacket(m, GET_SPARE_AREA, mem, index, size, + wsize, cmdpacket); + debugn(5, "\n>>> MPIO\n"); + hexdump(cmdpacket, sizeof(cmdpacket)); + + nwrite = mpio_io_bulk_write(m->fd, cmdpacket, CMD_SIZE); + + if(nwrite != CMD_SIZE) { + debug ("\nFailed to send command.\n\n"); + close (m->fd); + return 1; + } + + /* Receive packet from MPIO */ + for (i = 0; i < (toread / chips / CMD_SIZE); i++) + { + nread = mpio_io_bulk_read (m->fd, + output + (i * CMD_SIZE) + + (toread / chips * (chip - 1)), + CMD_SIZE); + + if ((progress_callback) && (i % 256)) + (*progress_callback)(mem, + (i*CMD_SIZE+(toread/chips*(chip-1))), + toread ); + + if(nread != CMD_SIZE) + { + debug ("\nFailed to read Block.\n%x\n",nread); + close (m->fd); + return 1; + } + debugn(5, "\n<<< MPIO\n"); + hexdump(output + (i * CMD_SIZE) + (toread / chips * (chip - 1)), + CMD_SIZE); + } + } + if (progress_callback) + (*progress_callback)(mem, toread, toread); + + return 0; +} + +int +mpio_io_block_delete(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) +{ + BYTE chip=0; + DWORD address; + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + fatentry2hw(f, &chip, &address); + + if (address == MPIO_BLOCK_NOT_FOUND) + { + debug("hmm, what happens here? (%4x)\n", f->entry); + return 0; + } + + return (mpio_io_block_delete_phys(m, chip, address)); +} + +int +mpio_io_block_delete_phys(mpio_t *m, BYTE chip, DWORD address) +{ + mpio_smartmedia_t *sm; + int nwrite, nread; + BYTE cmdpacket[CMD_SIZE], status[CMD_SIZE]; + + /* Send command packet to MPIO */ + + if (chip == MPIO_INTERNAL_MEM) sm = &m->internal; + /* hack to support 2+4 internal chips + * who ever allowed me to write code??? -mager + */ + if (chip == (MPIO_INTERNAL_MEM+1)) sm = &m->internal; + if (chip == (MPIO_INTERNAL_MEM+3)) sm = &m->internal; + if (chip == (MPIO_INTERNAL_MEM+7)) sm = &m->internal; + if (chip == MPIO_EXTERNAL_MEM) + { + sm = &m->external; + mpio_zone_block_set_free_phys(m, chip, address); + } + + mpio_io_set_cmdpacket(m, DEL_BLOCK, chip, address, sm->size, 0, cmdpacket); + + debugn (5, ">>> MPIO\n"); + hexdump (cmdpacket, sizeof(cmdpacket)); + + nwrite = mpio_io_bulk_write(m->fd, cmdpacket, 0x40); + + if (nwrite != CMD_SIZE) + { + debug ("Failed to send command.\n\n"); + close (m->fd); + return 0; + } + +/* Receive packet from MPIO */ + nread = mpio_io_bulk_read (m->fd, status, CMD_SIZE); + + if ((nread == -1) || (nread != CMD_SIZE)) + { + debug ("Failed to read Sector.\n%x\n",nread); + close (m->fd); + return 0; + } + + debugn(5, "<<< MPIO\n"); + hexdump(status, CMD_SIZE); + + if (status[0] != 0xc0) + { + debugn (2,"error formatting Block %02x:%06x\n", + chip, address); + if (chip == MPIO_EXTERNAL_MEM) + { + sm = &m->external; + mpio_zone_block_set_defect_phys(m, chip, address); + } + } + + return CMD_SIZE; +} + +int +mpio_io_block_write(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f, BYTE *data) +{ + mpio_smartmedia_t *sm; + int nwrite; + int i; + DWORD block_address, ba; + BYTE cmdpacket[CMD_SIZE], sendbuff[BLOCK_TRANS]; + BYTE chip=0; + DWORD address; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + fatentry2hw(f, &chip, &address); + } + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->external; + /* find free physical block */ + chip = MPIO_EXTERNAL_MEM; + address = mpio_zone_block_find_free_log(m, mem, f->entry); + } + + /* build block for transfer to MPIO */ + for (i = 0; i < BLOCK_SECTORS; i++) + { + memcpy(sendbuff + (i * SECTOR_TRANS), + data + (i * SECTOR_SIZE), + SECTOR_SIZE); + memset(sendbuff + (i * SECTOR_TRANS) + SECTOR_SIZE, + 0xff, CMD_SIZE); + + if (mem == MPIO_INTERNAL_MEM) + { + if (i == 0) + { + memcpy((sendbuff+SECTOR_SIZE+(i * SECTOR_TRANS)), + f->i_fat, 0x10); +/* debug("address %02x:%06x\n", chip, address); */ +/* hexdumpn(0, f->i_fat, 0x10); */ + } + } + + /* fill in block information */ + if (mem == MPIO_EXTERNAL_MEM) + { + block_address = mpio_zone_block_get_logical(m, mem, address); + block_address = blockaddress_encode(block_address); + + ba = (block_address / 0x100) & 0xff; + sendbuff[(i * SECTOR_TRANS) + SECTOR_SIZE + 0x06] = ba; + sendbuff[(i * SECTOR_TRANS) + SECTOR_SIZE + 0x0b] = ba; + + ba = block_address & 0xff; + sendbuff[(i * SECTOR_TRANS) + SECTOR_SIZE + 0x07] = ba; + sendbuff[(i * SECTOR_TRANS) + SECTOR_SIZE + 0x0c] = ba; + + /* generate ECC Area information */ + mpio_ecc_256_gen ((sendbuff + (i * SECTOR_TRANS)), + ((sendbuff + (i * SECTOR_TRANS) + + SECTOR_SIZE + 13))); + mpio_ecc_256_gen ((sendbuff + (i * SECTOR_TRANS) + + (SECTOR_SIZE / 2)), + ((sendbuff + (i * SECTOR_TRANS) + + SECTOR_SIZE + 8))); + } + } + + mpio_io_set_cmdpacket(m, PUT_BLOCK, chip, address, sm->size, 0x48 , cmdpacket); + + debugn(5, "\n>>> MPIO\n"); + hexdump(cmdpacket, sizeof(cmdpacket)); + + nwrite = mpio_io_bulk_write(m->fd, cmdpacket, CMD_SIZE); + + if(nwrite != CMD_SIZE) + { + debug ("\nFailed to send command.\n\n"); + close (m->fd); + return 1; + } + + /* send packet to MPIO */ + debugn(5, "\n<<< MPIO\n"); + hexdump(sendbuff, BLOCK_TRANS); + nwrite = mpio_io_bulk_write (m->fd, sendbuff, BLOCK_TRANS); + + if(nwrite != BLOCK_TRANS) + { + debug ("\nFailed to read Block.\n%x\n",nwrite); + close (m->fd); + return 1; + } + + return 0; +} -- cgit v1.2.3