aboutsummaryrefslogtreecommitdiff
path: root/libmpio/src
diff options
context:
space:
mode:
Diffstat (limited to 'libmpio/src')
-rw-r--r--libmpio/src/cis.c81
-rw-r--r--libmpio/src/cis.h42
-rw-r--r--libmpio/src/debug.c313
-rw-r--r--libmpio/src/debug.h110
-rw-r--r--libmpio/src/defs.h334
-rw-r--r--libmpio/src/directory.c1318
-rw-r--r--libmpio/src/directory.h84
-rw-r--r--libmpio/src/ecc.c247
-rw-r--r--libmpio/src/ecc.h44
-rw-r--r--libmpio/src/fat.c1039
-rw-r--r--libmpio/src/fat.h87
-rw-r--r--libmpio/src/id3.c292
-rw-r--r--libmpio/src/id3.h44
-rw-r--r--libmpio/src/io.c1213
-rw-r--r--libmpio/src/io.h95
-rw-r--r--libmpio/src/mpio.c1301
-rw-r--r--libmpio/src/mpio.h218
-rw-r--r--libmpio/src/smartmedia.c153
-rw-r--r--libmpio/src/smartmedia.h47
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(&current, 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, &current, f);
+ mpio_io_block_write(m, mem, &current, 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(&current, &firstblock, sizeof(mpio_fatentry_t));
+ memcpy(&backup, &firstblock, sizeof(mpio_fatentry_t));
+
+ while (mpio_fatentry_next_entry(m, mem, &current))
+ {
+ mpio_io_block_delete(m, mem, &backup);
+ mpio_fatentry_set_free(m, mem, &backup);
+ memcpy(&backup, &current, 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_ */