diff options
Diffstat (limited to 'libmpio/src')
-rw-r--r-- | libmpio/src/cis.c | 81 | ||||
-rw-r--r-- | libmpio/src/cis.h | 42 | ||||
-rw-r--r-- | libmpio/src/debug.c | 313 | ||||
-rw-r--r-- | libmpio/src/debug.h | 110 | ||||
-rw-r--r-- | libmpio/src/defs.h | 334 | ||||
-rw-r--r-- | libmpio/src/directory.c | 1318 | ||||
-rw-r--r-- | libmpio/src/directory.h | 84 | ||||
-rw-r--r-- | libmpio/src/ecc.c | 247 | ||||
-rw-r--r-- | libmpio/src/ecc.h | 44 | ||||
-rw-r--r-- | libmpio/src/fat.c | 1039 | ||||
-rw-r--r-- | libmpio/src/fat.h | 87 | ||||
-rw-r--r-- | libmpio/src/id3.c | 292 | ||||
-rw-r--r-- | libmpio/src/id3.h | 44 | ||||
-rw-r--r-- | libmpio/src/io.c | 1213 | ||||
-rw-r--r-- | libmpio/src/io.h | 95 | ||||
-rw-r--r-- | libmpio/src/mpio.c | 1301 | ||||
-rw-r--r-- | libmpio/src/mpio.h | 218 | ||||
-rw-r--r-- | libmpio/src/smartmedia.c | 153 | ||||
-rw-r--r-- | libmpio/src/smartmedia.h | 47 |
19 files changed, 7062 insertions, 0 deletions
diff --git a/libmpio/src/cis.c b/libmpio/src/cis.c new file mode 100644 index 0000000..776959d --- /dev/null +++ b/libmpio/src/cis.c @@ -0,0 +1,81 @@ +/* + * + * $Id: cis.c,v 1.1 2003/04/23 08:34:14 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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 "cis.h" + +/* This data is CIS block (Card Information System) of the SmartMedia + * cards, it can be found here: + * http://www.samsungelectronics.com/semiconductors/flash/technical_data/application_notes/SM_format.pdf (page 8 + 9) + * or on any Smartmedia card + * + * It is not believed to be some kind of trade secret or such, so ... + * ... if we are mistaken, please tell us so. + */ + +char cis_templ[0x80] = { + 0x01, 0x03, 0xd9, 0x01, 0xff, 0x18, 0x02, 0xdf, /* 0x00 */ + 0x01, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x21, + + 0x02, 0x04, 0x01, 0x22, 0x02, 0x01, 0x01, 0x22, /* 0x10 */ + 0x03, 0x02, 0x04, 0x07, 0x1a, 0x05, 0x01, 0x03, + + 0x00, 0x02, 0x0f, 0x1b, 0x08, 0xc0, 0xc0, 0xa1, /* 0x20 */ + 0x01, 0x55, 0x08, 0x00, 0x20, 0x1b, 0x0a, 0xc1, + + 0x41, 0x99, 0x01, 0x55, 0x64, 0xf0, 0xff, 0xff, /* 0x30 */ + 0x20, 0x1b, 0x0c, 0x82, 0x41, 0x18, 0xea, 0x61, + + 0xf0, 0x01, 0x07, 0xf6, 0x03, 0x01, 0xee, 0x1b, /* 0x40 */ + 0x0c, 0x83, 0x41, 0x18, 0xea, 0x61, 0x70, 0x01, + + 0x07, 0x76, 0x03, 0x01, 0xee, 0x15, 0x14, 0x05, /* 0x50 */ + 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + + 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x30, 0x2e, /* 0x60 */ + 0x30, 0x00, 0xff, 0x14, 0x00, 0xff, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +}; + +BYTE * +mpio_cis_gen() +{ + BYTE *p; + + p = (BYTE *)malloc(SECTOR_SIZE); + + memset(p, 0, SECTOR_SIZE); + memcpy(p, cis_templ, 0x80); + memcpy(p+0x100, cis_templ, 0x80); + + return p; + +} + + + + diff --git a/libmpio/src/cis.h b/libmpio/src/cis.h new file mode 100644 index 0000000..544d2fa --- /dev/null +++ b/libmpio/src/cis.h @@ -0,0 +1,42 @@ +/* + * + * $Id: cis.h,v 1.1 2003/04/23 08:34:14 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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. + * + * */ + +#ifndef _MPIO_CIS_H_ +#define _MPIO_CIS_H_ + +#include "defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* generate and return a fresh CIS block */ +BYTE *mpio_cis_gen(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmpio/src/debug.c b/libmpio/src/debug.c new file mode 100644 index 0000000..5fd5cbe --- /dev/null +++ b/libmpio/src/debug.c @@ -0,0 +1,313 @@ +/* + * debug.c + * + * Authors: Dirk Meyer <dmeyer@tzi.de> + * Andreas Büsching <crunchy@tzi.de> + * + * $Id: debug.c,v 1.1 2003/04/23 08:34:14 crunchy Exp $ + */ + +#include "debug.h" + +#include <ctype.h> +#include <string.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> + +#define DCOLOR "_color" +#define DFILE "_file" +#define DSUFFIX "_debug" +#define LEVEL_HEXDUMP 5 + +#define CHECK_FD if (__debug_fd == NULL) return; + +char *__debug_color = NULL; +int __debug_level = 0; +FILE *__debug_fd = NULL; + +void +debug_init(void) { + char *env_var = malloc(strlen(DPACKAGE) + strlen(DFILE) + 1); + const char *env; + + /* check debug output file */ + strcpy(env_var, DPACKAGE); + strcat(env_var, DFILE); + + if ((env = getenv(env_var))) { + if (__debug_fd && fileno(__debug_fd) != -1) { + fclose(__debug_fd); + } + + __debug_fd = fopen(env, "a"); + if (!__debug_fd) { + __debug_fd = stderr; + } + } else { + __debug_fd = stderr; + } + + free(env_var); + + /* check debug level */ + env_var = malloc(strlen(DPACKAGE) + strlen(DSUFFIX) + 1); + strcpy(env_var, DPACKAGE); + strcat(env_var, DSUFFIX); + + if ((env = getenv(env_var))) + if (isdigit(env[0])) + __debug_level = strtol(env, NULL, 10); + else + __debug_level = 1; + else + __debug_level = -1; + + free(env_var); + + /* check debug color */ + env_var = malloc(strlen(DPACKAGE) + strlen(DCOLOR) + 1); + + strcpy(env_var, DPACKAGE); + strcat(env_var, DCOLOR); + + if (__debug_color) free(__debug_color); + __debug_color = NULL; + + if ((env = getenv(env_var))) { + if (env[0] != '\0') { + __debug_color = malloc(4 + strlen(env)); + sprintf(__debug_color, "\033[%sm", env); + } else + __debug_color = malloc(6); + strcpy(__debug_color, "\033[32m"); + } else { + __debug_color = NULL; + } + + free(env_var); +} + +int +debug_file(char *filename) +{ + if (__debug_fd && fileno(__debug_fd) != -1) { + fclose(__debug_fd); + } + + __debug_fd = fopen(filename, "a"); + if (!__debug_fd) { + perror("fopen:"); + __debug_fd = stderr; + return 0; + } + + return 1; +} + +int +debug_level(int level) +{ + int tmp = __debug_level; + + __debug_level = level; + + return tmp; +} + +int +debug_level_get(void) +{ + return __debug_level; +} + + +void +_hexdump (const char *package, const char* file, int line, + const char* function, const char* data, int len) +{ + char buf[17]; + int i; + + CHECK_FD; + + if (_use_debug(LEVEL_HEXDUMP)) { + fprintf (__debug_fd, "%s%s:\033[m %s(%d): %s: data=%p len=%d\n", + __debug_color, package, file, line, function, data, len); + for (i = 0; data != NULL && i < len; i++) { + if (i % 16 == 0) + fprintf(__debug_fd, "\033[30m%s:\033[m %04x: ", package, i); + fprintf(__debug_fd, "%02x ", (unsigned int)(unsigned char)data[i]); + buf[i % 16] = (data[i] >= 32 && data[i] <= 126) ? data[i] : '.'; + buf[i % 16 + 1] = '\0'; + if (i % 4 == 3) fprintf(__debug_fd, " "); + if (i % 16 == 15) fprintf(__debug_fd, "%s\n", buf); + } + if (i % 16 != 0) { + for (; i % 16 != 0; i++) + fprintf (__debug_fd, (i % 4 == 3) ? " " : " "); + fprintf(__debug_fd, "%s\n", buf); + } + } +} + +void +_hexdump_n (const char *package, const int n, const char* file, int line, + const char* function, const char* data, int len) +{ + char buf[17]; + int i; + + CHECK_FD; + + if (_use_debug(n)) { + fprintf (__debug_fd, "%s%s:\033[m %s(%d): %s: data=%p len=%d\n", + __debug_color, package, file, line, function, data, len); + for (i = 0; data != NULL && i < len; i++) { + if (i % 16 == 0) + fprintf(__debug_fd, "\033[30m%s:\033[m %04x: ", package, i); + fprintf(__debug_fd, "%02x ", (unsigned int)(unsigned char)data[i]); + buf[i % 16] = (data[i] >= 32 && data[i] <= 126) ? data[i] : '.'; + buf[i % 16 + 1] = '\0'; + if (i % 4 == 3) fprintf(__debug_fd, " "); + if (i % 16 == 15) fprintf(__debug_fd, "%s\n", buf); + } + if (i % 16 != 0) { + for (; i % 16 != 0; i++) + fprintf (__debug_fd, (i % 4 == 3) ? " " : " "); + fprintf(__debug_fd, "%s\n", buf); + } + } +} + + +void +_hexdump_text (const char *text, + const char *package, const char *file, int line, + const char *function, const char *data, int len) +{ + CHECK_FD; + + if (_use_debug(LEVEL_HEXDUMP)) { + fprintf(__debug_fd, "%s%s: %s(%d): %s: %s\033[m", __debug_color, + package, file, line, function, text); + _hexdump(package, file, line, function, data, len); + } +} + + + +void +_error(const char *package, const char *file, int line, + const char *function, int fatal, const char *format, ...) +{ + char foo[2048]; + va_list ap; + + CHECK_FD; + + va_start(ap, format); + + + vsnprintf(foo, sizeof(foo) - strlen(format) - 1, format, ap); + if (_use_debug(0)) + fprintf(__debug_fd, "\033[31m%s: %s(%d): %s: %s\033[m", + package, file, line, function, foo); + else + fprintf(__debug_fd, "%s: %s(%d): %s: %s", + package, file, line, function, foo); + fflush(__debug_fd); + + if (fatal) { + fprintf(__debug_fd, "\033[31mfatal error -- exit programm\033[m\n"); + exit(1); + } + + va_end(ap); +} + +void +_debug(const char *package, const char *file, int line, + const char *function, const char *format, ...) +{ + char foo[2048]; + va_list ap; + va_start(ap, format); + + CHECK_FD; + + vsnprintf(foo, sizeof(foo) - strlen(format) - 1, format, ap); + + if (_use_debug(0)) { + fprintf(__debug_fd, "%s%s: %s(%d): %s: %s\033[m", + ( __debug_color ? __debug_color : ""), + package, file, line, function, foo); + fflush(__debug_fd); + } + + va_end(ap); +} + +void +_debug_n(const char *package, const int n, const char *file, + int line, const char *function, const char *format, ...) +{ + char foo[2048]; + va_list ap; + va_start(ap, format); + + CHECK_FD; + + vsnprintf(foo, sizeof(foo) - strlen(format) - 1, format, ap); + + if (_use_debug(n)) { + fprintf(__debug_fd, "%s%s: %s(%d): %s: %s\033[m", + ( __debug_color ? __debug_color : ""), + package, file, line, function, foo); + fflush(__debug_fd); + } + + va_end(ap); +} + +void +_octetstr(const char *package, const char *file, int line, + const char *function, const uint8_t *str, + const unsigned int len, const char *what) +{ + CHECK_FD; + + if (_use_debug(LEVEL_HEXDUMP)) { + unsigned int i; + + fprintf(__debug_fd, "%s%s: %s(%d): %s: ", + package, file, function, line, (what?what:"")); + for (i = 0; i < len; i++) { + if (i < (len - 1)) + fprintf(__debug_fd, "%03d.", str [i]); + else + fprintf(__debug_fd, "%03d", str [i]); + } + } +} + +int +_use_debug(int level) +{ + if (__debug_level == -1) return 0; + + CHECK_FD; + + if (level <= __debug_level) { + return 1; + } + + return 0; +} + +/* end of debug.c */ + + + + + diff --git a/libmpio/src/debug.h b/libmpio/src/debug.h new file mode 100644 index 0000000..8f5ff7e --- /dev/null +++ b/libmpio/src/debug.h @@ -0,0 +1,110 @@ +/* + * debug.h + * + * Author: Dirk Meyer <dmeyer@tzi.de> + * Andreas Büsching <crunchy@tzi.de> + * + * $Id: debug.h,v 1.1 2003/04/23 08:34:14 crunchy Exp $ + */ + +#ifndef _MPIO_DEBUG_H_ +#define _MPIO_DEBUG_H_ + +// if DPACKAGE is not definied use PACKAGE or "unknown" + +#ifndef DPACKAGE + +#ifdef PACKAGE +#define DPACKAGE PACKAGE +#else +#define DPACKAGE unknown +#endif + +#endif + +#include <stdio.h> + +#ifdef sun +#include <sys/int_types.h> +#else +#include <stdint.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef PBOOL +#define PBOOL(x) (x)?"True":"False" +#endif + +#define UNUSED(x) (x = x) + +#define debugn(n,args...) \ + _debug_n(DPACKAGE, n, __FILE__, __LINE__, __FUNCTION__, args) + +#define debug(args...) \ + _debug(DPACKAGE, __FILE__, __LINE__, __FUNCTION__, args) + +#define debug_error(fatal,args...) \ + _error(DPACKAGE, __FILE__, __LINE__, __FUNCTION__, fatal, args) + +#define hexdump(data,len) \ + _hexdump(DPACKAGE, __FILE__, __LINE__, __FUNCTION__, data, len) + +#define hexdumpn(n,data,len) \ + _hexdump_n(DPACKAGE, n, __FILE__, __LINE__, __FUNCTION__, data, len) + +#define hexdump_text(text,data,len) \ + _hexdump_text(text, DPACKAGE, __FILE__, __LINE__, __FUNCTION__, data, len) + +#define octetstrdump(data,len) \ + _octetstr(DPACKAGE, __FILE__, __LINE__, __FUNCTION__, data, len) + +#define ipadr_dump(data,len,text) \ + _octetstr(DPACKAGE, __FILE__, __LINE__, __FUNCTION__, data, len, text) + +#define use_debug() \ + use_debug(DPACKAGE) + + +#define with_special_debug(what) \ + _use_debug(DPACKAGE, what) + +void debug_init(void); +int debug_file(char *filename); +int debug_level(int level); +int debug_level_get(void); + +void _debug(const char *package, const char* file, int line, + const char* function, const char *format, ...); + +void _debug_n(const char *package, const int n, const char* file, + int line, const char* function, const char *format, ...); + +void _hexdump (const char *package, const char* file, int line, + const char* function, const char* data, int len); + +void _hexdump_n (const char *package, const int n, const char* file, int line, + const char* function, const char* data, int len); + +void _hexdump_text (const char *text, + const char *package, const char* file, int line, + const char* function, const char* data, int len); + +void _error(const char *package, const char* file, int line, + const char* function, int fatal, const char *format, ...); + +void _octetstr(const char *package, const char* file, int line, + const char* function, const uint8_t *str, + const unsigned int len, const char *what); + +int _use_debug(int level); + +#ifdef __cplusplus +} +#endif + +#endif /* _MPIO_DEBUG_H_ */ + +/* end of debug.h */ diff --git a/libmpio/src/defs.h b/libmpio/src/defs.h new file mode 100644 index 0000000..f676e23 --- /dev/null +++ b/libmpio/src/defs.h @@ -0,0 +1,334 @@ +/* -*- linux-c -*- */ + +/* + * $Id: defs.h,v 1.1 2003/04/23 08:34:14 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. + * + * */ + +#ifndef _MPIO_DEFS_H_ +#define _MPIO_DEFS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned int DWORD; + +/* Memory selection */ +typedef enum { MPIO_INTERNAL_MEM = 0x01, + MPIO_EXTERNAL_MEM = 0x10 } mpio_mem_t; + +/* model type */ +typedef enum { MPIO_MODEL_DME = 0x00, + MPIO_MODEL_DMG = 0x01, + MPIO_MODEL_DMG_PLUS = 0x02, + MPIO_MODEL_DMB = 0x03, + MPIO_MODEL_DMB_PLUS = 0x04, + MPIO_MODEL_DMK = 0x05, + MPIO_MODEL_FD100 = 0x06, + MPIO_MODEL_FL100 = 0x07, + MPIO_MODEL_FY100 = 0x08, + MPIO_MODEL_UNKNOWN = 0x09 } mpio_model_t; + +/* USB commands */ +typedef enum { GET_VERSION = 0x01, + GET_BLOCK = 0x02, + PUT_SECTOR = 0x03, + DEL_BLOCK = 0x04, + GET_SECTOR = 0x06, + GET_SPARE_AREA = 0x07, + PUT_BLOCK = 0x08, + MODIFY_FIRMWARE = 0xa0 } mpio_cmd_t; + +/* file types on internal memory */ +/* found in the code of salmoon, are these needed? -mager */ +typedef enum { FTYPE_CHAN = 0x00, + FTYPE_MUSIC = 0x01, + FTYPE_CONF = 'C', + FTYPE_FONT = 'F', + FTYPE_OTHER = 'H', + FTYPE_MEMO = 'M', + FTYPE_WAV = 'V', + FTYPE_ENTRY = 'R', + FTYPE_DIR = 'D', + FTYPE_PLAIN = '-'} mpio_filetype_t; + +/* fixed filenames */ +#define MPIO_CONFIG_FILE "CONFIG.DAT" +#define MPIO_CHANNEL_FILE "FMCONFIG.DAT" +#define MPIO_MPIO_RECORD "MPIO RECORD" + +/* type of callback functions */ +typedef BYTE (*mpio_callback_t)(int, int) ; +typedef BYTE (*mpio_callback_init_t)(mpio_mem_t, int, int) ; + +/* zone lookup table */ +#define MPIO_ZONE_MAX 8 /* 8* 16MB = 128MB */ +#define MPIO_ZONE_PBLOCKS 1024 /* physical blocks per zone */ +#define MPIO_ZONE_LBLOCKS 1000 /* logical blocks per zone */ +typedef DWORD mpio_zonetable_t[MPIO_ZONE_MAX][MPIO_ZONE_PBLOCKS]; + +#define MPIO_BLOCK_FREE 0xffff +#define MPIO_BLOCK_DEFECT 0xffee +#define MPIO_BLOCK_CIS 0xaaaa +#define MPIO_BLOCK_NOT_FOUND 0xcccccccc + +/* filenames */ +#define MPIO_FILENAME_LEN 129 +typedef BYTE mpio_filename_t[MPIO_FILENAME_LEN]; + +#ifndef NULL +#define NULL 0 +#endif + +#define MPIO_DEVICE "/dev/usb/mpio" +#define MPIO_CHARSET "ISO-8859-15" + +#define MPIO_ID3_FORMAT "%p - %t" + +#define SECTOR_SIZE 0x200 +#define SECTOR_ECC 0x040 +#define SECTOR_TRANS (SECTOR_SIZE + SECTOR_ECC) + +#define BLOCK_SECTORS 0x20 /* 0x10 8MB Smartmedia :salmoon */ +#define BLOCK_SIZE (SECTOR_SIZE * BLOCK_SECTORS) +#define BLOCK_TRANS (BLOCK_SIZE + (SECTOR_ECC * BLOCK_SECTORS)) + +#define DIR_NUM 0x10 +#define DIR_SIZE (SECTOR_SIZE*DIR_NUM) +#define DIR_ENTRY_SIZE 0x20 + +#define SMALL_MEM 0x02 + +#define CMD_SIZE 0x40 + +#define INFO_LINE 129 + +/* error codes */ +typedef struct { + int id; + char *msg; +} mpio_error_t; + +#define MPIO_OK 0 +#define MPIO_ERR_FILE_NOT_FOUND -1 +#define MPIO_ERR_NOT_ENOUGH_SPACE -2 +#define MPIO_ERR_FILE_EXISTS -3 +#define MPIO_ERR_FAT_ERROR -4 +#define MPIO_ERR_READING_FILE -5 +#define MPIO_ERR_PERMISSION_DENIED -6 +#define MPIO_ERR_WRITING_FILE -7 +#define MPIO_ERR_DIR_TOO_LONG -8 +#define MPIO_ERR_DIR_NOT_FOUND -9 +#define MPIO_ERR_DIR_NOT_A_DIR -10 +#define MPIO_ERR_DIR_NAME_ERROR -11 +#define MPIO_ERR_DIR_NOT_EMPTY -12 +#define MPIO_ERR_DEVICE_NOT_READY -13 +#define MPIO_ERR_OUT_OF_MEMORY -14 +#define MPIO_ERR_INTERNAL -15 +/* internal errors, occur when UI has errors! */ +#define MPIO_ERR_INT_STRING_INVALID -101 + +/* get formatted information, about the MPIO player */ + +typedef struct { + BYTE firmware_id[INFO_LINE]; + BYTE firmware_version[INFO_LINE]; + BYTE firmware_date[INFO_LINE]; + + BYTE model[INFO_LINE]; + + BYTE mem_internal[INFO_LINE]; + BYTE mem_external[INFO_LINE]; + +} mpio_info_t; + +/* view of the MPIO firmware */ +typedef struct { + /* everything we get from GET_VERSION */ + BYTE id[12]; + BYTE major[3]; + BYTE minor[3]; + BYTE year[5]; + BYTE month[3]; + BYTE day[3]; +} mpio_firmware_t; + +/* */ +typedef struct { + DWORD NumCylinder; + DWORD NumHead; + DWORD NumSector; + DWORD SumSector; +} mpio_disk_phy_t; + +/* */ + +struct mpio_directory_tx { + BYTE name[INFO_LINE]; + BYTE dir[BLOCK_SIZE]; + + BYTE *dentry; + + struct mpio_directory_tx *prev; + struct mpio_directory_tx *next; + +}; +typedef struct mpio_directory_tx mpio_directory_t; + + +/* view of a SmartMedia(tm) card */ +typedef struct { + BYTE id; + BYTE manufacturer; + WORD size; /* MB */ + BYTE chips; /* this is the hack for + MPIO internal representation, because + there might be up to four chips involved */ + + /* only needed for external SmartMedia cards */ + mpio_disk_phy_t geo; + + BYTE cis[SECTOR_SIZE]; + BYTE mbr[SECTOR_SIZE]; /* Master Boot Record */ + BYTE pbr[SECTOR_SIZE]; /* Partition Boot Record */ + + int pbr_offset; /* sector offset for the PBR */ + int fat_offset; /* sector offset for the FAT */ + int dir_offset; + + /* these are needed for internal and external cards */ + int max_cluster; /* # of clusters actually available */ + int fat_size; /* # sectors for FAT */ + int fat_nums; /* # of FATs */ + BYTE * fat; /* *real FAT (like in block allocation :-) */ + + /* needed for directory support */ + mpio_directory_t *root; /* root directory */ + mpio_directory_t *cdir; /* current directory */ + + /* how many physical blocks are available + * for internal memory is this value equal to max_cluster + */ + int max_blocks; + BYTE * spare; + + /* lookup table for phys.<->log. block mapping */ + mpio_zonetable_t zonetable; + +} mpio_smartmedia_t; + +/* health status of a memory "card" */ +typedef struct { + WORD total; /* total blocks on "card" */ + WORD spare; /* (available spare blocks */ + WORD broken; /* broken blocks */ +} mpio_health_single_t; + +typedef struct { + BYTE num; /* number of chips or zones */ + /* internal: max 4 chips + * external: max 8 zones (128MB) -> max 8 */ + mpio_health_single_t data[8]; +} mpio_health_t; + +/* view of the MPIO-* */ +typedef struct { + BYTE version[CMD_SIZE]; + + int fd; + BYTE *charset; /* charset used for filename conversion */ + + BYTE id3; /* enable/disable ID3 rewriting support */ + BYTE id3_format[INFO_LINE]; + BYTE id3_temp[INFO_LINE]; + + mpio_firmware_t firmware; + + mpio_model_t model; + + mpio_smartmedia_t internal; + mpio_smartmedia_t external; +} mpio_t; + +typedef struct { + mpio_t *m; + BYTE mem; /* internal/external memory */ + + DWORD entry; /* number of FAT entry */ + + /* internal */ + BYTE i_index; /* file index of file to store */ + BYTE i_fat[16]; /* internal FAT entry */ + + /* external */ + DWORD e_sector; /* logical startsector of cluster */ + + /* mapping to HW (== block address) */ + DWORD hw_address; /* 3 bytes block addressing + 1 byte chip */ + +} mpio_fatentry_t; + + +/* these are copied from: + * http://www.linuxhq.com/kernel/v2.4/doc/filesystems/vfat.txt.html + * + */ + +typedef struct { // Short 8.3 names + unsigned char name[8]; // file name + unsigned char ext[3]; // file extension + unsigned char attr; // attribute byte + unsigned char lcase; // Case for base and extension + unsigned char ctime_ms; // Creation time, milliseconds + unsigned char ctime[2]; // Creation time + unsigned char cdate[2]; // Creation date + unsigned char adate[2]; // Last access date + unsigned char reserved[2]; // reserved values (ignored) + unsigned char time[2]; // time stamp + unsigned char date[2]; // date stamp + unsigned char start[2]; // starting cluster number + unsigned char size[4]; // size of the file +} mpio_dir_entry_t; + +typedef struct { // Up to 13 characters of a long name + unsigned char id; // sequence number for slot + unsigned char name0_4[10]; // first 5 characters in name + unsigned char attr; // attribute byte + unsigned char reserved; // always 0 + unsigned char alias_checksum; // checksum for 8.3 alias + unsigned char name5_10[12]; // 6 more characters in name + unsigned char start[2]; // starting cluster number + unsigned char name11_12[4]; // last 2 characters in name +} mpio_dir_slot_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _MPIO_DEFS_H_ */ + diff --git a/libmpio/src/directory.c b/libmpio/src/directory.c new file mode 100644 index 0000000..fe8464c --- /dev/null +++ b/libmpio/src/directory.c @@ -0,0 +1,1318 @@ +/* + * + * $Id: directory.c,v 1.1 2003/04/23 08:34:14 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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 <unistd.h> +#include <iconv.h> + +#include "debug.h" +#include "io.h" +#include "mpio.h" +#include "directory.h" +#include <sys/time.h> + +#define UNICODE "UNICODELITTLE" + +/* the following function is copied from the linux kernel v2.4.18 + * file:/usr/src/linux/fs/fat/misc.c + * it was written by Werner Almesberger and Igor Zhbanov + * and is believed to be GPL + */ + +/* Linear day numbers of the respective 1sts in non-leap years. */ + +static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 }; + /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */ + +/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ + +int date_dos2unix(unsigned short time,unsigned short date) +{ + int month,year,secs; + struct timezone sys_tz; + struct timeval tv; + + gettimeofday(&tv, &sys_tz); + + /* first subtract and mask after that... Otherwise, if + date == 0, bad things happen */ + month = ((date >> 5) - 1) & 15; + year = date >> 9; + secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* + ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && + month < 2 ? 1 : 0)+3653); + /* days since 1.1.70 plus 80's leap day */ + secs += sys_tz.tz_minuteswest*60; + return secs; +} + +/* + * charset for filename encoding/converting + */ +BYTE * +mpio_charset_get(mpio_t *m) +{ + return strdup(m->charset); +} + +BYTE +mpio_charset_set(mpio_t *m, BYTE *charset) +{ + iconv_t ic; + int r = 1; + + ic = iconv_open(UNICODE, charset); + if (ic < 0) + r=0; + iconv_close(ic); + + ic = iconv_open(charset, UNICODE); + if (ic < 0) + r=0; + iconv_close(ic); + + if (r) + { + debugn(2, "setting new charset to: \"%s\"\n", charset); + free(m->charset); + m->charset=strdup(charset); + } else { + debugn(2, "could not set charset to: \"%s\"\n", charset); + } + + return r; +} + +int +mpio_directory_init(mpio_t *m, mpio_mem_t mem, mpio_directory_t *dir, + WORD self, WORD parent) +{ + mpio_dir_entry_t *dentry; + + memset(dir->dir, 0, BLOCK_SIZE); + memset(dir->dir, 0x20, 11); + memset(dir->dir+0x20, 0x20, 11); + + dentry = (mpio_dir_entry_t *)dir->dir; + + strncpy(dentry->name, ". ", 8); + strncpy(dentry->ext, " ", 3); + dentry->start[0] = self & 0xff; + dentry->start[1] = self / 0x100; + dentry->attr = 0x10; + + dentry++; + strncpy(dentry->name, ".. ", 8); + strncpy(dentry->ext, " ", 3); + dentry->start[0] = parent & 0xff; + dentry->start[1] = parent / 0x100; + dentry->attr = 0x10; + + hexdumpn(2, dir->dir, 64); + + return 0; +} + + +int +mpio_directory_read(mpio_t *m, mpio_mem_t mem, mpio_directory_t *dir) +{ + mpio_fatentry_t *f = 0; + + f = mpio_dentry_get_startcluster(m, mem, dir->dentry); + + if (!f) + { + debug("something bad has happened here!"); + exit (-1); + } + + mpio_io_block_read(m, mem, f, dir->dir); + + hexdumpn(5, dir->dir, DIR_SIZE); + + return 0; +} + +BYTE +mpio_directory_is_empty(mpio_t *m, mpio_mem_t mem, mpio_directory_t *dir) +{ + mpio_dir_entry_t *dentry; + BYTE r; + + dentry = (mpio_dir_entry_t *)dir->dir; + dentry += 2; + + r = MPIO_OK; + if (dentry->name[0] != 0x00) + r = !r; + + return r; +} + + +int +mpio_directory_write(mpio_t *m, mpio_mem_t mem, mpio_directory_t *dir) +{ + mpio_fatentry_t *f = 0; + + f = mpio_dentry_get_startcluster(m, mem, dir->dentry); + if (!f) + { + debug("something bad has happened here!"); + exit (-1); + } + + if (mem==MPIO_INTERNAL_MEM) + { + f->i_fat[0x01]= f->i_index; + if (m->model >= MPIO_MODEL_FD100) + f->i_fat[0x0e] = f->i_index; + + /* only one block needed for directory */ + f->i_fat[0x02]=0; + f->i_fat[0x03]=1; + + /* set type to directory */ + f->i_fat[0x06] = FTYPE_ENTRY; + + hexdumpn(2, f->i_fat, 16); + } + + mpio_io_block_delete(m, mem, f); + mpio_io_block_write(m, mem, f, dir->dir); + + return 0; +} + +/* directory operations */ +BYTE * +mpio_directory_open(mpio_t *m, mpio_mem_t mem) +{ + BYTE *out; + if (mem == MPIO_EXTERNAL_MEM) { + if (m->external.id) { + out = m->external.cdir->dir; + } else { + return NULL; + } + } else { + out = m->internal.cdir->dir; + } + + if (out[0] == 0x00) + { + debugn(3, "directory is empty\n"); + return NULL; + } + + debugn(3, "first dentry: %08x\n", out); + + return out; +} + +int +mpio_directory_make(mpio_t *m, mpio_mem_t mem, BYTE *dir) +{ + mpio_smartmedia_t *sm; + mpio_directory_t *new; + mpio_fatentry_t *f, *current; + WORD self, parent; + struct tm tt; + time_t curr; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if ((strcmp(dir, "..") == 0) || + (strcmp(dir, ".") == 0)) + { + debugn(2, "directory name not allowed: %s\n", dir); + return MPIO_ERR_DIR_NAME_ERROR; + } + + /* find free sector */ + f = mpio_fatentry_find_free(m, mem, FTYPE_ENTRY); + if (!f) + { + debug("could not free cluster for file!\n"); + return (MPIO_ERR_FAT_ERROR); + } else { + self=f->entry; + } + + /* find file-id for internal memory */ + if (mem==MPIO_INTERNAL_MEM) + { + f->i_index=mpio_fat_internal_find_fileindex(m); + debugn(2, "fileindex: %02x\n", f->i_index); + f->i_fat[0x01]= f->i_index; + if (m->model >= MPIO_MODEL_FD100) + f->i_fat[0x0e] = f->i_index; + self = f->i_index; + + /* only one block needed for directory */ + f->i_fat[0x02]=0; + f->i_fat[0x03]=1; + hexdumpn(2, f->i_fat, 16); + } + + if (sm->cdir == sm->root) + { + parent=0; + } else { + current = mpio_dentry_get_startcluster(m, mem, sm->cdir->dentry); + if (mem==MPIO_INTERNAL_MEM) + { + parent = current->i_index; + } else { + parent = current->entry; + } + } + + + new = malloc(sizeof(mpio_directory_t)); + mpio_directory_init(m, mem, new, self, parent); + + mpio_fatentry_set_eof(m ,mem, f); + mpio_io_block_write(m, mem, f, new->dir); + time(&curr); + tt = * localtime(&curr); + mpio_dentry_put(m, mem, + dir, strlen(dir), + mktime(&tt), + 0, self, 0x10); + + free(new); + + return MPIO_OK; +} + +int +mpio_directory_cd(mpio_t *m, mpio_mem_t mem, BYTE *dir) +{ + mpio_smartmedia_t *sm; + BYTE *p; + BYTE month, day, hour, minute, type; + BYTE fname[100]; + WORD year; + DWORD fsize; + int i, size; + BYTE pwd[INFO_LINE]; + mpio_directory_t *old, *new; + + if (strcmp(dir, ".")==0) + return MPIO_OK; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if (strcmp(dir, "..") == 0) + { + if (sm->cdir->prev) + { + old = sm->cdir; + sm->cdir = sm->cdir->prev; + sm->cdir->next = NULL; + free(old); + } + + return MPIO_OK; + } + + mpio_directory_pwd(m, mem, pwd); + + if ((strlen(pwd) + strlen(dir) + 2) > INFO_LINE) + { + debugn(2, "directory name gets to long!\n"); + return MPIO_ERR_DIR_TOO_LONG; + } + + + p = mpio_dentry_find_name(m, mem, dir); + + /* second try */ + if (!p) + p = mpio_dentry_find_name_8_3(m, mem, dir); + + if (!p) + { + debugn(2, "could not find directory: %s\n", dir); + return MPIO_ERR_DIR_NOT_FOUND; + } + + mpio_dentry_get(m, mem, p, + fname, 100, + &year, &month, &day, + &hour, &minute, &fsize, + &type); + + if (type != FTYPE_DIR) + { + debugn(2, "this is not a directory: %s\n", dir); + return MPIO_ERR_DIR_NOT_A_DIR; + } + + new = malloc(sizeof(mpio_directory_t)); + strcpy(new->name, dir); + new->next = NULL; + new->prev = sm->cdir; + new->dentry = p; + sm->cdir->next = new; + sm->cdir = new; + + mpio_directory_pwd(m, mem, pwd); + + if (strcmp(dir, "/") != 0) + { + /* read new directory */ + size=mpio_directory_read(m, mem, sm->cdir); + } + + return MPIO_OK; + +} + + +void +mpio_directory_pwd(mpio_t *m, mpio_mem_t mem, BYTE pwd[INFO_LINE]) +{ + mpio_smartmedia_t *sm; + mpio_directory_t *d; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + d = sm->root->next; + pwd[0] = 0; + + if (!d) + strcat(pwd, "/"); + + while (d) + { + strcat(pwd, "/"); + debugn(2, "name: %s\n", d->name); + strcat(pwd, d->name); + d = d->next; + } + + return; +} + +mpio_dir_entry_t * +mpio_dentry_filename_write(mpio_t *m, mpio_mem_t mem, BYTE *p, + BYTE *filename, int filename_size) +{ + BYTE *unicode = 0; + BYTE *back, *fback; + BYTE *fname = 0; + iconv_t ic; + int in = 0, out = 0; + int fin = 0, fout = 0; + int count = 0; + BYTE index; + BYTE f_8_3[13]; + mpio_dir_slot_t *slot; + mpio_dir_entry_t *dentry; + int i, j, points; + + /* generate vfat filename in UNICODE */ + ic = iconv_open(UNICODE, m->charset); + fin = in = filename_size + 1; + fout = out = filename_size * 2 + 2 + 26; + fname = malloc(in); + fback = fname; + unicode = malloc(out); + back = unicode; + + memset(fname, 0, in); + snprintf(fname, in, "%s", filename); + memset(unicode, 0xff, out); + iconv(ic, (char **)&fback, &fin, (char **)&back, &fout); + iconv_close(ic); + hexdump(fname, in); + hexdump(unicode, out); + + back = unicode; + + count = filename_size / 13; + if (filename_size % 13) + count++; + + slot = (mpio_dir_slot_t *)p; + + index = 0x40 + count; + while (count > 0) { + mpio_dentry_copy_to_slot(back + ((count - 1) * 26), slot); + hexdump((char *)back + ((count - 1) * 26), 0x20); + slot->id = index; + slot->attr = 0x0f; + slot->reserved = 0x00; + slot->start[0] = 0x00; + slot->start[1] = 0x00; + /* FIXME: */ + slot->alias_checksum = 0x00; // checksum for 8.3 alias + + hexdump((char *)slot, 0x20); + + slot++; + count--; + index = count; + } + +/* memcpy(p, m->internal.dir+0x220, 0x20); */ + +/* p+=0x20; */ + dentry = (mpio_dir_entry_t *)slot; + + /* find uniq 8.3 filename */ + memset(f_8_3, 0x20, 12); + f_8_3[8]='.'; + f_8_3[12]=0x00; + + i=0; + points=0; + /* count points to later find the correct file extension */ + while (i<(strlen(filename))) + { + if (filename[i] == '.') + points++; + i++; + } + + /* if we do not find any points we set the value ridiculously high, + then everything falls into place */ + if (!points) + points=1024*1024; + + i=j=0; + while ((j<8) && (points) && (i<(strlen(filename)))) + { + if (filename[i] == '.') + { + points--; + } else { + if (filename[i]!=' ') { + f_8_3[j] = toupper(filename[i]); + j++; + } + } + i++; + } + + j=i; + while((points) && (j<(strlen(filename)))) + { + if (filename[j] == '.') + points--; + j++; + } + + i=9; + while ((i<12) && (j<(strlen(filename)))) + { + f_8_3[i] = toupper(filename[j]); + i++; + j++; + } + + /* This seems like a special case to me! */ + if (strcmp(MPIO_MPIO_RECORD, filename)==0) + { + f_8_3[6]='~'; + f_8_3[7]='0'; + } + + if (mpio_dentry_find_name_8_3(m, mem, f_8_3)) + { + f_8_3[6]='~'; + f_8_3[7]='1'; + } + + while(mpio_dentry_find_name_8_3(m, mem, f_8_3)) + f_8_3[7]++; + + +/* memcpy(dentry->name,"AAAAAAAA",8); */ +/* memcpy(dentry->ext,"MP3",3); */ + +/* hexdumpn(0, f_8_3, 13); */ + + memcpy(dentry->name, f_8_3, 8); + memcpy(dentry->ext, f_8_3+9, 3); + + free(unicode); + free(fname); + + return dentry; +} + + +int +mpio_dentry_get_size(mpio_t *m, mpio_mem_t mem, BYTE *buffer) +{ + mpio_dir_entry_t *dentry; + + if (!buffer) + return -1; + + UNUSED(m); + + dentry = (mpio_dir_entry_t *)buffer; + + if ((dentry->name[0] & 0x40) && + (dentry->attr == 0x0f) && + (dentry->start[0] == 0x00) && + (dentry->start[1] == 0x00)) { + dentry++; + while ((dentry->attr == 0x0f) && + (dentry->start[0] == 0x00) && + (dentry->start[1] == 0x00)) { + /* this/these are vfat slots */ + dentry++; + } + } + dentry++; + + return(((BYTE *)dentry) - buffer); +} + +BYTE* +mpio_dentry_next(mpio_t *m, mpio_mem_t mem, BYTE *buffer) +{ + int size; + BYTE *out; + + size = mpio_dentry_get_size(m, mem, buffer); + + if (size<=0) + return NULL; + + out = buffer + size; + + if (*out == 0x00) + { + debugn(3, "no more entries\n"); + return NULL; + } + + debugn(3, "next dentry: %08x\n", out); + + return out; +} + +int +mpio_dentry_get_raw(mpio_t *m, mpio_mem_t mem, BYTE *dentry, + BYTE *buffer, int bufsize) +{ + int size; + + size = mpio_dentry_get_size(m, mem, buffer); + debugn(3, "dentry size is: 0x%02x\n", size); + + if (size < 0) + return size; + + if (size > bufsize) + return -2; + + memcpy(buffer, dentry, size); + + return size; +} + +void +mpio_dentry_copy_from_slot(BYTE *buffer, mpio_dir_slot_t *slot) +{ + memcpy(buffer, slot->name0_4, 10); + memcpy(buffer + 10, slot->name5_10, 12); + memcpy(buffer + 22, slot->name11_12, 4); +} + +void +mpio_dentry_copy_to_slot(BYTE *buffer, mpio_dir_slot_t *slot) +{ + memcpy(slot->name0_4, buffer, 10); + memcpy(slot->name5_10, buffer + 10, 12); + memcpy(slot->name11_12, buffer + 22, 4); +} + +int +mpio_dentry_get(mpio_t *m, mpio_mem_t mem, BYTE *buffer, + BYTE *filename, int filename_size, + WORD *year, BYTE *month, BYTE *day, + BYTE *hour, BYTE *minute, DWORD *fsize, BYTE *type) +{ + BYTE filename_8_3[13]; + + return mpio_dentry_get_real(m, mem, buffer, filename, filename_size, + filename_8_3, + year, month, day, hour, minute, fsize, type); +} + +/* TODO: please clean me up !!! */ +int +mpio_dentry_get_real(mpio_t *m, mpio_mem_t mem, BYTE *buffer, + BYTE *filename, int filename_size, + BYTE *filename_8_3, + WORD *year, BYTE *month, BYTE *day, + BYTE *hour, BYTE *minute, DWORD *fsize, + BYTE *type) +{ + int date, time; + int vfat = 0; + int num_slots = 0; + int slots = 0; + int in = 0, out = 0, iconv_return; + mpio_dir_entry_t *dentry; + mpio_dir_slot_t *slot; + BYTE *unicode = 0; + BYTE *uc; + BYTE *fname = 0; + iconv_t ic; + int dsize, i; + + if (buffer == NULL) + return -1; + + dentry = (mpio_dir_entry_t *)buffer; + + if ((dentry->name[0] & 0x40) && + (dentry->attr == 0x0f) && + (dentry->start[0] == 0x00) && + (dentry->start[1] == 0x00)) + { + dsize = mpio_dentry_get_size(m, mem, buffer); + debugn(3, "dentry size is: 0x%02x\n", dsize); + hexdump(buffer, dsize); + num_slots = (dsize / 0x20) - 1; + slots = num_slots - 1; + dentry++; + vfat++; + in = num_slots * 26; + out = num_slots * 13; + unicode = malloc(in + 2); + memset(unicode, 0x00, (in+2)); + uc = unicode; + fname = filename; + slot = (mpio_dir_slot_t *)buffer; + mpio_dentry_copy_from_slot(unicode + (26 * slots), slot); + slots--; + + while ((dentry->attr == 0x0f) && + (dentry->start[0] == 0x00) && + (dentry->start[1] == 0x00)) + { + /* this/these are vfat slots */ + slot = (mpio_dir_slot_t *)dentry; + mpio_dentry_copy_from_slot((unicode + (26 * slots)), slot); + dentry++; + slots--; + } + } + + if (vfat) + { + ic = iconv_open(m->charset, UNICODE); + memset(fname, 0, filename_size); + hexdumpn(4, unicode, in+2); + debugn(4, "before iconv: in: %2d - out: %2d\n", in, out); + iconv_return = iconv(ic, (char **)&uc, &in, (char **)&fname, &out); + debugn(4, "after iconv: in: %2d - out: %2d (return: %d)\n", in, out, + iconv_return); + hexdumpn(4, filename, (num_slots*13)-out); + iconv_close(ic); + } + free(unicode); + + memcpy(filename_8_3, dentry->name, 8); + i=8; + while(filename_8_3[i-1]==' ') + i--; + filename_8_3[i++] = '.'; + memcpy(filename_8_3 + i, dentry->ext, 3); + i+=3; + while(filename_8_3[i-1]==' ') + i--; + filename_8_3[i] = 0; + hexdumpn(4, filename_8_3, 13); + + if (!vfat) + { + if (filename_size >= 12) + { + snprintf(filename, 13, "%s", filename_8_3); + /* UGLY !! */ + if (((strncmp(dentry->name, ". ", 8)==0) && + (strncmp(dentry->ext, " ", 3) == 0))) + filename[1]=0; + if (((strncmp(dentry->name, ".. ", 8)==0) && + (strncmp(dentry->ext, " ", 3) == 0))) + filename[2]=0; + } else { + snprintf(filename, filename_size, "%s", "ERROR"); + } + } + + date = (dentry->date[1] * 0x100) + dentry->date[0]; + *year = date / 512 + 1980; + *month = (date / 32) & 0xf; + *day = date & 0x1f; + + time = (dentry->time[1] * 0x100) + dentry->time[0]; + *hour = time / 2048; + *minute= (time / 32) & 0x3f; + + *fsize = dentry->size[3]; + *fsize *= 0x100; + *fsize += dentry->size[2]; + *fsize *= 0x100; + *fsize += dentry->size[1]; + *fsize *= 0x100; + *fsize += dentry->size[0]; + + if (dentry->attr & 0x10) { + /* is this a directory? */ + *type = FTYPE_DIR; + } else { + *type = FTYPE_PLAIN; + } + + return(((BYTE *)dentry) - buffer); +} + +/* read "size" sectors of fat into the provided buffer */ +int +mpio_rootdir_read (mpio_t *m, mpio_mem_t mem) +{ + mpio_smartmedia_t *sm; + BYTE recvbuff[SECTOR_SIZE]; + int i; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + for (i = 0; i < DIR_NUM; i++) { + if (mpio_io_sector_read(m, mem, (sm->dir_offset + i), recvbuff)) + return 1; + + memcpy(sm->root->dir + (i * SECTOR_SIZE), recvbuff, SECTOR_SIZE); + } + + return (0); +} + +int +mpio_rootdir_clear (mpio_t *m, mpio_mem_t mem) +{ + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) sm=&m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm=&m->external; + + memset(sm->root->dir, 0x00, DIR_SIZE); + + return 0; +} + +BYTE +mpio_dentry_is_dir(mpio_t *m, mpio_mem_t mem, BYTE *p) +{ + int s; + mpio_dir_entry_t *dentry; + BYTE r; + + s = mpio_dentry_get_size(m, mem, p); + s -= DIR_ENTRY_SIZE ; + + dentry = (mpio_dir_entry_t *)p; + + while (s != 0) { + dentry++; + s -= DIR_ENTRY_SIZE ; + } + + if (dentry->attr & 0x10) { + r = MPIO_OK; + } else { + r= !MPIO_OK; + } + + return r; +} + +int +mpio_dentry_get_filesize(mpio_t *m, mpio_mem_t mem, BYTE *p) +{ + int s; + int fsize; + mpio_dir_entry_t *dentry; + + s = mpio_dentry_get_size(m, mem, p); + s -= DIR_ENTRY_SIZE ; + + dentry = (mpio_dir_entry_t *)p; + + while (s != 0) { + dentry++; + s -= DIR_ENTRY_SIZE ; + } + + if (dentry->attr & 0x10) { + fsize = BLOCK_SIZE; + } else { + fsize = dentry->size[3]; + fsize *= 0x100; + fsize += dentry->size[2]; + fsize *= 0x100; + fsize += dentry->size[1]; + fsize *= 0x100; + fsize += dentry->size[0]; + } + + return fsize; +} + +long +mpio_dentry_get_time(mpio_t *m, mpio_mem_t mem, BYTE *p) +{ + int s; + mpio_dir_entry_t *dentry; + + s = mpio_dentry_get_size(m, mem, p); + s -= DIR_ENTRY_SIZE ; + + dentry = (mpio_dir_entry_t *)p; + + while (s != 0) { + dentry++; + s -= DIR_ENTRY_SIZE ; + } + + + return date_dos2unix((dentry->time[0]+dentry->time[1]*0x100), + (dentry->date[0]+dentry->date[1]*0x100)); +} + + + +mpio_fatentry_t * +mpio_dentry_get_startcluster(mpio_t *m, mpio_mem_t mem, BYTE *p) +{ + int s; + DWORD cluster; + BYTE i_index; + mpio_dir_slot_t *dentry; + mpio_fatentry_t *new; + + s = mpio_dentry_get_size(m, mem, p); + s -= DIR_ENTRY_SIZE ; + + dentry = (mpio_dir_slot_t *)p; + + while (s != 0) { + dentry++; + s -= DIR_ENTRY_SIZE ; + } + + cluster = dentry->start[1] * 0x100 + dentry->start[0]; + + if (mem == MPIO_INTERNAL_MEM) + { + i_index=dentry->start[0]; + cluster = mpio_fat_internal_find_startsector(m, cluster); + } + if (cluster < 0) + return NULL; + + new = mpio_fatentry_new(m, mem, cluster, FTYPE_MUSIC); + + if (mem == MPIO_INTERNAL_MEM) + { + new->entry=cluster; + new->i_index=i_index; + mpio_fatentry_entry2hw(m, new); + } + + debugn(2,"i_index=0x%02x\n", new->i_index); + + return new; +} + +int +mpio_dentry_put(mpio_t *m, mpio_mem_t mem, + BYTE *filename, int filename_size, + time_t date, DWORD fsize, WORD ssector, BYTE attr) +{ + BYTE *p; + mpio_dir_entry_t *dentry; + + /* read and copied code from mtools-3.9.8/directory.c + * to make this one right + */ + struct tm *now; + time_t date2 = date; + unsigned char hour, min_hi, min_low, sec; + unsigned char year, month_hi, month_low, day; + + + p = mpio_directory_open(m, mem); + if (p) { + while (*p != 0x00) + p += 0x20; + } else { + if (mem == MPIO_EXTERNAL_MEM) + p = m->external.cdir->dir; + if (mem == MPIO_INTERNAL_MEM) + p = m->internal.cdir->dir; + } + + dentry = mpio_dentry_filename_write(m, mem, p, filename, filename_size); + + dentry->attr = attr; + dentry->lcase = 0x00; + + /* read and copied code from mtools-3.9.8/directory.c + * to make this one right + */ + now = localtime(&date2); + dentry->ctime_ms = 0; + hour = now->tm_hour << 3; + min_hi = now->tm_min >> 3; + min_low = now->tm_min << 5; + sec = now->tm_sec / 2; + dentry->ctime[1] = dentry->time[1] = hour + min_hi; + dentry->ctime[0] = dentry->time[0] = min_low + sec; + year = (now->tm_year - 80) << 1; + month_hi = (now->tm_mon + 1) >> 3; + month_low = (now->tm_mon + 1) << 5; + day = now->tm_mday; + dentry -> adate[1] = dentry->cdate[1] = dentry->date[1] = year + month_hi; + dentry -> adate[0] = dentry->cdate[0] = dentry->date[0] = month_low + day; + + dentry->size[0] = fsize & 0xff; + dentry->size[1] = (fsize / 0x100) & 0xff; + dentry->size[2] = (fsize / 0x10000) & 0xff; + dentry->size[3] = (fsize / 0x1000000) & 0xff; + dentry->start[0] = ssector & 0xff; + dentry->start[1] = ssector / 0x100; + + /* what do we want to return? */ + return 0; +} + +BYTE * +mpio_dentry_find_name_8_3(mpio_t *m, BYTE mem, BYTE *filename) +{ + BYTE *p; + BYTE bdummy; + WORD wdummy; + BYTE fname[129]; + BYTE fname_8_3[13]; + DWORD ddummy; + BYTE *found = 0; + int i, j, len; + + p = mpio_directory_open(m, mem); + while ((p) && (!found)) { + mpio_dentry_get_real (m, mem, p, + fname, 128, + fname_8_3, + &wdummy, &bdummy, &bdummy, + &bdummy, &bdummy, &ddummy, &bdummy); + if ((strcmp(fname_8_3, filename) == 0) && + (strcmp(filename,fname_8_3) == 0)) { + found = p; + p = NULL; + } + + p = mpio_dentry_next(m, mem, p); + } + + return found; +} + +BYTE * +mpio_dentry_find_name(mpio_t *m, BYTE mem, BYTE *filename) +{ + BYTE *p; + BYTE bdummy; + WORD wdummy; + BYTE fname[129]; + DWORD ddummy; + BYTE *found = 0; + + p = mpio_directory_open(m, mem); + while ((p) && (!found)) { + mpio_dentry_get (m, mem, p, + fname, 128, + &wdummy, &bdummy, &bdummy, + &bdummy, &bdummy, &ddummy, &bdummy); + if ((strcmp(fname,filename) == 0) && (strcmp(filename,fname) == 0)) { + found = p; + p = NULL; + } + + p = mpio_dentry_next(m, mem, p); + } + + return found; +} + + +int +mpio_dentry_delete(mpio_t *m, BYTE mem, BYTE *filename) +{ + mpio_smartmedia_t *sm; + BYTE *start; + int size; + BYTE tmp[DIR_SIZE]; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + start = mpio_dentry_find_name(m, mem, filename); + + /* second try */ + if (!start) + start = mpio_dentry_find_name_8_3(m, mem, filename); + + if (!start) { + debugn(2, "could not find file: %s\n", filename); + return 0; + } + + size = mpio_dentry_get_size(m, mem, start); + + if (size <= 0) { + debug("fatal error in mpio_dentry_delete\n"); + return 0; + } + + debugn(5, "size: %2x\n", size); + + /* clear new buffer */ + memset(tmp, 0, DIR_SIZE); + /* copy before delete */ + if (start != sm->cdir->dir) + memcpy(tmp, sm->cdir->dir, (start - (sm->cdir->dir))); + /* copy after delete */ + memcpy(tmp + (start - (sm->cdir->dir)), (start + size), + (sm->cdir->dir + DIR_SIZE - (start + size))); + + memcpy(sm->cdir->dir, tmp, DIR_SIZE); + + return 0; +} + +void +mpio_dentry_move(mpio_t *m,mpio_mem_t mem,BYTE *m_file,BYTE *a_file) { + mpio_smartmedia_t *sm; + + BYTE *t0,*t1,*t2,*t3; + + int s0,s1,s2,s3; + int m_file_s,a_file_s; + BYTE tmp[DIR_SIZE]; + BYTE *b_file; + + if (mem == MPIO_INTERNAL_MEM) + sm = &m->internal; + + if (mem == MPIO_EXTERNAL_MEM) + sm = &m->external; + + if (m_file == a_file) + return; + + m_file_s = mpio_dentry_get_size(m, mem, m_file); + a_file_s = mpio_dentry_get_size(m, mem, a_file); + + // -- we determine the 'befor' file. The start of the region which needs to be moved down + // -- if a_file == NULL this is the start of the directory. + + if(a_file==NULL) { + b_file = sm->cdir->dir; + } else { + b_file = a_file + a_file_s; + } + + if(b_file == m_file) { + return; + } + + /** We disect the whole directory in four pieces. + in different ways according to the direction + the directoy entry is moved (up or down). + */ + + if(m_file > b_file) { + fprintf(stderr,"U "); + t0 = sm->cdir->dir; + s0 = b_file - sm->cdir->dir; + + t1 = m_file; + s1 = m_file_s; + + t2 = b_file; + s2 = m_file - b_file; + + t3 = m_file + m_file_s; + s3 = DIR_SIZE - (m_file-sm->cdir->dir) - m_file_s; + } else { + fprintf(stderr,"D "); + t0 = sm->cdir->dir; + s0 = m_file - sm->cdir->dir; + + t1 = m_file + m_file_s; + s1 = a_file + a_file_s - (m_file + m_file_s); + + t2 = m_file; + s2 = m_file_s; + + t3 = b_file; + s3 = DIR_SIZE - (b_file - sm->cdir->dir); + } + + if(s0) { + memcpy(tmp,t0,s0); + } + + if(s1) { + memcpy(tmp + s0 , t1 , s1 ); + } + + if(s2) { + memcpy(tmp + s0 + s1, t2, s2); + } + + if(s3) { + memcpy(tmp + s0 + s1 + s2, t3, s3); + } + + fprintf(stderr," -- t0=%ld, s0=%d, t1=%ld, s1=%d, t2=%ld, s2=%d, t3=%ld, s3=%d; sum=%d, DIRSIZE=%d\n", + (long)t0,s0,(long)t1,s1,(long)t2,s2,(long)t3,s3,s0+s1+s2+s3,DIR_SIZE); + + memcpy(sm->cdir->dir, tmp, DIR_SIZE); +} + +void +mpio_dentry_switch(mpio_t *m, mpio_mem_t mem, BYTE *file1, BYTE *file2) +{ + mpio_smartmedia_t *sm; + BYTE *p1, *p2; + BYTE *current; + int size1 , size2; + BYTE tmp[DIR_SIZE]; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if (file1 == file2) + return; + + if (file1<file2) + { + p1 = file1; + p2 = file2; + } else { + p1 = file2; + p2 = file1; + } + size1 = mpio_dentry_get_size(m, mem, p1); + size2 = mpio_dentry_get_size(m, mem, p2); + + current = tmp; + memset(tmp, 0xff, DIR_SIZE); + /* before the first file */ + if (p1 != sm->cdir->dir) + { + memcpy(current, sm->cdir->dir, p1 - sm->cdir->dir); + current += (p1 - sm->cdir->dir); + } + /* the second file*/ + memcpy(current, p2, size2); + current += size2; + /* between the files */ + memcpy(current, p1+size1, (p2-p1-size1)); + current += (p2-p1-size1); + /* the first file */ + memcpy(current, p1, size1); + current += size1; + /* and the rest */ + memcpy(current, p2+size2, (sm->cdir->dir+DIR_SIZE-p2-size2)); + + /* really update the directory */ + memcpy(sm->cdir->dir, tmp, DIR_SIZE); + + return; +} + +void +mpio_dentry_rename(mpio_t *m, mpio_mem_t mem, BYTE *p, BYTE *newfilename) +{ + mpio_smartmedia_t *sm; + BYTE *current; + int size1 , size2, offset, offset_d1, offset_d2; + BYTE tmp[DIR_SIZE]; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + current = sm->cdir->dir; + + size1 = mpio_dentry_get_size(m, mem, p) / 0x20; + size2 = (strlen(newfilename) / 13) + 1; + if ((strlen(newfilename) % 13)) + size2++; + + debugn(2, "size1: %d size2: %d\n", size1, size2); + + /* we want to copy the last dentry to the right location + * so we avoid reading and writing the same information + */ + size1--; /* kludge so we can do compares without worry */ + size2--; + + memcpy(tmp, current, DIR_SIZE); + offset = p - current; + offset_d1 = offset + (size1 * 0x20); + offset_d2 = offset + (size2 * 0x20); + + if (size2>size1) { + /* new filename needs at least one slot more than the old one */ + memcpy(current+offset_d2, tmp+offset_d1, (DIR_SIZE-offset_d1)); + } + + if (size2<size1) { + /* new filename needs at least one slot less than the old one */ + memset(p+offset, 0, (DIR_SIZE-offset)); /* clear to avoid bogus dentries */ + memcpy(current+offset_d2, tmp+offset_d1, (DIR_SIZE-offset_d2)); + } + + mpio_dentry_filename_write(m, mem, p, newfilename, strlen(newfilename)); + + return ; +} diff --git a/libmpio/src/directory.h b/libmpio/src/directory.h new file mode 100644 index 0000000..4edcdb5 --- /dev/null +++ b/libmpio/src/directory.h @@ -0,0 +1,84 @@ +/* + * + * $Id: directory.h,v 1.1 2003/04/23 08:34:14 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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. + * + * */ + +#ifndef _MPIO_DIRECTORY_H_ +#define _MPIO_DIRECTORY_H_ + +#include "fat.h" +#include "time.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* root directory operations */ +int mpio_rootdir_read (mpio_t *, mpio_mem_t); +int mpio_rootdir_clear (mpio_t *, mpio_mem_t); +int mpio_rootdir_format(mpio_t *, mpio_mem_t); + +/* directory opertations */ +int mpio_directory_init(mpio_t *, mpio_mem_t, mpio_directory_t *, + WORD, WORD); +int mpio_directory_read(mpio_t *, mpio_mem_t, mpio_directory_t *); +int mpio_directory_write(mpio_t *, mpio_mem_t, mpio_directory_t *); +BYTE mpio_directory_is_empty(mpio_t *, mpio_mem_t, mpio_directory_t *); + +/* operations on a single directory entry */ +int mpio_dentry_get_size(mpio_t *, mpio_mem_t, BYTE *); +int mpio_dentry_get_raw(mpio_t *, mpio_mem_t, BYTE *, BYTE *, int); +int mpio_dentry_put(mpio_t *, mpio_mem_t, BYTE *, int, + time_t, DWORD, WORD, BYTE); +BYTE * mpio_dentry_find_name_8_3(mpio_t *, BYTE, BYTE *); +BYTE * mpio_dentry_find_name(mpio_t *, BYTE, BYTE *); +int mpio_dentry_delete(mpio_t *, BYTE, BYTE *); +int mpio_dentry_get_filesize(mpio_t *, mpio_mem_t, BYTE *); +long mpio_dentry_get_time(mpio_t *, mpio_mem_t, BYTE *); +mpio_fatentry_t *mpio_dentry_get_startcluster(mpio_t *, mpio_mem_t, BYTE *); +BYTE mpio_dentry_is_dir(mpio_t *, mpio_mem_t, BYTE *); + +/* switch two directory entries */ +void mpio_dentry_switch(mpio_t *, mpio_mem_t, BYTE *, BYTE *); + +/* rename a dentry */ +void mpio_dentry_rename(mpio_t *, mpio_mem_t, BYTE *, BYTE *); + +/* Move a given file to a new position in the file + list relative to another file. +*/ +void mpio_dentry_move(mpio_t *,mpio_mem_t, BYTE *, BYTE *); + +/* helper functions */ +void mpio_dentry_copy_from_slot(BYTE *, mpio_dir_slot_t *); +void mpio_dentry_copy_to_slot(BYTE *, mpio_dir_slot_t *); +int mpio_dentry_get_real(mpio_t *, mpio_mem_t, BYTE *, BYTE *, + int, BYTE[12], + WORD *, BYTE *, BYTE *, BYTE *, BYTE *, DWORD *, + BYTE *); + +#ifdef __cplusplus +} +#endif + +#endif /* _MPIO_DIRECTORY_H_ */ diff --git a/libmpio/src/ecc.c b/libmpio/src/ecc.c new file mode 100644 index 0000000..95bdafd --- /dev/null +++ b/libmpio/src/ecc.c @@ -0,0 +1,247 @@ +/* + * + * $Id: ecc.c,v 1.1 2003/04/23 08:34:14 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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 "ecc.h" +#include "debug.h" + +BYTE get_bit(BYTE, int); + +/* TODO: fix correctable errors */ + +inline BYTE +get_bit(BYTE d, int offset) +{ + return ((d >> offset) & 0x01 ); +} + +int +mpio_ecc_256_gen(BYTE *data, BYTE *ecc) +{ + BYTE p1, p1_; + BYTE p2, p2_; + BYTE p4, p4_; + + BYTE p08, p08_; + BYTE p16, p16_; + BYTE p32, p32_; + BYTE p64, p64_; + + BYTE p0128, p0128_; + BYTE p0256, p0256_; + BYTE p0512, p0512_; + BYTE p1024, p1024_; + + int i, j; + + /* init */ + p1=p1_=0; + p2=p2_=0; + p4=p4_=0; + + p08=p08_=0; + p16=p16_=0; + p32=p32_=0; + p64=p64_=0; + + p0128=p0128_=0; + p0256=p0256_=0; + p0512=p0512_=0; + p1024=p1024_=0; + + /* vertical */ + for (i=0; i<256; i++) { + + /* p1, p1_ */ + p1 ^= (get_bit(data[i], 7) ^ + get_bit(data[i], 5) ^ + get_bit(data[i], 3) ^ + get_bit(data[i], 1)); + p1_^= (get_bit(data[i], 6) ^ + get_bit(data[i], 4) ^ + get_bit(data[i], 2) ^ + get_bit(data[i], 0)); + + /* p2, p2_ */ + p2 ^= (get_bit(data[i], 7) ^ + get_bit(data[i], 6) ^ + get_bit(data[i], 3) ^ + get_bit(data[i], 2)); + p2_^= (get_bit(data[i], 5) ^ + get_bit(data[i], 4) ^ + get_bit(data[i], 1) ^ + get_bit(data[i], 0)); + + /* p4, p4_ */ + p4 ^= (get_bit(data[i], 7) ^ + get_bit(data[i], 6) ^ + get_bit(data[i], 5) ^ + get_bit(data[i], 4)); + p4_^= (get_bit(data[i], 3) ^ + get_bit(data[i], 2) ^ + get_bit(data[i], 1) ^ + get_bit(data[i], 0)); + } + + /* horizontal */ + for (i=0; i<8; i++) { + + for (j=0; j<256; j++) { + + /* p08, p08_ */ + if ((j & 0x01) == 0) + p08_^= get_bit(data[j], i); + if ((j & 0x01) == 1) + p08 ^= get_bit(data[j], i); + + /* p16, p16_ */ + if (((j/2) & 0x01) == 0) + p16_^= get_bit(data[j], i); + if (((j/2) & 0x01) == 1) + p16^= get_bit(data[j], i); + + /* p32, p32_ */ + if (((j/4) & 0x01) == 0) + p32_^= get_bit(data[j], i); + if (((j/4) & 0x01) == 1) + p32^= get_bit(data[j], i); + + /* p64, p64_ */ + if (((j/8) & 0x01) == 0) + p64_^= get_bit(data[j], i); + if (((j/8) & 0x01) == 1) + p64^= get_bit(data[j], i); + + + /* p0128, p0128_ */ + if (((j/16) & 0x01) == 0) + p0128_^= get_bit(data[j], i); + if (((j/16) & 0x01) == 1) + p0128 ^= get_bit(data[j], i); + + /* p0256, p0256_ */ + if (((j/32) & 0x01) == 0) + p0256_^= get_bit(data[j], i); + if (((j/32) & 0x01) == 1) + p0256^= get_bit(data[j], i); + + /* p0512, p0512_ */ + if (((j/64) & 0x01) == 0) + p0512_^= get_bit(data[j], i); + if (((j/64) & 0x01) == 1) + p0512^= get_bit(data[j], i); + + /* p1024, p1024_ */ + if (((j/128) & 0x01) == 0) + p1024_^= get_bit(data[j], i); + if (((j/128) & 0x01) == 1) + p1024^= get_bit(data[j], i); + + } + } + + ecc[0]=~((p64 << 7) | (p64_ << 6) | + (p32 << 5) | (p32_ << 4) | + (p16 << 3) | (p16_ << 2) | + (p08 << 1) | (p08_ << 0)); + + ecc[1]=~((p1024 << 7) | (p1024_ << 6) | + (p0512 << 5) | (p0512_ << 4) | + (p0256 << 3) | (p0256_ << 2) | + (p0128 << 1) | (p0128_ << 0)); + + ecc[2]=~((p4 << 7) | (p4_ << 6) | + (p2 << 5) | (p2_ << 4) | + (p1 << 3) | (p1_ << 2)); + + return 0; +} + + +int +mpio_ecc_256_check(BYTE *data, BYTE *ecc) +{ + BYTE own_ecc[3]; + BYTE check[3]; + BYTE c; + BYTE line, col; + + int v, i; + + mpio_ecc_256_gen(data, own_ecc); + if ((own_ecc[0]^ecc[0])| + (own_ecc[1]^ecc[1])| + (own_ecc[2]^ecc[2])) { + debugn(2, "ECC %2x %2x %2x vs. %2x %2x %2x\n", + ecc[0], ecc[1], ecc[2], own_ecc[0], own_ecc[1], own_ecc[2]); + check[0] = (ecc[0] ^ own_ecc[0]); + check[1] = (ecc[1] ^ own_ecc[1]); + check[2] = (ecc[2] ^ own_ecc[2]); + + v=1; + for(i=0; i<4; i++) + { + if (!((get_bit(check[1], i*2) ^ + (get_bit(check[1], i*2+1))))) + v=0; + if (!((get_bit(check[0], i*2) ^ + (get_bit(check[0], i*2+1))))) + v=0; + } + for(i=1; i<4; i++) + { + if (!((get_bit(check[2], i*2) ^ + (get_bit(check[2], i*2+1))))) + v=0; + } + + if (v) { + debug("correctable error detected ... fixing the bit\n"); + line = get_bit(check[1], 7) * 128 + + get_bit(check[1], 5) * 64 + + get_bit(check[1], 3) * 32 + + get_bit(check[1], 1) * 16 + + get_bit(check[0], 7) * 8 + + get_bit(check[0], 5) * 4 + + get_bit(check[0], 3) * 2 + + get_bit(check[0], 1); + col = get_bit(check[2], 7) * 4 + + get_bit(check[2], 5) * 2 + + get_bit(check[2], 3); + debug ("error in line: %d , col %d\n", line, col); + debug ("defect byte is: %02x\n", data[line]); + data[line] ^= ( 1 << col); + debug ("fixed byte is: %02x\n", data[line]); + } else { + debug("uncorrectable error detected. Sorry you lose!\n"); + return 1; + } + } + + return 0; +} + + + + diff --git a/libmpio/src/ecc.h b/libmpio/src/ecc.h new file mode 100644 index 0000000..55ca297 --- /dev/null +++ b/libmpio/src/ecc.h @@ -0,0 +1,44 @@ +/* + * + * $Id: ecc.h,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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. + * + * */ + +#ifndef _MPIO_ECC_H_ +#define _MPIO_ECC_H_ + +#include "defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 256 Bytes Data, 3 Byte ECC to generate */ +int mpio_ecc_256_gen(BYTE *, BYTE *); +/* 256 Bytes Data, 3 Bytes ECC to check and possibly correct */ +int mpio_ecc_256_check(BYTE *, BYTE*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmpio/src/fat.c b/libmpio/src/fat.c new file mode 100644 index 0000000..27974cd --- /dev/null +++ b/libmpio/src/fat.c @@ -0,0 +1,1039 @@ +/* + * + * $Id: fat.c,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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 "fat.h" +#include "io.h" +#include "debug.h" + +#include <string.h> +#include <stdlib.h> + +/* I'm lazy so I hard code all the values */ + +BYTE mpio_part_016[0x10] = { + 0x80, 0x02, 0x0a, 0x00, 0x01, 0x03, 0x50, 0xf3, + 0x29, 0x00, 0x00, 0x00, 0xd7, 0x7c, 0x00, 0x00 +}; +BYTE mpio_part_032[0x10] = { + 0x80, 0x02, 0x04, 0x00, 0x01, 0x07, 0x50, 0xf3, + 0x23, 0x00, 0x00, 0x00, 0xdd, 0xf9, 0x00, 0x00 +}; +BYTE mpio_part_064[0x10] = { + 0x80, 0x01, 0x18, 0x00, 0x01, 0x07, 0x60, 0xf3, + 0x37, 0x00, 0x00, 0x00, 0xc9, 0xf3, 0x01, 0x00 +}; +BYTE mpio_part_128[0x10] = { + 0x80, 0x01, 0x10, 0x00, 0x06, 0x0f, 0x60, 0xf3, + 0x2f, 0x00, 0x00, 0x00, 0xd1, 0xe7, 0x03, 0x00 +}; + +/* ------------------------- */ + +BYTE mpio_pbr_head[0x10] = { + 0xe9, 0x00, 0x00, 0x4d, 0x53, 0x44, 0x4f, 0x53, + 0x35, 0x2e, 0x30, 0x00, 0x02, 0x20, 0x01, 0x00 +}; +BYTE mpio_pbr_016[0x13] = { + 0x02, 0x00, 0x01, 0xd7, 0x7c, 0xf8, 0x03, 0x00, + 0x10, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 +}; +BYTE mpio_pbr_032[0x13] = { + 0x02, 0x00, 0x01, 0xdd, 0xf9, 0xf8, 0x06, 0x00, + 0x10, 0x00, 0x08, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 +}; +BYTE mpio_pbr_064[0x13] = { + 0x02, 0x00, 0x01, 0x00, 0x00, 0xf8, 0x0c, 0x00, + 0x20, 0x00, 0x08, 0x00, 0x37, 0x00, 0x00, 0x00, + 0xc9, 0xf3, 0x01 +}; +BYTE mpio_pbr_128[0x13] = { + 0x02, 0x00, 0x01, 0x00, 0x00, 0xf8, 0x20, 0x00, + 0x20, 0x00, 0x10, 0x00, 0x2f, 0x00, 0x00, 0x00, + 0xd1, 0xe7, 0x03 +}; + +BYTE * +mpio_mbr_gen(BYTE size) +{ + BYTE *p; + + p = (BYTE *)malloc(SECTOR_SIZE); + memset(p, 0, SECTOR_SIZE); + + /* MBR signature */ + p[0x1fe] = 0x55; + p[0x1ff] = 0xaa; + + /* frist boot partition */ + switch(size) + { + case 16: + memcpy(p+0x1be, mpio_part_016, 0x10); + break; + case 32: + memcpy(p+0x1be, mpio_part_032, 0x10); + break; + case 64: + memcpy(p+0x1be, mpio_part_064, 0x10); + break; + case 128: + memcpy(p+0x1be, mpio_part_128, 0x10); + break; + default: + debug("This should never happen! (%d)\n", size); + exit(-1); + } + + /* all other partitions are set to zero */ + + return p; +} + +BYTE * +mpio_pbr_gen(BYTE size) +{ + BYTE *p; + + p = (BYTE *)malloc(SECTOR_SIZE); + memset(p, 0, SECTOR_SIZE); + + /* MBR signature */ + p[0x1fe] = 0x55; + p[0x1ff] = 0xaa; + + memcpy(p, mpio_pbr_head, 0x10); + /* BIOS parameter etc. */ + switch(size) + { + case 16: + memcpy(p+0x10, mpio_pbr_016, 0x13); + break; + case 32: + memcpy(p+0x10, mpio_pbr_032, 0x13); + break; + case 64: + memcpy(p+0x10, mpio_pbr_064, 0x13); + break; + case 128: + memcpy(p+0x10, mpio_pbr_128, 0x13); + break; + default: + debug("This should never happen! (%d)\n", size); + exit(-1); + } + + /* FAT id */ + if (size >=128) { + strcpy(p+0x36, "FAT16"); + } else { + strcpy(p+0x36, "FAT12"); + } + + return p; +} + +int +mpio_mbr_eval(mpio_smartmedia_t *sm) +{ + BYTE *pe; /* partition entry */ + int sector, head, cylinder; + + if ((sm->mbr[0x1fe] != 0x55) || (sm->mbr[0x1ff] != 0xaa)) + { + debug("This is not the MBR!\n"); + return 1; + } + + /* always use the first partition */ + /* we probably don't need to support others */ + pe = sm->mbr + 0x1be; + + head = (int)(*(pe+0x01) & 0xff); + sector = (int)(*(pe+0x02) & 0x3f); + cylinder = (int)((*(pe+0x02) >> 6) * 0x100 + *(pe + 0x03)); + + sm->pbr_offset=(cylinder * sm->geo.NumHead + head ) * + sm->geo.NumSector + sector - 1; + + return 0; + +} + + +int +mpio_pbr_eval(mpio_smartmedia_t *sm) +{ + BYTE *bpb; /* BIOS Parameter Block */ + int total_sector; + long temp; + + if ((sm->pbr[0x1fe] != 0x55) || (sm->pbr[0x1ff] != 0xaa)) + { + debug("This is not the PBR!\n"); + return 1; + } + + if (strncmp((sm->pbr+0x36),"FAT", 3) != 0) + { + debug("Did not find an FAT signature, *not* good!\n"); + return 2; + } + + bpb = sm->pbr + 0x0b; + + total_sector = (*(sm->pbr+0x14) * 0x100 + *(sm->pbr + 0x13)); + if (!total_sector) + total_sector = (*(sm->pbr+0x23) * 0x1000000 + + *(sm->pbr+0x22) * 0x10000 + + *(sm->pbr+0x21) * 0x100 + + *(sm->pbr+0x20)); + + /* 128 MB need 2 Bytes instead of 1.5 */ + if (sm->size != 128) + { + temp = ((total_sector / 0x20 * 0x03 / 0x02 / 0x200) + 0x01); + } else { + temp = ((total_sector / 0x20 * 0x02 / 0x200) + 0x01); + } + + sm->fat_offset = sm->pbr_offset + 0x01; + sm->fat_size = temp; + sm->fat_nums = *(sm->pbr + 0x10); + sm->dir_offset = sm->pbr_offset + 0x01 + temp * 2; + sm->max_cluster = (total_sector / BLOCK_SECTORS); + /* fix max clusters */ + temp*=2; + while (temp>=0x10) + { + sm->max_cluster--; + temp-=BLOCK_SECTORS; + } + + return 0; +} + + +void +mpio_fatentry_hw2entry(mpio_t *m, mpio_fatentry_t *f) +{ + mpio_smartmedia_t *sm; + BYTE chip, t; + DWORD value; + + if (f->mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + + if (f->hw_address == 0xffffffff) + return ; + + value = f->hw_address; + t = value >> 24; + chip = 0; + + while(t/=2) + chip++; + + value &= 0xffffff; + value /= 0x20; + value += chip * (sm->max_cluster / sm->chips); + + f->entry = value; + + return; + } + + debug("This should never happen!\n"); + exit(-1); + + return; +} + + +void +mpio_fatentry_entry2hw(mpio_t *m, mpio_fatentry_t *f) +{ + mpio_smartmedia_t *sm; + DWORD cluster; + BYTE chip; + + if (f->mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + + chip = f->entry / (sm->max_cluster / sm->chips); + cluster = f->entry - ((sm->max_cluster / sm->chips) * chip); + cluster *= 0x20; + cluster += 0x01000000 * (1 << chip); + + f->hw_address=cluster; + + return; + } + + debug("This should never happen!\n"); + exit(-1); + + return; +} + + + +int +mpio_bootblocks_read (mpio_t *m, mpio_mem_t mem) +{ + mpio_smartmedia_t *sm=0; + + int error; + + /* this should not be needed for internal memory, but ... */ + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + if (!sm) + return 1; + + /* in case the external mem is defective we need this here! */ + sm->fat=0; + sm->fat_size=0; + sm->fat_nums=0; + + /* TODO: check a few things more, just to be sure */ + + /* read CIS (just in case it might me usefull) */ + if (mpio_io_sector_read(m, mem, MPIO_BLOCK_CIS, sm->cis)) + { + debug("error reading CIS\n"); + return 1; + } + + /* read MBR */ + /* the MBR is always located @ logical block 0, sector 0! */ + if (mpio_io_sector_read(m, mem, 0, sm->mbr)) + { + debug("error reading MBR\n"); + return 1; + } + + if (error=mpio_mbr_eval(sm)) + { + debug("problem with the MBR (#%d), so I won't try to access the card any" + "further.\n", error); + return 1; + } + + /* read PBR */ + if (mpio_io_sector_read(m, mem, sm->pbr_offset, sm->pbr)) + { + debug("error reading PBR\n"); + return 1; + } + + if (error=mpio_pbr_eval(sm)) + { + debug("problem with the PBR (#%d), so I won't try to access the card any" + "further.\n", error); + return 1; + } + + return 0; +} + +mpio_fatentry_t * +mpio_fatentry_new(mpio_t *m, mpio_mem_t mem, DWORD sector, BYTE ftype) +{ + mpio_smartmedia_t *sm; + mpio_fatentry_t *new; + + new = malloc (sizeof(mpio_fatentry_t)); + + if (new) + { + new->m = m; + new->mem = mem; + new->entry = sector; + + /* init FAT entry */ + memset(new->i_fat, 0xff, 0x10); + new->i_fat[0x00] = 0xaa; /* start of file */ + new->i_fat[0x06] = ftype; + new->i_fat[0x0b] = 0x00; + new->i_fat[0x0c] = 0x00; + new->i_fat[0x0d] = 0x00; + if (m->model >= MPIO_MODEL_FD100) { + /* 0x0e is a copy of the file index number */ + new->i_fat[0x0f] = 0x00; + } else { + new->i_fat[0x0e] = 'P'; + new->i_fat[0x0f] = 'C'; + } + } + + if (mem == MPIO_INTERNAL_MEM) + mpio_fatentry_entry2hw(m, new); + + return new; +} + +int +mpio_fatentry_plus_plus(mpio_fatentry_t *f) +{ + f->entry++; + + if (f->mem == MPIO_INTERNAL_MEM) { + if (f->entry >= f->m->internal.max_cluster) + { + f->entry--; + mpio_fatentry_entry2hw(f->m, f); + return 0; + } + mpio_fatentry_entry2hw(f->m, f); + } + + if (f->mem == MPIO_EXTERNAL_MEM) { + if (f->entry > f->m->external.max_cluster) + { + f->entry--; + return 0; + } + } + + return 1; +} + + +/* read "fat_size" sectors of fat into the provided buffer */ +int +mpio_fat_read (mpio_t *m, mpio_mem_t mem, + mpio_callback_init_t progress_callback) +{ + mpio_smartmedia_t *sm; + BYTE recvbuff[SECTOR_SIZE]; + int i; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + if (mpio_io_spare_read(m, mem, 0, sm->size, 0, sm->fat, + (sm->fat_size * SECTOR_SIZE), progress_callback)) + return 1; + return 0; + } + + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if (!sm) + return 1; + + for (i = 0; i < sm->fat_size; i++) { + if (mpio_io_sector_read(m, mem, (sm->fat_offset + i), recvbuff)) + return 1; + + memcpy(sm->fat + (i * SECTOR_SIZE), recvbuff, SECTOR_SIZE); + } + + return (0); +} + +int +mpio_fatentry_free(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f ) +{ + int e,i ; + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) { + sm = &m->internal; + e = f->entry * 0x10; + + /* be more strict to avoid writing + * to defective blocks! + */ + i=0; + while (i<0x10) + { + if (sm->fat[e+i] != 0xff) + return 0; + i++; + } + return 1; + } + + if (mem == MPIO_EXTERNAL_MEM) { + sm = &m->internal; + if (mpio_fatentry_read(m, mem, f) == 0) + return 1; + } + + return 0; +} + +DWORD +mpio_fatentry_read(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f ) +{ + mpio_smartmedia_t *sm; + int e; + int v; + + if (mem == MPIO_INTERNAL_MEM) { + sm = &m->internal; + e = f->entry * 0x10; + if (mpio_fatentry_is_defect(m, mem, f)) + return 0xffffffff; + + /* this is a special system file! */ + if((sm->fat[e+6] != FTYPE_MUSIC) && + (sm->fat[e+7] == 0xff) && + (sm->fat[e+8] == 0x00) && + (sm->fat[e+9] == 0xff) && + (sm->fat[e+10] == 0xff)) + return 0xffffffff; + /* this is a special system file! */ +/* this is not correct!! */ +/* if (sm->fat[e+6] == FTYPE_CONF) */ +/* return 0xffffffff; */ + /* this is a special system file! */ + if((sm->fat[e+6] != FTYPE_MUSIC) && + (sm->fat[e+0x0b] == 0xff) && + (sm->fat[e+0x0c] == 0xff) && + (sm->fat[e+0x0d] == 0xff)) + return 0xffffffff; + + if((sm->fat[e+7] == 0xff) && + (sm->fat[e+8] == 0xff) && + (sm->fat[e+9] == 0xff) && + (sm->fat[e+10] == 0xff)) + return 0xffffffff; + + v = sm->fat[e+7] * 0x1000000 + + sm->fat[e+8] * 0x10000 + + sm->fat[e+9] * 0x100 + + sm->fat[e+10]; + + return v; + } + + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if (!sm->fat) + { + debug ("error, no space for FAT allocated!\n"); + return 0; + } + + + if (sm->size == 128) { + /* 2 Byte per entry */ + e = f->entry * 2; + v = sm->fat[e + 1] * 0x100 + sm->fat[e]; + } else { + /* 1.5 Byte per entry */ + /* Nibble order: x321 */ + e = (f->entry * 3 / 2); +/* printf("mager: byte (%d/%d)\n", e, e+1); */ + if ((f->entry & 0x01) == 0) { + /* LLxH */ + /* 21x3 */ + v = (sm->fat[e + 1] & 0x0f) * 0x100 + sm->fat[e]; + } else { + /* 1x32 */ + v = (sm->fat[e + 1] * 0x10) + (sm->fat[e] >> 4); + } + } + + return v; +} + +int +mpio_fatentry_write(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f, WORD value) +{ + mpio_smartmedia_t *sm; + int e; + BYTE backup; + + if (mem == MPIO_INTERNAL_MEM) + { + debug("This should not be used for internal memory!\n"); + exit(-1); + } + + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if (sm->size == 128) + { + /* 2 Byte per entry */ + e = f->entry * 2; + sm->fat[e] = value & 0xff; + sm->fat[e + 1] = (value >> 8 ) & 0xff; + } else { + /* 1.5 Byte per entry */ + e = (f->entry * 3 / 2); + if ((f->entry & 0x01) == 0) { + /* 21x3 */ + sm->fat[e] = value & 0xff; + backup = sm->fat[e + 1] & 0xf0; + sm->fat[e + 1] = backup | (( value / 0x100 ) & 0x0f); + } else { + /* 1x32 */ + sm->fat[e + 1] = (value / 0x10) & 0xff; + backup = sm->fat[e] & 0x0f; + sm->fat[e] = backup | ( (value * 0x10) & 0xf0 ); + } + } + + return 0; +} + +int +mpio_fat_internal_find_startsector(mpio_t *m, BYTE start) +{ + mpio_fatentry_t *f; + mpio_smartmedia_t *sm = &m->internal; + int found=-1; + + f = mpio_fatentry_new(m, MPIO_INTERNAL_MEM, 0, FTYPE_MUSIC); + + while(mpio_fatentry_plus_plus(f)) + { + if ((sm->fat[f->entry * 0x10] == 0xaa) && + (sm->fat[f->entry * 0x10 + 1] == start)) + found=f->entry; + } + + free(f); + + return found; +} + +BYTE +mpio_fat_internal_find_fileindex(mpio_t *m) +{ + mpio_fatentry_t *f; + mpio_smartmedia_t *sm = &m->internal; + BYTE index[256]; + BYTE found; /* hmm, ... */ + + memset(index, 1, 256); + + f = mpio_fatentry_new(m, MPIO_INTERNAL_MEM, 0, FTYPE_MUSIC); + while(mpio_fatentry_plus_plus(f)) + { + if (sm->fat[f->entry * 0x10 + 1] != 0xff) + index[sm->fat[f->entry * 0x10 + 1]] = 0; + } + free(f); + + found=6; + while((found<256) && (!index[found])) + found++; + + if (found==256) + { + debug("Oops, did not find a new fileindex!\n" + "This should never happen, aborting now!, Sorry!\n"); + exit(-1); + } + + return found; +} + + +int +mpio_fat_free_clusters(mpio_t *m, mpio_mem_t mem) +{ + mpio_smartmedia_t *sm; + mpio_fatentry_t *f; + int i; + int e = 0; + int fsize; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if (sm->fat) + { + f = mpio_fatentry_new(m, mem, 0, FTYPE_MUSIC); + do + { + if (mpio_fatentry_free(m, mem, f)) + e++; + } while (mpio_fatentry_plus_plus(f)); + free(f); + } else { + f = 0; + } + + + return (e * 16); +} + +mpio_fatentry_t * +mpio_fatentry_find_free(mpio_t *m, mpio_mem_t mem, BYTE ftype) +{ + mpio_fatentry_t *f; + + f = mpio_fatentry_new(m, mem, 1, ftype); + + while(mpio_fatentry_plus_plus(f)) + { + if (mpio_fatentry_free(m, mem, f)) + return f; + } + + free(f); + + return NULL; +} + +int +mpio_fatentry_next_free(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) +{ + mpio_fatentry_t backup; + + memcpy(&backup, f, sizeof(mpio_fatentry_t)); + + while(mpio_fatentry_plus_plus(f)) + { + if (mpio_fatentry_free(m, mem, f)) + { + if (mem == MPIO_INTERNAL_MEM) + f->i_fat[0x00] = 0xee; + return 1; + } + } + + /* no free entry found, restore entry */ + memcpy(f, &backup, sizeof(mpio_fatentry_t)); + + return 0; +} + +int +mpio_fatentry_next_entry(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) +{ + mpio_smartmedia_t *sm; + DWORD value; + DWORD endvalue; + + value = mpio_fatentry_read(m, mem, f); + + if (value == 0xaaaaaaaa) + return -1; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + f->hw_address = value; + + mpio_fatentry_hw2entry(m, f); + + endvalue = 0xffffffff; + } + + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->external; + f->entry = value; + + if (sm->size==128) + { + endvalue = 0xfff8; + } else { + endvalue = 0xff8; + } + } + + if (value >= endvalue) + return 0; + + return 1; +} + + +int +mpio_fat_clear(mpio_t *m, mpio_mem_t mem) +{ + mpio_smartmedia_t *sm; + mpio_fatentry_t *f; + + if (mem == MPIO_INTERNAL_MEM) { + sm = &m->internal; + + f = mpio_fatentry_new(m, mem, 1, FTYPE_MUSIC); + do { + mpio_fatentry_set_free(m, mem, f) ; + } while(mpio_fatentry_plus_plus(f)); + free(f); + } + + if (mem == MPIO_EXTERNAL_MEM) { + sm = &m->external; + memset(sm->fat, 0x00, (sm->fat_size * SECTOR_SIZE)); + sm->fat[0] = 0xf8; + sm->fat[1] = 0xff; + sm->fat[2] = 0xff; + /* for FAT 16 */ + if (sm->size == 128) + sm->fat[3] = 0xff; + } + + return 0; +} + +/* + * This function acutally writes both, + * the FAT _and_ the root directory + * + */ + +int +mpio_fat_write(mpio_t *m, mpio_mem_t mem) +{ + mpio_smartmedia_t *sm; + mpio_fatentry_t *f; + BYTE dummy[BLOCK_SIZE]; + WORD i; + DWORD block; + + if (mem == MPIO_INTERNAL_MEM) { + sm = &m->internal; + + if (sm->cdir == sm->root) + { + f=mpio_fatentry_new(m, mem, 0, FTYPE_MUSIC); + mpio_io_block_delete(m, mem, f); + free(f); + + memset(dummy, 0x00, BLOCK_SIZE); + + /* only write the root dir */ + for (i= 0; i< 0x20; i++) + { + + if (i<DIR_NUM) + { + mpio_io_sector_write(m, mem, i, + (sm->root->dir + SECTOR_SIZE * i)); + } else { + /* fill the rest of the block with zeros */ + mpio_io_sector_write(m, mem, i, dummy); + } + } + } else { + mpio_directory_write(m, mem, sm->cdir); + } + + } + + if (mem == MPIO_EXTERNAL_MEM) + { + sm=&m->external; + + memset(dummy, 0xff, BLOCK_SIZE); + + for (i = 0; i < (sm->dir_offset + DIR_NUM) ; i++) { + /* before writing to a new block delete it! */ + if (((i / 0x20) * 0x20) == i) { + block = mpio_zone_block_find_seq(m, mem, (i/0x20)); + if (block == MPIO_BLOCK_NOT_FOUND) + { + block = mpio_zone_block_find_free_seq(m, mem, (i/0x20)); + } + if (block == MPIO_BLOCK_NOT_FOUND) + { + debug("This should never happen!"); + exit(-1); + } + + mpio_io_block_delete_phys(m, mem, block); + } + + /* remeber: logical sector 0 is the MBR! */ + if (i == 0) + mpio_io_sector_write(m, mem, 0, sm->mbr); + if ((i > 0) && (i < sm->pbr_offset)) + mpio_io_sector_write(m, mem, i, dummy); + + if (i == sm->pbr_offset) + mpio_io_sector_write(m, mem, sm->pbr_offset, sm->pbr); + + if ((i >= sm->fat_offset) && (i < (sm->fat_offset + (2*sm->fat_size)))) + mpio_io_sector_write(m, mem, i, + (sm->fat + SECTOR_SIZE * + ((i - sm->fat_offset) % sm->fat_size))); + + if (i>=sm->dir_offset) + mpio_io_sector_write(m, mem, i, + (sm->root->dir + + (i - sm->dir_offset) * SECTOR_SIZE)); + } + + if (sm->cdir != sm->root) + mpio_directory_write(m, mem, sm->cdir); + + } + + + return 0; +} + +int +mpio_fatentry_set_free (mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) +{ + int e; + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + e = f->entry * 0x10; + memset((sm->fat+e), 0xff, 0x10); + } + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->internal; + mpio_fatentry_write(m, mem, f, 0); + } + + return 0; +} + +int +mpio_fatentry_set_defect(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) +{ + int e; + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + e = f->entry * 0x10; + memset((sm->fat+e), 0xaa, 0x10); + } + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->internal; + mpio_fatentry_write(m, mem, f, 0xfff7); + } + + return 0; +} + +int +mpio_fatentry_is_defect(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) +{ + int e; + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + e = f->entry * 0x10; + if (mpio_fatentry_free(m, mem, f)) + return 0; + /* check if this block became defective */ + if (m->model >= MPIO_MODEL_FD100) { + /* newer models */ + if ((sm->fat[e+0x0f] != 0) || + (sm->fat[e+0x01] != sm->fat[e+0x0e])) + { + debug("defective block encountered, abort reading! (newer models check)\n"); + return 1; + } + } else + if ((sm->fat[e+0x0e] != 'P') || + (sm->fat[e+0x0f] != 'C') || + ((sm->fat[e+0x00] != 0xaa) && + (sm->fat[e+0x00] != 0xee))) + { + debug("defective block encountered, abort reading! (older models check)\n"); + return 1; + } + } + + if (mem == MPIO_EXTERNAL_MEM) + { + if (mpio_fatentry_read(m, mem, f)==0xfff7) + return 1; + } + + return 0; +} + +int +mpio_fatentry_set_eof(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) +{ + int e; + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + e = f->entry * 0x10; + memset((f->i_fat+0x07), 0xff, 4); + memcpy((sm->fat+e), f->i_fat, 0x10); + } + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->internal; + mpio_fatentry_write(m, mem, f, 0xffff); + } + + return 0; +} + +int +mpio_fatentry_set_next(mpio_t *m, mpio_mem_t mem, + mpio_fatentry_t *f, mpio_fatentry_t *value) +{ + int e; + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + e = f->entry * 0x10; + + f->i_fat[0x07]= value->hw_address / 0x1000000; + f->i_fat[0x08]=(value->hw_address / 0x10000 ) & 0xff; + f->i_fat[0x09]=(value->hw_address / 0x100 ) & 0xff; + f->i_fat[0x0a]= value->hw_address & 0xff; + + memcpy((sm->fat+e), f->i_fat, 0x10); + } + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->internal; + mpio_fatentry_write(m, mem, f, value->entry); + } + + return 0; +} + diff --git a/libmpio/src/fat.h b/libmpio/src/fat.h new file mode 100644 index 0000000..adb359b --- /dev/null +++ b/libmpio/src/fat.h @@ -0,0 +1,87 @@ +/* + * + * $Id: fat.h,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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. + * + * */ + +#ifndef _MPIO_FAT_H_ +#define _MPIO_FAT_H_ + +#include "defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* generate fresh boot sectors for formatting of external mem */ +BYTE *mpio_mbr_gen(BYTE); +BYTE *mpio_pbr_gen(BYTE); + +/* only needed for external memory */ +int mpio_bootblocks_read(mpio_t *, mpio_mem_t); +int mpio_mbr_eval(mpio_smartmedia_t *); +int mpio_pbr_eval(mpio_smartmedia_t *); + +/* functions on the FAT for internal *and* external */ +int mpio_fat_read(mpio_t *, mpio_mem_t, mpio_callback_init_t); +int mpio_fat_write(mpio_t *, mpio_mem_t); +int mpio_fat_clear(mpio_t *, mpio_mem_t); +int mpio_fat_free_clusters(mpio_t *, mpio_mem_t); +int mpio_fat_free(mpio_t *, mpio_mem_t); + +/* functions to iterate through the FAT linked list(s) */ +mpio_fatentry_t *mpio_fatentry_new(mpio_t *, mpio_mem_t, DWORD, BYTE); +int mpio_fatentry_plus_plus(mpio_fatentry_t *); + +mpio_fatentry_t *mpio_fatentry_find_free(mpio_t *, mpio_mem_t, BYTE); +int mpio_fatentry_next_free(mpio_t *, mpio_mem_t, + mpio_fatentry_t *); +int mpio_fatentry_next_entry(mpio_t *, mpio_mem_t, + mpio_fatentry_t *); +DWORD mpio_fatentry_read(mpio_t *, mpio_mem_t, mpio_fatentry_t *); +int mpio_fatentry_write(mpio_t *, mpio_mem_t, mpio_fatentry_t *, + WORD); + +int mpio_fatentry_set_free (mpio_t *, mpio_mem_t, + mpio_fatentry_t *); +int mpio_fatentry_set_defect(mpio_t *, mpio_mem_t, + mpio_fatentry_t *); +int mpio_fatentry_set_eof(mpio_t *, mpio_mem_t, + mpio_fatentry_t *); +int mpio_fatentry_set_next(mpio_t *, mpio_mem_t, + mpio_fatentry_t *, mpio_fatentry_t *); +int mpio_fatentry_is_defect(mpio_t *, mpio_mem_t, + mpio_fatentry_t *); + +/* finding a file is fundamental different for internal mem */ +int mpio_fat_internal_find_startsector(mpio_t *, BYTE); +BYTE mpio_fat_internal_find_fileindex(mpio_t *); + +/* mapping logical <-> physical for internal memory only */ +void mpio_fatentry_hw2entry(mpio_t *, mpio_fatentry_t *); +void mpio_fatentry_entry2hw(mpio_t *, mpio_fatentry_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _MPIO_FAT_H_ */ diff --git a/libmpio/src/id3.c b/libmpio/src/id3.c new file mode 100644 index 0000000..e5aba36 --- /dev/null +++ b/libmpio/src/id3.c @@ -0,0 +1,292 @@ +/* + * $Id: id3.c,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for accessing Digit@lways MPIO players + * Copyright (C) 2003 Markus Germeier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc.,g 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <unistd.h> +#include <fcntl.h> +#include <iconv.h> + +#include "id3.h" +#include "debug.h" +#include "mplib.h" + +#ifdef MPLIB +void +mpio_id3_get_content(id3_tag *tag, id3_tag *tag2, int field, + BYTE out[INFO_LINE]) +{ + id3_content *content; + id3_text_content *text_content; + + content = mp_get_content(tag, field); + if (!content) + content = mp_get_content(tag2, field); + if (content) + { + text_content = mp_parse_artist(content); + debugn(2, "Found (%d): %s\n", field, text_content->text); + strncpy(out, text_content->text, INFO_LINE); + } else { + strcpy(out,""); + } + +} + +void +mpio_id3_copy_tag(BYTE *src, BYTE *dest, int *offset) +{ + int i=0; + int last=0; + + /* find last non-space character, so we can strip */ + /* trailing spaces */ + while(src[i]) + if (src[i++]!=0x20) + last=i; + + i=0; + while((*offset<(INFO_LINE-1)) && (src[i]) && (i<last)) + dest[(*offset)++]=src[i++]; +} + +#endif /* MPLIB */ + +BYTE +mpio_id3_set(mpio_t *m, BYTE value) +{ +#ifdef MPLIB + m->id3 = value; + return m->id3; +#else + return 0; +#endif /* MPLIB */ +} + +/* query ID3 rewriting support */ +BYTE +mpio_id3_get(mpio_t *m) +{ +#ifdef MPLIB + return m->id3; +#else + return 0; +#endif /* MPLIB */ +} + +/* ID3 rewriting: do the work */ +/* context, src filename, uniq filename template */ +int +mpio_id3_do(mpio_t *m, BYTE *src, BYTE *tmp) +{ +#ifdef MPLIB + int fd, in; + BYTE buf[BLOCK_SIZE]; + int r, w; + int i, j, t; + id3_tag *tag, *tag2, *new_tag; + id3_tag_list *tag_list; + id3_tag_list new_tag_list; + id3_content *content; + id3_content new_content; + id3_text_content *text_content; + id3v2_tag *v2_tag; + BYTE data_artist[INFO_LINE]; + BYTE data_title[INFO_LINE]; + BYTE data_album[INFO_LINE]; + BYTE data_year[INFO_LINE]; + BYTE data_genre[INFO_LINE]; + BYTE data_comment[INFO_LINE]; + BYTE data_track[INFO_LINE]; + + BYTE mpio_tag[INFO_LINE]; + char *mpio_tag_unicode; + + char *uc; + iconv_t ic; + int fin, fout; + char *fback, *back; + + if (!m->id3) + return 0; + + sprintf(tmp, "/tmp/MPIO-XXXXXXXXXXXXXXX", INFO_LINE); + + fd = mkstemp(tmp); + if (fd==-1) return 0; + sprintf(m->id3_temp, tmp, INFO_LINE); + + in = open(src, O_RDONLY); + if (in==-1) return 0; + + do { + r=read(in, buf, BLOCK_SIZE); + if (r>0) + w=write(fd, buf, r); + } while (r>0); + + close (in); + + tag_list = mp_get_tag_list_from_fd(fd); + if (!tag_list) + { + debug("no tag list found!\n"); + return 0; + } + + tag = tag_list->tag; + tag2 = NULL; + if (tag_list->next) + tag2 = tag_list->next->tag; + + /* read tags from file */ + mpio_id3_get_content(tag, tag2, MP_ARTIST, data_artist); + mpio_id3_get_content(tag, tag2, MP_TITLE, data_title); + mpio_id3_get_content(tag, tag2, MP_ALBUM, data_album); + mpio_id3_get_content(tag, tag2, MP_GENRE, data_genre); + mpio_id3_get_content(tag, tag2, MP_COMMENT, data_comment); + mpio_id3_get_content(tag, tag2, MP_YEAR, data_year); + mpio_id3_get_content(tag, tag2, MP_TRACK, data_track); + + /* build new tag */ + mpio_tag[0]=0x00; + i=j=t=0; + + while ((t<(INFO_LINE-1) && m->id3_format[i]!=0)) + { + if (m->id3_format[i] == '%') + { + i++; + switch(m->id3_format[i]) + { + case 'p': + mpio_id3_copy_tag(data_artist, mpio_tag, &t); + break; + case 't': + mpio_id3_copy_tag(data_title, mpio_tag, &t); + break; + case 'a': + mpio_id3_copy_tag(data_album, mpio_tag, &t); + break; + case 'g': + mpio_id3_copy_tag(data_genre, mpio_tag, &t); + break; + case 'c': + mpio_id3_copy_tag(data_comment, mpio_tag, &t); + break; + case 'y': + mpio_id3_copy_tag(data_year, mpio_tag, &t); + break; + case 'n': + mpio_id3_copy_tag(data_track, mpio_tag, &t); + break; + default: + mpio_tag[t] = m->id3_format[i]; + } + } else { + mpio_tag[t] = m->id3_format[i]; + t++; + } + + i++; + } + mpio_tag[t]=0x00; + + debugn(2, "new_tag: %s\n", mpio_tag); + + /* convert tag to UNICODELITTLE */ + fin = strlen(mpio_tag) + 1; + fout = fin*2 + 2; + ic = iconv_open("UNICODELITTLE", "ASCII"); + fback = mpio_tag; + mpio_tag_unicode = (char *)malloc(2*INFO_LINE+3); + back = (char *)mpio_tag_unicode; + *back=0x01; + back++; + *back=0xff; + back++; + *back=0xfe; + back++; + + debugn(2,"iconv before %s %d %d\n", fback, fin, fout); + iconv(ic, (char **)&fback, &fin, (char **)&back, &fout); + debugn(2,"iconv after %s %d %d\n", fback, fin, fout); + iconv_close(ic); + hexdumpn(2, mpio_tag, strlen(mpio_tag)); + hexdumpn(2, (char *)mpio_tag_unicode, (2*strlen(mpio_tag))+3); + + /* build new ID3 v2 tag with only TXXX field */ + new_content.length=(2*strlen(mpio_tag))+3; + new_content.data = (char *)malloc(new_content.length); + new_content.compressed=0; + new_content.encrypted=0; + memcpy(new_content.data, mpio_tag_unicode, new_content.length); + + new_tag = mp_alloc_tag_with_version (2); + mp_set_custom_content(new_tag, "TXXX", &new_content); + + v2_tag = (id3v2_tag *)new_tag->tag; + v2_tag->header->unsyncronization=0; + v2_tag->header->is_experimental=0; + + new_tag_list.tag = new_tag; + new_tag_list.next = NULL; + new_tag_list.first = NULL; + + /* delete ID3 v2 tag from file */ + mp_del_tags_by_ver_from_fd(fd, 2); + close (fd); + + /* write new ID3 v2 tag to file */ + mp_write_to_file(&new_tag_list, tmp); + + free(mpio_tag_unicode); + + return 1; +#else + return 0; +#endif /* MPLIB */ +} + +int +mpio_id3_end(mpio_t *m) +{ +#ifdef MPLIB + if (m->id3_temp[0]) + unlink(m->id3_temp); + m->id3_temp[0] = 0x00; + return 1; +#else + return 0; +#endif /* MPLIB */ +} + +void +mpio_id3_format_set(mpio_t *m, BYTE *format) +{ + strncpy(m->id3_format, format, INFO_LINE); +} + +/* get format string for rewriting*/ +void +mpio_id3_format_get(mpio_t *m, BYTE *format) +{ + strncpy(format, m->id3_format, INFO_LINE); +} diff --git a/libmpio/src/id3.h b/libmpio/src/id3.h new file mode 100644 index 0000000..1bb549c --- /dev/null +++ b/libmpio/src/id3.h @@ -0,0 +1,44 @@ +/* + * $Id: id3.h,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for accessing Digit@lways MPIO players + * Copyright (C) 2003 Markus Germeier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _MPIO_ID3_H_ +#define _MPIO_ID3_H_ + +#include "defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ID3 rewriting: do the work */ +/* context, src filename, uniq filename template */ +int mpio_id3_do(mpio_t *, BYTE *, BYTE *); + +/* ID3: clean up temp file */ +int mpio_id3_end(mpio_t *); + +#ifdef __cplusplus +} +#endif + + +#endif /* _MPIO_ID3_H_ */ 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 <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#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; i<sm->max_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) && (i<MPIO_ZONE_PBLOCKS)) + i++; + + if (i==MPIO_ZONE_PBLOCKS) + { + debug("could not find free pysical block\n"); + return MPIO_BLOCK_NOT_FOUND; + } + + debugn(2, "set new sector in zonetable, [%d][%d] = %4x\n", zone, i, block); + + sm->zonetable[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; +} diff --git a/libmpio/src/io.h b/libmpio/src/io.h new file mode 100644 index 0000000..9b5df11 --- /dev/null +++ b/libmpio/src/io.h @@ -0,0 +1,95 @@ +/* -*- linux-c -*- */ + +/* + * + * $Id: io.h,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. + * + * */ + +#ifndef _MPIO_IO_H_ +#define _MPIO_IO_H_ + +#include "defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* phys.<->log. block mapping */ +int mpio_zone_init(mpio_t *, mpio_cmd_t); +/* context, memory bank, logical block */ +/* returns address of physical block! */ +DWORD mpio_zone_block_find_log(mpio_t *, mpio_cmd_t, DWORD); + /* context, memory bank, sequential block (for sector addressing) */ +/* returns address of physical block! */ +DWORD mpio_zone_block_find_seq(mpio_t *, mpio_cmd_t, DWORD); +/* context, memory bank, logical block */ +/* find used physical block and mark it as unused! */ +/* returns address of physical block! (to delete the physical block!) */ +DWORD mpio_zone_block_set_free(mpio_t *, mpio_cmd_t, DWORD); +/* context, memory bank, physical block */ +void mpio_zone_block_set_free_phys(mpio_t *, mpio_cmd_t, DWORD); +/* context, memory bank, physical block */ +void mpio_zone_block_set_defect_phys(mpio_t *, mpio_cmd_t, DWORD); +/* context, memory bank, logical block */ +/* looks for a free physical block to be used for given logical block */ +/* mark the found block used for this logical block */ +/* returns address of physical block! */ +DWORD mpio_zone_block_find_free_log(mpio_t *, mpio_cmd_t, DWORD); +DWORD mpio_zone_block_find_free_seq(mpio_t *, mpio_cmd_t, DWORD); +/* return zone-logical block for a given physical block */ +WORD mpio_zone_block_get_logical(mpio_t *, mpio_cmd_t, DWORD); + + +/* real I/O */ +int mpio_io_set_cmdpacket(mpio_t *, mpio_cmd_t, mpio_mem_t, + DWORD, WORD, BYTE, BYTE *); + +int mpio_io_bulk_read (int, BYTE *, int); +int mpio_io_bulk_write(int, BYTE *, int); + +/* read version block into memory */ +int mpio_io_version_read(mpio_t *, BYTE *); + +/* */ +int mpio_io_sector_read (mpio_t *, BYTE, DWORD, BYTE *); +int mpio_io_sector_write(mpio_t *, BYTE, DWORD, BYTE *); + +/* */ +int mpio_io_block_read (mpio_t *, mpio_mem_t, mpio_fatentry_t *, BYTE *); +int mpio_io_block_write (mpio_t *, mpio_mem_t, mpio_fatentry_t *, BYTE *); +int mpio_io_block_delete(mpio_t *, mpio_mem_t, mpio_fatentry_t *); +/* needed for formatting of external memory */ +int mpio_io_block_delete_phys(mpio_t *, BYTE, DWORD); + +/* */ +int mpio_io_spare_read (mpio_t *, BYTE, DWORD, WORD, BYTE, BYTE *, int, + mpio_callback_init_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _MPIO_IO_H_ */ diff --git a/libmpio/src/mpio.c b/libmpio/src/mpio.c new file mode 100644 index 0000000..894b6f8 --- /dev/null +++ b/libmpio/src/mpio.c @@ -0,0 +1,1301 @@ +/* + * + * $Id: mpio.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. + * + * */ + +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/types.h> +#include <utime.h> + +#include "cis.h" +#include "defs.h" +#include "debug.h" +#include "directory.h" +#include "io.h" +#include "mpio.h" +#include "smartmedia.h" +#include "fat.h" + +void mpio_bail_out(void); +void mpio_init_internal(mpio_t *); +void mpio_init_external(mpio_t *); +int mpio_check_filename(mpio_filename_t); + +int mpio_file_get_real(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_filename_t, + mpio_callback_t, BYTE **); + +int mpio_file_put_real(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_filename_t, + mpio_filetype_t, mpio_callback_t, BYTE *, int); + +static BYTE *mpio_model_name[] = { + "MPIO-DME", + "MPIO-DMG", + "MPIO-DMG+", + "MPIO-DMB", + "MPIO-DMB+", + "MPIO-DMK", + "MPIO-FD100", + "MPIO-FL100", + "MPIO-FY100", + "unknown" +}; + +static mpio_error_t mpio_errors[] = { + { MPIO_ERR_FILE_NOT_FOUND, + "The selected file can not be found." }, + { MPIO_ERR_NOT_ENOUGH_SPACE, + "There is not enough space left on the selected memory card." }, + { MPIO_ERR_FILE_EXISTS, + "The selected file already exists and can not be overwritten. Remove it first." }, + { MPIO_ERR_FAT_ERROR, + "Internal error while reading the FAT." }, + { MPIO_ERR_READING_FILE, + "The selected file can not be read." }, + { MPIO_ERR_PERMISSION_DENIED, + "There are not enough rights to access the file/directory." }, + { MPIO_ERR_WRITING_FILE, + "There are no permisson to write to the selected file." }, + { MPIO_ERR_DIR_TOO_LONG, + "The selected directory name is to long." }, + { MPIO_ERR_DIR_NOT_FOUND, + "The selected directory can not be found." }, + { MPIO_ERR_DIR_NOT_A_DIR, + "The selected directory is not a directory." }, + { MPIO_ERR_DIR_NAME_ERROR, + "The selected directory name is not allowed." }, + { MPIO_ERR_DIR_NOT_EMPTY, + "The selected directory is not empty." }, + { MPIO_ERR_DEVICE_NOT_READY, + "Could not open " MPIO_DEVICE "\n" + "Verify that the mpio module is loaded and " + "your MPIO is\nconnected and powered up.\n" }, + { MPIO_ERR_OUT_OF_MEMORY, + "Out of Memory." }, + { MPIO_ERR_INTERNAL, + "Oops, internal ERROR. :-(" }, + { MPIO_ERR_INT_STRING_INVALID, + "Internal Error: Supported is invalid!" } +}; + +static const int mpio_error_num = sizeof mpio_errors / sizeof(mpio_error_t); + +static int _mpio_errno = 0; + +#define MPIO_ERR_RETURN(err) { mpio_id3_end(m); _mpio_errno = err; return -1 ; } + +#define MPIO_CHECK_FILENAME(filename) \ + if (!mpio_check_filename(filename)) { \ + MPIO_ERR_RETURN(MPIO_ERR_INT_STRING_INVALID); \ + } + +void +mpio_bail_out(void){ + printf("I'm utterly confused and aborting now, sorry!"); + printf("Please report this to: mpio-devel@lists.sourceforge.net\n"); + exit(1); +} + +int +mpio_check_filename(mpio_filename_t filename) +{ + BYTE *p=filename; + + while (p < (filename + MPIO_FILENAME_LEN)) + { + if (*p) + return 1; + p++; + } + + return 0; +} + +void +mpio_init_internal(mpio_t *m) +{ + mpio_smartmedia_t *sm = &m->internal; + BYTE i_offset = 0x18; + + /* init main memory parameters */ + sm->manufacturer = m->version[i_offset]; + sm->id = m->version[i_offset + 1]; + sm->chips = 1; + if (!(mpio_id_valid(m->version[i_offset]))) + { + sm->manufacturer = 0; + sm->id = 0; + sm->size = 0; + debug("WARNING: no internal memory found\n"); + return; + } + + + /* look for further installed memory chips + * models with 1, 2 and 4 chips are known + * (there _really_ shouldn't be any other versions out there ...) + */ + while ((sm->chips < 4) && + (mpio_id_valid(m->version[i_offset + (2 * sm->chips)]))) + { + if(mpio_id2mem(sm->id) != + mpio_id2mem(m->version[i_offset + (2 * sm->chips) + 1])) + { + printf("Found a MPIO with internal chips of different sizes!"); + mpio_bail_out(); + } + sm->chips++; + } + + if ((sm->chips == 3) || (sm->chips > 4)) + { + printf("Found a MPIO with %d internal chips", sm->chips); + mpio_bail_out(); + } + + sm->size = sm->chips * mpio_id2mem(sm->id); + debugn(2, "found %d chip(s) with %d MB => %d MB internal mem\n", + sm->chips, mpio_id2mem(sm->id), sm->size); + + /* used for size calculations (see mpio_memory_free) */ + mpio_id2geo(sm->id, &sm->geo); + + /* read FAT information from spare area */ + sm->max_cluster = (sm->size * 1024) / 16; /* 1 cluster == 16 KB */ + sm->max_blocks = sm->max_cluster; + debugn(2, "max_cluster: %d\n", sm->max_cluster); + /* 16 bytes per cluster */ + sm->fat_size = (sm->max_cluster * 16) / SECTOR_SIZE; + debugn(2, "fat_size: %04x\n", sm->fat_size * SECTOR_SIZE); + sm->fat = malloc(sm->fat_size * SECTOR_SIZE); + /* fat will be read in mpio_init, so we can more easily handle + a callback function */ + + if (!(sm->fat_size)) + { + printf("Some values on the way to the FAT calculations did not compute. :-(\n"); + mpio_bail_out(); + } + + + /* Read directory from internal memory */ + sm->dir_offset=0; + sm->root = malloc (sizeof(mpio_directory_t)); + sm->root->name[0] = 0; + sm->root->next = NULL; + sm->root->prev = NULL; + mpio_rootdir_read(m, MPIO_INTERNAL_MEM); + sm->cdir = sm->root; +} + +void +mpio_init_external(mpio_t *m) +{ + mpio_smartmedia_t *sm = &(m->external); + 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->model != MPIO_MODEL_FL100)) /* ignore external memory ATM until + we know how to support it! */ + { + sm->manufacturer = m->version[e_offset]; + sm->id = m->version[e_offset + 1]; + } else { + sm->manufacturer = 0; + sm->id = 0; + sm->chips = 0; + sm->size = 0; + } + + /* init memory parameters if external memory is found */ + if (sm->id != 0) + { + /* Read things from external memory (if available) */ + sm->size = mpio_id2mem(sm->id); + sm->chips = 1; /* external is always _one_ chip !! */ + + mpio_id2geo(sm->id, &sm->geo); + + if (sm->size < 16) + { + debug("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"); + } + + /* for reading the spare area later! */ + sm->max_blocks = sm->size / 16 * 1024; /* 1 cluster == 16 KB */ + sm->spare = malloc(sm->max_blocks * 0x10); + } + + /* setup directory support */ + sm->dir_offset=0; + sm->root = malloc (sizeof(mpio_directory_t)); + sm->root->name[0] = 0; + sm->root->next = NULL; + sm->root->prev = NULL; + sm->cdir = sm->root; +} + +mpio_t * +mpio_init(mpio_callback_init_t progress_callback) +{ + mpio_t *new_mpio; + mpio_smartmedia_t *sm; + int id_offset; + BYTE i; + + new_mpio = malloc(sizeof(mpio_t)); + if (!new_mpio) { + debug ("Error allocating memory for mpio_t"); + return NULL; + } + memset(new_mpio, 0, sizeof(mpio_t)); + + new_mpio->fd = open(MPIO_DEVICE, O_RDWR); + + if (new_mpio->fd < 0) { + _mpio_errno = MPIO_ERR_DEVICE_NOT_READY; + return NULL; + } + + /* Read Version Information */ + mpio_io_version_read(new_mpio, new_mpio->version); + + /* fill in values */ + snprintf(new_mpio->firmware.id, 12, "%s", new_mpio->version); + /* fix for newer versions which have a 0x00 in their version */ + for (i=0x0c ; i<0x10 ; i++) + if (new_mpio->version[i] == 0x00) + new_mpio->version[i]=' '; + 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); + + /* there are different identification strings! */ + if (strncmp(new_mpio->version, "MPIO", 4) == 0) { + /* strings: "MPIOxy " */ + id_offset = 4; + + /* string: "MPIO-xy " */ + if (new_mpio->version[id_offset] == '-') + id_offset++; + + /* identify different versions */ + switch (new_mpio->version[id_offset]) + { + case 'E': + new_mpio->model = MPIO_MODEL_DME; + break ; + case 'K': + new_mpio->model = MPIO_MODEL_DMK; + break ; + case 'G': + new_mpio->model = MPIO_MODEL_DMG; + if (new_mpio->version[id_offset+1] == 'P') + new_mpio->model = MPIO_MODEL_DMG_PLUS; + break ; + case 'B': + new_mpio->model = MPIO_MODEL_DMB; + if (new_mpio->version[id_offset+1] == 'P') + new_mpio->model = MPIO_MODEL_DMB_PLUS; + break; + default: + new_mpio->model = MPIO_MODEL_UNKNOWN; + } + } else if (strncmp(new_mpio->version, "FD100", 5) == 0) { + new_mpio->model = MPIO_MODEL_FD100; + } else if (strncmp(new_mpio->version, "FL100", 5) == 0) { + /* we assume this model is not supported */ + new_mpio->model = MPIO_MODEL_FL100; + debug("FL100 found: External memory is ignored, because we don't know how" + " to support it at the moment (MultiMediaCards instead of SmartMedia)\n"); + } else if (strncmp(new_mpio->version, "FY100", 5) == 0) { + new_mpio->model = MPIO_MODEL_FY100; + /* I assume this is like the FD100/FL100, I didn't had the chance to + look at a FY100 firmware yet. -mager */ + debug("FY100 found: Beware, this model is not tested and we don't know" + " if it does work!\n"); + } else { + new_mpio->model = MPIO_MODEL_UNKNOWN; + } + + if (new_mpio->model == MPIO_MODEL_UNKNOWN) { + debug("Unknown version string found!\n" + "Please report this to: mpio-devel@lists.sourceforge.net\n"); + hexdumpn(1, new_mpio->version, CMD_SIZE); + } + + /* internal init */ + mpio_init_internal(new_mpio); + + /* external init */ + mpio_init_external(new_mpio); + + /* read FAT/spare area */ + if (new_mpio->internal.id) + mpio_fat_read(new_mpio, MPIO_INTERNAL_MEM, progress_callback); + + /* read the spare area (for block mapping) */ + if (new_mpio->external.id) + { + sm = &new_mpio->external; + mpio_io_spare_read(new_mpio, MPIO_EXTERNAL_MEM, 0, + sm->size, 0, sm->spare, + (sm->max_blocks * 0x10), progress_callback); + mpio_zone_init(new_mpio, MPIO_EXTERNAL_MEM); + + /* card might be defect */ + if (mpio_bootblocks_read(new_mpio, MPIO_EXTERNAL_MEM)==0) + { + sm->fat = malloc(SECTOR_SIZE*sm->fat_size); + mpio_fat_read(new_mpio, MPIO_EXTERNAL_MEM, NULL); + mpio_rootdir_read(new_mpio, MPIO_EXTERNAL_MEM); + } + } + + /* set default charset for filename conversion */ + new_mpio->charset=strdup(MPIO_CHARSET); + + /* disable ID3 rewriting support */ + new_mpio->id3=0; + strncpy(new_mpio->id3_format, MPIO_ID3_FORMAT, INFO_LINE); + new_mpio->id3_temp[0]=0x00; + + 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) +{ + if (mem==MPIO_INTERNAL_MEM) { + if (!m->internal.size) { + *free=0; + return 0; + } + *free=mpio_fat_free_clusters(m, mem); + return (m->internal.geo.SumSector + * SECTOR_SIZE / 1000 * m->internal.chips); + } + + if (mem==MPIO_EXTERNAL_MEM) { + if (!m->external.size) { + *free=0; + return 0; + } + *free=mpio_fat_free_clusters(m, mem); + return (m->external.geo.SumSector * SECTOR_SIZE / 1000); + } + + return 0; +} + +void +mpio_close(mpio_t *m) +{ + if (m) { + close(m->fd); + + if(m->internal.fat) + free(m->internal.fat); + if(m->external.fat) + free(m->external.fat); + + free(m); + } +} + +mpio_model_t +mpio_get_model(mpio_t *m) +{ + mpio_model_t r; + + if (m) + { + r = m->model; + } else { + r = MPIO_MODEL_UNKNOWN; + } + + return r; +} + +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); + snprintf(info->model, max, "%s", mpio_model_name[m->model]); + + if (!m->internal.id) + { + snprintf(info->mem_internal, max, "not available"); + } else { + if (m->internal.chips == 1) + { + snprintf(info->mem_internal, max, "%3dMB (%s)", + mpio_id2mem(m->internal.id), + mpio_id2manufacturer(m->internal.manufacturer)); + } else { + snprintf(info->mem_internal, max, "%3dMB (%s) - %d chips", + mpio_id2mem(m->internal.id)*m->internal.chips, + mpio_id2manufacturer(m->internal.manufacturer), + m->internal.chips); + } + } + + if (m->external.id) + { + snprintf(info->mem_external, max, "%3dMB (%s)", + mpio_id2mem(m->external.id), + mpio_id2manufacturer(m->external.manufacturer)); + } else { + snprintf(info->mem_external, max, "not available"); + } + +} + + +int +mpio_file_get_as(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_filename_t as, mpio_callback_t progress_callback) +{ + return mpio_file_get_real(m, mem, filename, as, progress_callback, NULL); +} + +int +mpio_file_get(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_callback_t progress_callback) +{ + return mpio_file_get_real(m, mem, filename, NULL, progress_callback, NULL); +} + +int +mpio_file_get_to_memory(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_callback_t progress_callback, BYTE **memory) +{ + return mpio_file_get_real(m, mem, filename, NULL, progress_callback, memory); +} + +int +mpio_file_get_real(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_filename_t as, mpio_callback_t progress_callback, + BYTE **memory) +{ + mpio_smartmedia_t *sm; + BYTE block[BLOCK_SIZE]; + int fd, towrite; + BYTE *p; + mpio_fatentry_t *f = 0; + struct utimbuf utbuf; + long mtime; + DWORD filesize, fsize; + BYTE abort = 0; + int merror; + + MPIO_CHECK_FILENAME(filename); + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if(as==NULL) { + as = filename; + } + + /* find file */ + p = mpio_dentry_find_name(m, mem, filename); + if (!p) + p = mpio_dentry_find_name_8_3(m, mem, filename); + + if (p) + f = mpio_dentry_get_startcluster(m, mem, p); + + if (f && p) { + filesize=fsize=mpio_dentry_get_filesize(m, mem, p); + + if (memory) + { + *memory = malloc(filesize); + } else { + unlink(filename); + fd = open(as, (O_RDWR | O_CREAT), (S_IRWXU | S_IRGRP | S_IROTH)); + } + + do + { + mpio_io_block_read(m, mem, f, block); + + if (filesize > BLOCK_SIZE) { + towrite = BLOCK_SIZE; + } else { + towrite = filesize; + } + + if (memory) + { + memcpy((*memory)+(fsize-filesize) , block, towrite); + } else { + if (write(fd, block, towrite) != towrite) { + debug("error writing file data\n"); + close(fd); + free (f); + MPIO_ERR_RETURN(MPIO_ERR_WRITING_FILE); + } + } + + filesize -= towrite; + + if (progress_callback) + abort=(*progress_callback)((fsize-filesize), fsize); + if (abort) + debug("aborting operation"); + + } while ((((merror=(mpio_fatentry_next_entry(m, mem, f)))>0) && + (filesize>0)) && (!abort)); + + if (merror<0) + debug("defective block encountered!\n"); + + if(!memory) + { + close (fd); + free (f); + } + + /* read and copied code from mtools-3.9.8/mcopy.c + * to make this one right + */ + mtime=mpio_dentry_get_time(m, mem, p); + utbuf.actime = mtime; + utbuf.modtime = mtime; + utime(filename, &utbuf); + + } else { + debugn(2, "unable to locate the file: %s\n", filename); + _mpio_errno=MPIO_ERR_FILE_NOT_FOUND; + } + + return (fsize-filesize); +} + +int +mpio_file_put_as(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_filename_t as, mpio_filetype_t filetype, + mpio_callback_t progress_callback) +{ + return mpio_file_put_real(m, mem, filename, as, filetype, + progress_callback, NULL,0); +} + +int +mpio_file_put(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_filetype_t filetype, mpio_callback_t progress_callback) +{ + return mpio_file_put_real(m, mem, filename, NULL, filetype, + progress_callback, NULL,0); +} + +int +mpio_file_put_from_memory(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_filetype_t filetype, + mpio_callback_t progress_callback, + BYTE *memory, int memory_size) +{ + return mpio_file_put_real(m, mem, filename, NULL, filetype, + progress_callback, memory, memory_size); +} + +int +mpio_file_put_real(mpio_t *m, mpio_mem_t mem, mpio_filename_t i_filename, + mpio_filename_t o_filename, mpio_filetype_t filetype, + mpio_callback_t progress_callback, + BYTE *memory, int memory_size) +{ + mpio_smartmedia_t *sm; + mpio_fatentry_t *f, current, firstblock, backup; + WORD start; + BYTE block[BLOCK_SIZE]; + BYTE use_filename[INFO_LINE]; + int fd, toread; + struct stat file_stat; + struct tm tt; + time_t curr; + int id3; + + BYTE *p = NULL; + DWORD filesize, fsize, free, blocks; + BYTE abort = 0; + + if(o_filename == NULL) { + o_filename = i_filename; + } + + MPIO_CHECK_FILENAME(o_filename); + + if (mem==MPIO_INTERNAL_MEM) sm=&m->internal; + if (mem==MPIO_EXTERNAL_MEM) sm=&m->external; + + if (memory) + { + fsize=filesize=memory_size; + } else { + id3 = mpio_id3_do(m, i_filename, use_filename); + if (!id3) + strncat(use_filename, i_filename, INFO_LINE); + if (stat((const char *)use_filename, &file_stat)!=0) { + debug("could not find file: %s\n", use_filename); + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + } + fsize=filesize=file_stat.st_size; + debugn(2, "filesize: %d\n", fsize); + } + + /* check if there is enough space left */ + mpio_memory_free(m, mem, &free); + if (free*1024<fsize) { + debug("not enough space left (only %d KB)\n", free); + MPIO_ERR_RETURN(MPIO_ERR_NOT_ENOUGH_SPACE); + } + + /* check if filename already exists */ + p = mpio_dentry_find_name(m, mem, o_filename); + if (!p) + p = mpio_dentry_find_name_8_3(m, mem, o_filename); + if (p) + { + debug("filename already exists\n"); + MPIO_ERR_RETURN(MPIO_ERR_FILE_EXISTS); + } + + /* find first free sector */ + f = mpio_fatentry_find_free(m, mem, filetype); + if (!f) + { + debug("could not free cluster for file!\n"); + MPIO_ERR_RETURN(MPIO_ERR_FAT_ERROR); + } else { + memcpy(&firstblock, f, sizeof(mpio_fatentry_t)); + start=f->entry; + } + + /* find file-id for internal memory */ + if (mem==MPIO_INTERNAL_MEM) + { + f->i_index=mpio_fat_internal_find_fileindex(m); + debugn(2, "fileindex: %02x\n", f->i_index); + f->i_fat[0x01]= f->i_index; + if (m->model >= MPIO_MODEL_FD100) + f->i_fat[0x0e] = f->i_index; + start = f->i_index; + + /* number of blocks needed for file */ + blocks = filesize / 0x4000; + if (filesize % 0x4000) + blocks++; + debugn(2, "blocks: %02x\n", blocks); + f->i_fat[0x02]=(blocks / 0x100) & 0xff; + f->i_fat[0x03]= blocks & 0xff; + } + + if (!memory) + { + /* open file for reading */ + fd = open(use_filename, O_RDONLY); + if (fd==-1) + { + debug("could not open file: %s\n", use_filename); + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + } + } + + while ((filesize>BLOCK_SIZE) && (!abort)) { + + if (filesize>=BLOCK_SIZE) { + toread=BLOCK_SIZE; + } else { + toread=filesize; + } + + if (memory) + { + memcpy(block, memory+(fsize-filesize), toread); + } else { + if (read(fd, block, toread)!=toread) { + debug("error reading file data\n"); + close(fd); + MPIO_ERR_RETURN(MPIO_ERR_READING_FILE); + } + } + filesize -= toread; + + /* get new free block from FAT and write current block out */ + memcpy(¤t, f, sizeof(mpio_fatentry_t)); + if (!(mpio_fatentry_next_free(m, mem, f))) + { + debug ("Found no free cluster during mpio_file_put\n" + "This should never happen\n"); + exit(-1); + } + mpio_fatentry_set_next(m ,mem, ¤t, f); + mpio_io_block_write(m, mem, ¤t, block); + + if (progress_callback) + abort=(*progress_callback)((fsize-filesize), fsize); + } + + /* handle the last block to write */ + + if (filesize>=BLOCK_SIZE) { + toread=BLOCK_SIZE; + } else { + toread=filesize; + } + + if (memory) + { + memcpy(block, memory+(fsize-filesize), toread); + } else { + if (read(fd, block, toread)!=toread) { + debug("error reading file data\n"); + close(fd); + MPIO_ERR_RETURN(MPIO_ERR_READING_FILE); + } + } + filesize -= toread; + + /* mark end of FAT chain and write last block */ + mpio_fatentry_set_eof(m ,mem, f); + mpio_io_block_write(m, mem, f, block); + + if (!memory) + close(fd); + + if (progress_callback) + (*progress_callback)((fsize-filesize), fsize); + + if (abort) + { /* delete the just written blocks, because the user + * aborted the operation + */ + debug("aborting operation\n"); + debug("removing already written blocks\n"); + + filesize=fsize; + + memcpy(¤t, &firstblock, sizeof(mpio_fatentry_t)); + memcpy(&backup, &firstblock, sizeof(mpio_fatentry_t)); + + while (mpio_fatentry_next_entry(m, mem, ¤t)) + { + mpio_io_block_delete(m, mem, &backup); + mpio_fatentry_set_free(m, mem, &backup); + memcpy(&backup, ¤t, sizeof(mpio_fatentry_t)); + + if (filesize > BLOCK_SIZE) + { + filesize -= BLOCK_SIZE; + } else { + filesize -= filesize; + } + + if (progress_callback) + (*progress_callback)((fsize-filesize), fsize); + } + mpio_io_block_delete(m, mem, &backup); + mpio_fatentry_set_free(m, mem, &backup); + + if (filesize > BLOCK_SIZE) + { + filesize -= BLOCK_SIZE; + } else { + filesize -= filesize; + } + + if (progress_callback) + (*progress_callback)((fsize-filesize), fsize); + + } else { + if (memory) + { + time(&curr); + tt = * localtime(&curr); + } + mpio_dentry_put(m, mem, + o_filename, strlen(o_filename), + ((memory)?mktime(&tt):file_stat.st_ctime), + fsize, start, 0x20); + } + + mpio_id3_end(m); + + return fsize-filesize; +} + +int +mpio_file_switch(mpio_t *m, mpio_mem_t mem, + mpio_filename_t file1, mpio_filename_t file2) +{ + BYTE *p1, *p2; + + /* find files */ + p1 = mpio_dentry_find_name(m, mem, file1); + if (!p1) + p1 = mpio_dentry_find_name_8_3(m, mem, file1); + + p2 = mpio_dentry_find_name(m, mem, file2); + if (!p2) + p2 = mpio_dentry_find_name_8_3(m, mem, file2); + + if ((!p1) || (!p2)) + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + + mpio_dentry_switch(m, mem, p1, p2); + + return 0; +} + +int +mpio_file_rename(mpio_t *m, mpio_mem_t mem, + mpio_filename_t old, mpio_filename_t new) +{ + BYTE *p; + + /* find files */ + p = mpio_dentry_find_name(m, mem, old); + if (!p) + p = mpio_dentry_find_name_8_3(m, mem, old); + + if (!p) + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + + mpio_dentry_rename(m, mem, p, new); + + return 0; +} + +int mpio_file_move(mpio_t *m,mpio_mem_t mem, mpio_filename_t file, + mpio_filename_t after) +{ + BYTE *p1,*p2; + + if( ( p1 = mpio_dentry_find_name(m,mem,file)) == NULL ) { + if( (p1 = mpio_dentry_find_name_8_3(m, mem, file)) == NULL ) { + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + } + } + + if(after!=NULL) { + if( ( p2 = mpio_dentry_find_name(m,mem,after)) == NULL ) { + if( (p2 = mpio_dentry_find_name_8_3(m, mem, after)) == NULL ) { + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + } + } + } + + fprintf(stderr," -- moving '%s' after '%s'\n",file,after); + + mpio_dentry_move(m,mem,p1,p2); + + return 0; +} + +int +mpio_memory_format(mpio_t *m, mpio_mem_t mem, + mpio_callback_t progress_callback) +{ + int data_offset; + mpio_smartmedia_t *sm; + mpio_fatentry_t *f; + DWORD clusters; + BYTE abort = 0; + BYTE *cis, *mbr, *pbr; + BYTE defect[SECTOR_SIZE]; + int i; + + if (mem == MPIO_INTERNAL_MEM) + { + sm=&m->internal; + data_offset = 0x01; + } + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->external; + data_offset = 0x02; + } + + clusters = sm->size*128; + + + /* TODO: read and write "Config.dat" so the player does not become "dumb" */ + if (mem==MPIO_INTERNAL_MEM) + { + /* clear the fat before anything else, so we can mark clusters defective + * if we found a bad block + */ + /* external mem must be handled diffrently, + * see comment(s) below! + */ + mpio_fat_clear(m, mem); + f = mpio_fatentry_new(m, mem, data_offset, FTYPE_MUSIC); + do + { + + if (!mpio_io_block_delete(m, mem, f)) + mpio_fatentry_set_defect(m, mem, f); + + if (progress_callback) + { + if (!abort) + { + abort=(*progress_callback)(f->entry, sm->max_cluster + 1); + if (abort) + debug("received abort signal, but ignoring it!\n"); + } else { + (*progress_callback)(f->entry, sm->max_cluster + 1); + } + } + + } while (mpio_fatentry_plus_plus(f)); + free(f); + } + + if (mem == MPIO_EXTERNAL_MEM) { + /* delete all blocks! */ + + i=0; + while (i < sm->max_blocks) + { + mpio_io_block_delete_phys(m, mem, (i * BLOCK_SECTORS)); + i++; + + if (progress_callback) + { + if (!abort) + { + abort=(*progress_callback)(i, sm->max_blocks); + if (abort) + debug("received abort signal, but ignoring it!\n"); + } else { + (*progress_callback)(i, sm->max_blocks); + } + } + + + } + + /* generate "defect" first block */ + mpio_io_sector_write(m, mem, MPIO_BLOCK_DEFECT, defect); + + /* format CIS area */ + f = mpio_fatentry_new(m, mem, MPIO_BLOCK_CIS, FTYPE_MUSIC); + /* mpio_io_block_delete(m, mem, f); */ + free(f); + cis = (BYTE *)mpio_cis_gen(); /* hmm, why this cast? */ + mpio_io_sector_write(m, mem, MPIO_BLOCK_CIS, cis); + mpio_io_sector_write(m, mem, MPIO_BLOCK_CIS+1, cis); + free(cis); + + /* generate boot blocks ... */ + mbr = (BYTE *)mpio_mbr_gen(m->external.size); + pbr = (BYTE *)mpio_pbr_gen(m->external.size); + /* ... copy the blocks to internal memory structurs ... */ + memcpy(sm->cis, cis, SECTOR_SIZE); + memcpy(sm->mbr, mbr, SECTOR_SIZE); + memcpy(sm->pbr, pbr, SECTOR_SIZE); + /* ... and set internal administration accordingly */ + mpio_mbr_eval(sm); + mpio_pbr_eval(sm); + + if (!sm->fat) /* perhaps we have to build a new FAT */ + sm->fat=malloc(sm->fat_size*SECTOR_SIZE); + mpio_fat_clear(m, mem); + + /* TODO: for external memory we have to work a little "magic" + * to identify and mark "bad blocks" (because we have a set of + * spare ones! + */ + } + + mpio_rootdir_clear(m, mem); + + /* this writes the FAT *and* the root directory */ + mpio_fat_write(m, mem); + + if (progress_callback) + (*progress_callback)(sm->max_cluster+1, sm->max_cluster+1); + + return 0; +} + +int +mpio_file_del(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_callback_t progress_callback) +{ + BYTE *p; + mpio_smartmedia_t *sm; + mpio_fatentry_t *f, backup; + DWORD filesize, fsize; + BYTE abort=0; + + MPIO_CHECK_FILENAME(filename); + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if ((strcmp(filename, "..") == 0) || + (strcmp(filename, ".") == 0)) + { + debugn(2, "directory name not allowed: %s\n", filename); + MPIO_ERR_RETURN(MPIO_ERR_DIR_NAME_ERROR); + } + + /* find file */ + p = mpio_dentry_find_name(m, mem, filename); + if (!p) + p = mpio_dentry_find_name_8_3(m, mem, filename); + + if (p) + f = mpio_dentry_get_startcluster(m, mem, p); + + if (f && p) { + if (mpio_dentry_is_dir(m, mem, p) == MPIO_OK) + { + /* ugly */ + mpio_directory_cd(m, mem, filename); + if (mpio_directory_is_empty(m, mem, sm->cdir) != MPIO_OK) + { + mpio_directory_cd(m, mem, ".."); + MPIO_ERR_RETURN(MPIO_ERR_DIR_NOT_EMPTY); + } else { + mpio_directory_cd(m, mem, ".."); + } + } + + filesize=fsize=mpio_dentry_get_filesize(m, mem, p); + do + { + debugn(2, "sector: %4x\n", f->entry); + + mpio_io_block_delete(m, mem, f); + + if (filesize != fsize) + mpio_fatentry_set_free(m, mem, &backup); + + memcpy(&backup, f, sizeof(mpio_fatentry_t)); + + if (filesize > BLOCK_SIZE) + { + filesize -= BLOCK_SIZE; + } else { + filesize -= filesize; + } + + if (progress_callback) + { + if (!abort) + { + abort=(*progress_callback)((fsize-filesize), fsize); + if (abort) + debug("received abort signal, but ignoring it!\n"); + } else { + (*progress_callback)((fsize-filesize), fsize); + } + } + + } while (mpio_fatentry_next_entry(m, mem, f)); +/* mpio_io_block_delete(m, mem, &backup); */ + mpio_fatentry_set_free(m, mem, &backup); + free(f); + + } else { + debugn(2, "unable to locate the file: %s\n", filename); + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + } + + mpio_dentry_delete(m, mem, filename); + + return MPIO_OK; +} + +int +mpio_sync(mpio_t *m, mpio_mem_t mem) +{ + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if (!sm->size) + return 0; + + /* this writes the FAT *and* the root directory */ + return mpio_fat_write(m, mem); +} + +int +mpio_health(mpio_t *m, mpio_mem_t mem, mpio_health_t *r) +{ + mpio_smartmedia_t *sm; + int i, j, zones; + mpio_fatentry_t *f; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + r->num = sm->chips; + + f = mpio_fatentry_new(m, mem, 0x00, FTYPE_MUSIC); + + for (i=0 ; i < sm->chips; i++) + { + r->data[i].spare = 0; + r->data[i].total = (sm->max_cluster / sm->chips); + r->data[i].broken = 0; + /* now count the broken blocks */ + for(j=0; j<r->data[i].total; j++) + { + if (mpio_fatentry_is_defect(m, mem, f)) + r->data[i].broken++; + mpio_fatentry_plus_plus(f); + } + } + + free(f); + + return MPIO_OK; + } + + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->external; + + zones = sm->max_cluster / MPIO_ZONE_LBLOCKS + 1; + r->num = zones; + + for(i=0; i<zones; i++) + { + r->data[i].spare = (i?24:22); /* first zone has only 23 due to CIS */ + r->data[i].total = MPIO_ZONE_PBLOCKS; + r->data[i].broken = 0; + /* now count the broken blocks */ + for(j=0; j<MPIO_ZONE_PBLOCKS; j++) + { + if (!i && !j) + continue; /* ignore "defective" first block */ + if (sm->zonetable[i][j] == MPIO_BLOCK_DEFECT) + r->data[i].broken++; + } + if (r->data[i].spare < r->data[i].broken) + debug("(spare blocks<broken blocks) -> expect trouble!\n"); + } + return MPIO_OK; + } + + return MPIO_ERR_INTERNAL; +} + +int +mpio_memory_dump(mpio_t *m, mpio_mem_t mem) +{ + BYTE block[BLOCK_SIZE]; + int i; + + if (mem == MPIO_INTERNAL_MEM) + { + hexdump(m->internal.fat, m->internal.max_blocks*0x10); + hexdump(m->internal.root->dir, DIR_SIZE); + } + + if (mem == MPIO_EXTERNAL_MEM) + { + hexdump(m->external.spare, m->external.max_blocks*0x10); + hexdump(m->external.fat, m->external.fat_size*SECTOR_SIZE); + hexdump(m->external.root->dir, DIR_SIZE); + } + + for (i = 0 ; i<=0x100 ; i++) + mpio_io_sector_read(m, mem, i, block); + + return 0; +} + +int +mpio_errno(void) +{ + int no = _mpio_errno; + _mpio_errno = 0; + + return no; +} + +char * +mpio_strerror(int err) +{ + int i; + + if (err >= 0) return NULL; + + for (i = 0; i < mpio_error_num; i++) { + if (mpio_errors[i].id == err) + return mpio_errors[i].msg; + } + + return NULL; +} + +void +mpio_perror(char *prefix) +{ + char *msg = mpio_strerror(_mpio_errno); + + if (msg == NULL) return; + + if (prefix) + fprintf(stderr, "%s: %s\n", prefix, msg); + else + fprintf(stderr, "%s\n", msg); +} diff --git a/libmpio/src/mpio.h b/libmpio/src/mpio.h new file mode 100644 index 0000000..1d5ba3c --- /dev/null +++ b/libmpio/src/mpio.h @@ -0,0 +1,218 @@ +#/* -*- linux-c -*- */ + +/* + * $Id: mpio.h,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. + * + * */ + +#ifndef _MPIO_H_ +#define _MPIO_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> + +#include "defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + *init and shutdown + */ + +mpio_t *mpio_init(mpio_callback_init_t); +void mpio_close(mpio_t *); + +/* + * request information + */ + +/* get version */ +void mpio_get_info(mpio_t *, mpio_info_t *); +/* get model */ +mpio_model_t mpio_get_model(mpio_t *); +/* retrieves free memory in bytes */ +int mpio_memory_free(mpio_t *, mpio_mem_t, int *free); + +/* + * charset for filename encoding/converting + */ +BYTE *mpio_charset_get(mpio_t *); +BYTE mpio_charset_set(mpio_t *, BYTE *); + +/* + * directory operations + */ + +/* context, memory bank */ +BYTE* mpio_directory_open(mpio_t *, mpio_mem_t); +/* context, memory bank, directory name */ +int mpio_directory_make(mpio_t *, mpio_mem_t, BYTE *); +/* context, memory bank, directory name */ +int mpio_directory_cd(mpio_t *, mpio_mem_t, BYTE *); +/* context, memory bank, directory name buffer space */ +void mpio_directory_pwd(mpio_t *, mpio_mem_t, BYTE pwd[INFO_LINE]); +/* context, dir context */ +BYTE* mpio_dentry_next(mpio_t *, mpio_mem_t, BYTE *); +/* context, dir context */ +int mpio_dentry_get(mpio_t *, mpio_mem_t, BYTE *, BYTE *, int,WORD *, + BYTE *, BYTE *, BYTE *, BYTE *, DWORD *, BYTE *); + +/* + * reading/writing/deleting of files + */ + +int mpio_file_get_as(mpio_t *, mpio_mem_t, mpio_filename_t, + mpio_filename_t,mpio_callback_t); + +/* context, memory bank, filename, callback */ +int mpio_file_get(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_callback_t); + +/* context, memory bank, filename, filetype, callback */ +int mpio_file_put(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_filetype_t, + mpio_callback_t); + +/* context, memory bank, filename, as, filetype, callback */ +int mpio_file_put_as(mpio_t *, mpio_mem_t, mpio_filename_t, + mpio_filename_t, mpio_filetype_t, + mpio_callback_t); + +/* context, memory bank, filename, callback */ +int mpio_file_del(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_callback_t); + +/* + * reading/writing files into memory (used for config+font files) + */ + +/* context, memory bank, filename, callback, pointer to memory */ +/* the needed memory is allocated and the memory pointer is return */ +/* via the "BYTE **" */ + +int mpio_file_get_to_memory(mpio_t *, mpio_mem_t, mpio_filename_t, + mpio_callback_t, BYTE **); + +/* context, memory bank, filename, filetype, callback ... */ +/* ... memory pointer, size of file */ +int mpio_file_put_from_memory(mpio_t *, mpio_mem_t, mpio_filename_t, + mpio_filetype_t, mpio_callback_t, + BYTE *, int); + +/* + * rename a file on the MPIO + */ +/* context, memory bank, filename, filename */ +int mpio_file_rename(mpio_t *, mpio_mem_t, + mpio_filename_t, mpio_filename_t); + +/* + * switch position of two files + */ +/* context, memory bank, filename, filename */ +int mpio_file_switch(mpio_t *, mpio_mem_t, + mpio_filename_t, mpio_filename_t); + +/* Move a named file after a given file. If after==NULL move it + to the top of the list, +*/ + +int mpio_file_move(mpio_t *,mpio_mem_t m,mpio_filename_t,mpio_filename_t); + +/* + * formating a memory (internal mem or external SmartMedia card) + */ + +/* context, memory bank, callback */ +int mpio_memory_format(mpio_t *, mpio_mem_t, mpio_callback_t); + +/* mpio_sync has to be called after every set of mpio_file_{del,put} + * operations to write the current state of FAT and (root) directory. + * This is done explicitly to avoid writing these informations to often + * and thereby exhausting the SmartMedia chips + */ +/* context, memory bank */ +int mpio_sync(mpio_t *, mpio_mem_t); + +/* + * ID3 rewriting support + */ + +/* enable disable ID3 rewriting support */ +BYTE mpio_id3_set(mpio_t *, BYTE); +/* query ID3 rewriting support */ +BYTE mpio_id3_get(mpio_t *); + +/* set format string for rewriting*/ +void mpio_id3_format_set(mpio_t *, BYTE *); +/* get format string for rewriting*/ +void mpio_id3_format_get(mpio_t *, BYTE *); + +/* + * "special" functions + */ + +/* returns health status of selected memory */ +int mpio_health(mpio_t *, mpio_mem_t, mpio_health_t *); + +/* + * error handling + */ + +/* returns error code of last error */ +int mpio_errno(void); + +/* returns the description of the error <errno> */ +char * mpio_strerror(int err); + +/* prints the error message of the last error*/ +void mpio_perror(char *prefix); + +/* + * debugging + */ + +/* context, memory bank */ +int mpio_memory_dump(mpio_t *, mpio_mem_t); + +/* + * timeline: + * --------- + * 2004: some functions to change the order of files + * 2005: read mp3 tags of the files + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MPIO_H_ */ + + diff --git a/libmpio/src/smartmedia.c b/libmpio/src/smartmedia.c new file mode 100644 index 0000000..9b70108 --- /dev/null +++ b/libmpio/src/smartmedia.c @@ -0,0 +1,153 @@ +/* -*- linux-c -*- */ + +/* + * + * $Id: smartmedia.c,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * + * 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 <stdio.h> +#include <stdlib.h> + +#include "smartmedia.h" +#include "debug.h" + +mpio_disk_phy_t MPIO_DISK_GEO_001={ 125, 4, 4, 2000 }; +mpio_disk_phy_t MPIO_DISK_GEO_002={ 125, 4, 8, 4000 }; +mpio_disk_phy_t MPIO_DISK_GEO_004={ 250, 4, 8, 8000 }; +mpio_disk_phy_t MPIO_DISK_GEO_008={ 250, 4, 16, 16000 }; +mpio_disk_phy_t MPIO_DISK_GEO_016={ 500, 4, 16, 32000 }; +mpio_disk_phy_t MPIO_DISK_GEO_032={ 500, 8, 16, 64000 }; +mpio_disk_phy_t MPIO_DISK_GEO_064={ 500, 8, 32, 128000 }; +mpio_disk_phy_t MPIO_DISK_GEO_128={ 500,16, 32, 256000 }; + +/* This comes from the Samsung documentation files */ + +/* a small warning: only use this function (mpio_id2mem) in the very + * beginning of MPIO model detection. After that use the values + * of size and chips! -mager + */ + +int +mpio_id2mem(BYTE id) +{ + int i=0; + + switch(id) + { + case 0xea: + i=2; + break; + case 0xe3: /* Samsung */ + case 0xe5: /* Toshiba */ + i=4; + break; + case 0xe6: + i=8; + break; + case 0x73: + i=16; + break; + case 0x75: + i=32; + break; + case 0x76: + i=64; + break; + case 0x79: + i=128; + break; + default: + debug("This should never happen (id2mem)!\n"); + exit (1); + } + return i; +} + +BYTE * +mpio_id2manufacturer(BYTE id) +{ + BYTE *m; + switch(id) + { + case 0xec: + m="Samsung"; + break; + case 0x98: + m="Toshiba"; + break; + default: + m="unknown"; + } + return m; +} + +BYTE +mpio_id_valid(BYTE id) +{ + switch(id) + { + case 0xec: /* Samsung */ + case 0x98: /* Toshiba */ + return 1; + default: + ; + } + + return 0; +} + +void +mpio_id2geo(BYTE id, mpio_disk_phy_t *geo) +{ + switch(id) + { + case 0xea: + *geo = MPIO_DISK_GEO_002; + break; + case 0xe3: /* Samsung */ + case 0xe5: /* Toshiba */ + *geo = MPIO_DISK_GEO_004; + break; + case 0xe6: + *geo = MPIO_DISK_GEO_008; + break; + case 0x73: + *geo = MPIO_DISK_GEO_016; + break; + case 0x75: + *geo = MPIO_DISK_GEO_032; + break; + case 0x76: + *geo = MPIO_DISK_GEO_064; + break; + case 0x79: + *geo = MPIO_DISK_GEO_128; + break; + default: + debug("This should never happen!\n"); + exit (1); + } + + return; +} diff --git a/libmpio/src/smartmedia.h b/libmpio/src/smartmedia.h new file mode 100644 index 0000000..57f3e3e --- /dev/null +++ b/libmpio/src/smartmedia.h @@ -0,0 +1,47 @@ +/* -*- linux-c -*- */ + +/* + * + * $Id: smartmedia.h,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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. + * + * */ + +#ifndef _MPIO_SMARTMEDIA_H_ +#define _MPIO_SMARTMEDIA_H_ + +#include "defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* get our configuration for SmartMedia cards right */ +int mpio_id2mem (BYTE); +BYTE * mpio_id2manufacturer(BYTE); +void mpio_id2geo(BYTE, mpio_disk_phy_t *); +BYTE mpio_id_valid(BYTE); + +#ifdef __cplusplus +} +#endif + +#endif /* _MPIO_SMARTMEDIA_H_ */ |