From 0d8d92cf4631f4a0a88fe04817d375f9e73408e4 Mon Sep 17 00:00:00 2001 From: salmoon Date: Wed, 28 Aug 2002 16:10:44 +0000 Subject: Initial revision --- libmpio/mpio.c | 769 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 769 insertions(+) create mode 100644 libmpio/mpio.c (limited to 'libmpio/mpio.c') diff --git a/libmpio/mpio.c b/libmpio/mpio.c new file mode 100644 index 0000000..ce16963 --- /dev/null +++ b/libmpio/mpio.c @@ -0,0 +1,769 @@ +/* + * + * $Id: mpio.c,v 1.1 2002/08/28 16:10:50 salmoon 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. + * + * */ + +#include +#include +#include +#include + +#include "defs.h" +#include "debug.h" +#include "directory.h" +#include "io.h" +#include "mpio.h" +#include "smartmedia.h" +#include "fat.h" + +#define DSTRING 100 + +int sector_hack(int mem, int sector); +void mpio_init_internal(mpio_t *); +void mpio_init_external(mpio_t *); + +void +mpio_init_internal(mpio_t *m) +{ + BYTE i_offset = 0x18; + /* init main memory parameters */ + m->internal.manufacturer = m->version[i_offset]; + m->internal.id = m->version[i_offset+1]; + m->internal.size = mpio_id2mem(m->internal.id); + m->internal.max_cluster = m->internal.size/16*1024; + m->internal.chips = 1; + + /* look for a second installed memory chip */ + if (mpio_id_valid(m->version[i_offset+2])) + { + if(mpio_id2mem(m->internal.id) != mpio_id2mem(m->version[i_offset+3])) + { + printf("Found a MPIO with two chips with different size!"); + printf("I'm utterly confused and aborting now, sorry!"); + printf("Please report this to: mpio-devel@lists.sourceforge.net\n"); + exit(1); + } + m->internal.size = 2 * mpio_id2mem(m->internal.id); + m->internal.chips = 2; + } + + mpio_id2geo(m->internal.id, &m->internal.geo); + + /* read FAT information from spare area */ + m->internal.fat_size=m->internal.size*2; + m->internal.fat=malloc(m->internal.fat_size*SECTOR_SIZE); + mpio_fat_read(m, MPIO_INTERNAL_MEM); + + /* Read directory from internal memory */ + m->internal.dir_offset=0; + mpio_rootdir_read(m, MPIO_INTERNAL_MEM); +} + +void +mpio_init_external(mpio_t *m) +{ + BYTE e_offset=0x20; + + /* heuristic to find the right offset for the external memory */ + while((e_offset<0x3a) && !(mpio_id_valid(m->version[e_offset]))) + e_offset++; + + if (mpio_id_valid(m->version[e_offset])) + { + m->external.manufacturer=m->version[e_offset]; + m->external.id=m->version[e_offset+1]; + } else { + m->external.manufacturer=0; + m->external.id=0; + } + + if (m->external.id!=0) { + + m->external.fat=0; + /* Read things from external memory (if available) */ + m->external.size = mpio_id2mem(m->external.id); + m->external.chips = 1; /* external is always _one_ chip !! */ + mpio_id2geo(m->external.id, &m->external.geo); + + if (m->external.size < 16) { + printf("Sorry, I don't believe this software works with " + "SmartMedia Cards less than 16MB\n" + "Proceed with care and send any findings to: " + "mpio-devel@lists.sourceforge.net\n"); + } + + mpio_bootblocks_read(m, MPIO_EXTERNAL_MEM); + m->external.fat = malloc(SECTOR_SIZE*m->external.fat_size); + mpio_fat_read(m, MPIO_EXTERNAL_MEM); + mpio_rootdir_read(m, MPIO_EXTERNAL_MEM); + } + + + +} + +mpio_t * +mpio_init(void) +{ + mpio_t *new_mpio; + + new_mpio = malloc(sizeof(mpio_t)); + if (!new_mpio) { + debug ("Error allocating memory for mpio_t"); + return NULL; + } + + new_mpio->fd = open(MPIO_DEVICE, O_RDWR); + + if (new_mpio->fd < 0) { + + debug ("Could not open %s\n" + "Verify that the mpio module is loaded and " + "your MPIO is\nconnected and powered up.\n\n" , MPIO_DEVICE); + + return NULL; + } + + /* Read Version Information */ + mpio_io_version_read(new_mpio, new_mpio->version); + + /* fill in values */ + /* TODO: check for different versions !! */ + snprintf(new_mpio->firmware.id, 12, "%s", new_mpio->version); + snprintf(new_mpio->firmware.major, 3, "%s", new_mpio->version + 0x0c); + snprintf(new_mpio->firmware.minor, 3, "%s", new_mpio->version + 0x0e); + snprintf(new_mpio->firmware.year, 5, "%s", new_mpio->version + 0x10); + snprintf(new_mpio->firmware.month, 3, "%s", new_mpio->version + 0x14); + snprintf(new_mpio->firmware.day, 3, "%s", new_mpio->version + 0x16); + + /* internal init */ + mpio_init_internal(new_mpio); + + /* external init */ + mpio_init_external(new_mpio); + + return new_mpio; +} + +/* + * returns available memory + * + * free: give back free memory size + * + */ +int +mpio_memory_free(mpio_t *m, mpio_mem_t mem, int *free) +{ + *free=mpio_fat_free_clusters(m, mem); + if (mem==MPIO_INTERNAL_MEM) { + return (m->internal.geo.SumSector * SECTOR_SIZE / 1000); + } + + if (mem==MPIO_EXTERNAL_MEM) { + return (m->external.geo.SumSector * SECTOR_SIZE / 1000); + } + + return 0; +} + +void +mpio_close(mpio_t *m) +{ + close(m->fd); + + if(m->internal.fat) + free(m->internal.fat); + if(m->external.fat) + free(m->external.fat); + + free(m); + +} + +void +mpio_get_info(mpio_t *m, mpio_info_t *info) +{ + int max=INFO_LINE-1; + snprintf(info->firmware_id, max, "\"%s\"", m->firmware.id); + snprintf(info->firmware_version, max, "%s.%s", + m->firmware.major, m->firmware.minor); + snprintf(info->firmware_date, max, "%s.%s.%s", + m->firmware.day, m->firmware.month, m->firmware.year); + + if (m->internal.chips == 1) { + snprintf(info->firmware_mem_internal, max, "%3dMB (%s)", + mpio_id2mem(m->internal.id), + mpio_id2manufacturer(m->internal.manufacturer)); + } else { + snprintf(info->firmware_mem_internal, max, "%3dMB (%s) - %d chips", + mpio_id2mem(m->internal.id), + mpio_id2manufacturer(m->internal.manufacturer), + m->internal.chips); + } + + snprintf(info->firmware_mem_external, max, "%3dMB (%s)", + mpio_id2mem(m->external.id), + mpio_id2manufacturer(m->external.manufacturer)); +} + +/* void */ +/* mpio_print_version(mpio_t *m) */ +/* { */ +/* printf("Firmware Id: \"%s\"\n", m->firmware.id); */ +/* printf("Firmware Version: %s.%s\n", m->firmware.major, */ +/* m->firmware.minor); */ +/* printf("Firmware Date: %s.%s.%s\n", m->firmware.day, */ +/* m->firmware.month, */ +/* m->firmware.year); */ + +/* printf("internal Memory: %3dMB (%s)\n", */ +/* mpio_id2mem(m->internal.id), */ +/* mpio_id2manufacturer(m->internal.manufacturer)); */ +/* if (m->external.id!=0) { */ +/* printf("external Memory: %3dMB (%s)\n", */ +/* mpio_id2mem(m->external.id), */ +/* mpio_id2manufacturer(m->external.manufacturer)); */ +/* } else { */ +/* printf("external Memory: %3dMB (%s)\n", 0, "not available"); */ +/* } */ +/* } */ + +/* + * + * foo + * + */ + +/* + * HELP! + * + * somebody explain me these values!!! + * + */ + +int +sector_hack(int mem, int sector) +{ + int a = sector; + + /* No Zone-based block management for SmartMedia below 32MB !!*/ + + if (mem == 64) { + /* I'm so large in *not* knowing! */ + if (sector >= 89) + a++; + if (a >= 1000) + a += 21; + if (a >= 2021) + a += 24; + if (a >= 3045) + a += 24; + /* WHAT? */ + if (a >= 3755) + a++; + + } + if ((mem == 128) || (mem == 32)) { + /* two blocks are already spent elsewhere */ + /* question is: where (CIS and ??) */ + if (sector >= 998) + a += 22; + /* ... and then add 24 empty blocks every 1000 sectors */ + a += ((sector - 998) / 1000 * 24); +/* if (a>=2020) */ +/* a+=24; */ +/* if (a>=3044) */ +/* a+=24; */ +/* if (a>=4068) */ +/* a+=24; */ +/* if (a>=5092) */ +/* a+=24; */ +/* if (a>=6116) */ +/* a+=24; */ +/* if (a>=7140) */ +/* a+=24; */ + } + + return a; +} + +int +mpio_file_get(mpio_t *m, mpio_mem_t mem, BYTE *filename, + BYTE (*progress_callback)(int, int)) +{ + BYTE *p; + BYTE bdummy; + WORD wdummy; + + mpio_smartmedia_t *sm; + int data_offset; + BYTE fname[129]; + BYTE block[BLOCK_SIZE]; + DWORD startsector = 0, sector; + DWORD realsector = 0; + int fd, towrite; + + DWORD filesize, fsize; + DWORD fat_and; + DWORD fat_end; + BYTE abort = 0; + + /* please fix me sometime */ + /* the system entry are kind of special ! */ + if (strncmp("sysdum", filename, 6) == 0) + return 0; + + if (mem == MPIO_INTERNAL_MEM) { + sm = &m->internal; + data_offset = 0x00; + fat_and = 0xffffffff; + fat_end = 0xffffffff; + } + + if (mem == MPIO_EXTERNAL_MEM) { + sm = &m->external; + data_offset = sm->dir_offset + DIR_NUM - (2 * BLOCK_SECTORS); + /* FAT 16 vs. FAT 12 */ + if (sm->size==128) { + fat_and = 0xffff; + fat_end = 0xfff8; + } else { + fat_and = 0xfff; + fat_end = 0xff8; + } + } + + p = mpio_directory_open(m, mem); + while (p) { + mpio_dentry_get (m, p, + fname, 128, + &wdummy, &bdummy, &bdummy, + &bdummy, &bdummy, &filesize); + fsize = filesize; + if ((strcmp(fname,filename) == 0) && (strcmp(filename,fname) == 0)) { + startsector = mpio_dentry_get_startsector(m, p); + p = NULL; + } + + p = mpio_dentry_next(m, p); + } + + /* grr, of curse these are clusters not sectors */ + /* must code while awake, must ... */ + if (startsector) { + fd = open(filename, (O_RDWR | O_CREAT), (S_IRWXU | S_IRGRP | S_IROTH)); + debugn(2, "startsector: %4x\n", startsector); + sector = startsector; + if (mem == MPIO_INTERNAL_MEM) { + realsector = mpio_fat_internal_find_startsector(m, sector); + realsector = realsector+ /* chose the right bank */ + (0x01000000 * ((realsector / (sm->size / 16 * 1000 / sm->chips)) + 1)); + sector=realsector; + debugn(2, "startsector (real): %4x\n", sector); + } else { + realsector=sector_hack(sm->size, sector); + } + + mpio_io_block_read(m, mem, realsector + (data_offset / BLOCK_SECTORS), + sm->size, 0, block); + + if (filesize > BLOCK_SIZE) { + towrite = BLOCK_SIZE; + } else { + towrite = filesize; + } + + if (write(fd, block, towrite) != towrite) { + debug("error writing file data\n"); + close(fd); + return -1; + } + + filesize -= towrite; + + debugn(5, "sector: (%6x) %4x\n", + (sector&0xffffff), mpio_fat_entry_read(m, mem, sector&0xffffff)); + + + + while((((mpio_fat_entry_read(m, mem, (sector & 0xffffff)) & fat_and) + < fat_end)) && (filesize > 0) && (!abort)) { + sector=mpio_fat_entry_read(m, mem, sector & 0xffffff); + debugn(2,"next sector: %4x\n", sector); + if (mem == MPIO_INTERNAL_MEM) { + realsector = sector; + } else { + realsector = sector_hack(sm->size, sector); + } + + debugn(2," realsector: %4x\n", realsector); + + mpio_io_block_read(m, mem, + (realsector + (data_offset / BLOCK_SECTORS)), + sm->size, 0, block); + if (filesize > BLOCK_SIZE) { + towrite=BLOCK_SIZE; + } else { + towrite=filesize; + } + + if (write(fd, block, towrite)!=towrite) { + debug("error writing file data\n"); + close(fd); + return -1; + } + filesize-=towrite; + + if (progress_callback) + abort=(*progress_callback)((fsize-filesize), fsize); + + } + + close (fd); + } else { + debug("unable to locate the file: %s\n", filename); + } + + return (fsize-filesize); +} + +int +mpio_file_put(mpio_t *m, mpio_mem_t mem, BYTE *filename, + BYTE (*progress_callback)(int, int)) +{ + mpio_smartmedia_t *sm; + int data_offset; + BYTE block[BLOCK_SIZE]; + DWORD startsector=0, sector, nextsector; + DWORD realsector=0; + int fd, toread; + struct stat file_stat; + + DWORD filesize, fsize; + DWORD fat_and; + DWORD fat_end; + BYTE abort=0; + + + if (mem==MPIO_INTERNAL_MEM) { + sm=&m->internal; + data_offset=0x00; + fat_and=0xffffffff; + fat_end=0xffffffff; + debug("writing to internal memory is not yet supported, sorry\n"); + return 0; + } + + if (mem==MPIO_EXTERNAL_MEM) { + sm=&m->external; + data_offset=sm->dir_offset+DIR_NUM-(2*BLOCK_SECTORS); + /* FAT 16 vs. FAT 12 */ + if (sm->size==128) { + fat_and=0xffff; + fat_end=0xfff8; + } else { + fat_and=0xfff; + fat_end=0xff8; + } + } + + if (stat((const char *)filename, &file_stat)!=0) { + debug("could not find file: %s\n", filename); + return 0; + } + + fsize=filesize=file_stat.st_size; + debugn(2, "filesize: %d\n", fsize); + + fd = open(filename, O_RDONLY); + if (fd==-1) { + debug("could not find file: %s\n", filename); + return 0; + } + + while ((filesize>0) & (!abort)) { + + if (filesize>=BLOCK_SIZE) { + toread=BLOCK_SIZE; + } else { + toread=filesize; + } + + if (read(fd, block, toread)!=toread) { + debug("error reading file data\n"); + close(fd); + return -1; + } + + if (!startsector) { + startsector=mpio_fat_find_free(m, mem); + if (!startsector) { + debug("could not find startsector for file!\n"); + close(fd); + return 0; + } + sector=startsector; + debugn(2, "startsector: %d\n", startsector); + /* evil hacks are us ;-) */ + mpio_fat_entry_write(m, mem, startsector, fat_and); + } else { + nextsector=mpio_fat_find_free(m, mem); + if (!nextsector){ + debug("no more free blocks, short write!\n"); + close(fd); + return (fsize-filesize); + } + debugn(2, " nextsector: %d\n", nextsector); + + mpio_fat_entry_write(m, mem, sector, nextsector); + sector=nextsector; + /* evil hacks are us ;-) */ + mpio_fat_entry_write(m, mem, sector, fat_and); + + } + + if (mem==MPIO_INTERNAL_MEM) { +/* realsector=fat_internal_find_startsector(m, sector); */ +/* realsector=realsector+ /\* chose the right bank *\/ */ +/* (0x01000000*((realsector/(sm->size/16*1000/sm->chips))+1)); */ +/* sector=realsector; */ +/* debugn(2, "startsector (real): %4x\n", sector); */ + } else { + realsector=sector_hack(sm->size, sector); + } + +/* debug("mager: %04x : %3d\n", realsector*BLOCK_SECTORS, realsector); */ + mpio_io_block_delete(m, mem, ((realsector*BLOCK_SECTORS) + data_offset), + sm->size); + mpio_io_block_write(m, mem, realsector + (data_offset/BLOCK_SECTORS), + sm->size, 0x48, block); + + filesize -= toread; + + if (progress_callback) + abort=(*progress_callback)((fsize-filesize), fsize); + } + + close(fd); + + /* FIXEME: add real values here!!! */ + mpio_dentry_put(m, mem, + filename, strlen(filename), + 2002, 8, 13, + 2, 12, fsize, startsector); + + mpio_fat_write(m, mem); + + return fsize-filesize; +} + +int +mpio_memory_format(mpio_t *m, mpio_mem_t mem, + BYTE (*progress_callback)(int, int)) +{ + int data_offset; + mpio_smartmedia_t *sm; + DWORD clusters; + DWORD i; + + if (mem == MPIO_INTERNAL_MEM) { + sm=&m->internal; + data_offset=0x00; + debug("formatting of internal memory is not yet supported, sorry\n"); + return 0; + } + + if (mem == MPIO_EXTERNAL_MEM) { + sm = &m->external; + data_offset = sm->dir_offset+DIR_NUM; + } +/* debug("mager: %2x\n", data_offset); */ + + clusters = sm->size*128; + +/* debug("Clusters: %4x\n", sm->size*128); */ + + for (i = data_offset; i < clusters; i += 0x20) { + mpio_io_block_delete(m, mem, i, sm->size); + if (progress_callback) + (*progress_callback)(i, clusters + 1); + } + + /* format CIS area */ + mpio_io_block_delete(m, mem, 0x20, sm->size); + mpio_io_sector_write(m, mem, 0x20, sm->size, 0, sm->cis); + mpio_io_sector_write(m, mem, 0x21, sm->size, 0, sm->cis); + + mpio_fat_clear(m, mem); + mpio_rootdir_clear(m, mem); + mpio_fat_write(m, mem); + + if (progress_callback) + (*progress_callback)(clusters+1, clusters+1); + + return 0; +} + + +/* can we share code with mpio_file_get ??? */ +int +mpio_file_del(mpio_t *m, mpio_mem_t mem, BYTE *filename, + BYTE (*progress_callback)(int, int)) +{ + BYTE *p; + BYTE bdummy; + WORD wdummy; + + mpio_smartmedia_t *sm; + int data_offset; + BYTE fname[129]; + DWORD startsector=0, sector; + DWORD realsector=0, oldsector=0; + int towrite; + + DWORD filesize, fsize; + DWORD fat_and; + DWORD fat_end; + BYTE abort=0; + + /* please fix me sometime */ + /* the system entry are kind of special ! */ + if (strncmp("sysdum", filename, 6)==0) + return 0; + + if (mem==MPIO_INTERNAL_MEM) { + sm=&m->internal; + data_offset=0x00; + fat_and=0xffffffff; + fat_end=0xffffffff; + debug("deleting from files of internal memory" + " is not yet supported, sorry\n"); + return 0; + } + + if (mem==MPIO_EXTERNAL_MEM) { + sm=&m->external; + data_offset=sm->dir_offset+DIR_NUM-(2*BLOCK_SECTORS); + /* FAT 16 vs. FAT 12 */ + if (sm->size==128) { + fat_and=0xffff; + fat_end=0xfff8; + } else { + fat_and=0xfff; + fat_end=0xff8; + } + } + + + p=mpio_directory_open(m, mem); + while (p) { + + mpio_dentry_get (m, p, + fname, 128, + &wdummy, &bdummy, &bdummy, + &bdummy, &bdummy, &filesize); + fsize=filesize; + if ((strcmp(fname,filename)==0) && (strcmp(filename,fname)==0)) { + startsector=mpio_dentry_get_startsector(m, p); + p=NULL; + } + + p=mpio_dentry_next(m, p); + } + + /* grr, of curse these are clusters not sectors */ + /* must code while awake, must ... */ + if (startsector) { + debugn(2, "startsector: %4x\n", startsector); + sector = startsector; + if (mem == MPIO_INTERNAL_MEM) { + realsector = mpio_fat_internal_find_startsector(m, sector); + realsector = realsector+ /* chose the right bank */ + (0x01000000*((realsector / (sm->size / 16 * 1000 / sm->chips)) + 1)); + sector = realsector; + debugn(2, "startsector (real): %4x\n", sector); + } else { + realsector = sector_hack(sm->size, sector); + } + + mpio_io_block_delete(m, mem, (realsector * BLOCK_SECTORS) + data_offset, + sm->size); + + if (filesize > BLOCK_SIZE) { + towrite = BLOCK_SIZE; + } else { + towrite = filesize; + } + + filesize -= towrite; + + debugn(5, "sector: (%6x) %4x\n", + (sector&0xffffff), mpio_fat_entry_read(m, mem, sector&0xffffff)); + + while((((mpio_fat_entry_read(m, mem, (sector & 0xffffff)) & fat_and) + < fat_end)) && (filesize>0) && (!abort)) { + oldsector = sector; + sector = mpio_fat_entry_read(m, mem, sector & 0xffffff); + mpio_fat_entry_write(m, mem, oldsector, 0); + debugn(2,"next sector: %4x\n", sector); + if (mem == MPIO_INTERNAL_MEM) { + realsector = sector; + } else { + realsector = sector_hack(sm->size, sector); + } + + debugn(2," realsector: %4x\n", realsector); + + mpio_io_block_delete(m, mem, + ((realsector * BLOCK_SECTORS) + data_offset), + sm->size); + if (filesize > BLOCK_SIZE) { + towrite = BLOCK_SIZE; + } else { + towrite = filesize; + } + + filesize -= towrite; + + if (progress_callback) + abort=(*progress_callback)((fsize-filesize), fsize); + } + mpio_fat_entry_write(m, mem, sector, 0); + + } else { + debug("unable to locate the file: %s\n", filename); + } + + /* TODO: delete directory entry */ + mpio_dentry_delete(m, mem, filename); + + mpio_fat_write(m, mem); + + return (fsize-filesize); +} + + + -- cgit v1.2.3