mirror of
https://github.com/gwenhael-le-moine/x49gp.git
synced 2024-12-26 21:58:41 +01:00
c61f11cff2
Misc changes, mostly fixes: - fix ./newconfig systems other than OSX (broke inc8b823f
) - fix palette usage in 2-bit color mode (was broken ever since grayscale was implemented in18e1003
and its improperly attributed copyf7913eb
) - fix continuing from breakpoints in the debugger (never worked, was exposed when the debugger was enabled in9c1f2ed
) - restore the printf statements commented out in9c1f2ed
and hide them with #ifdefs instead - close the server socket after accepting a debugger connection to allow another simultaneous debug session to be started using the same TCP port - use the symbolic constant DEFAULT_GDBSTUB_PORT (already defined in gdb_stub.h as 1234) when starting the gdb server in main.c in place of the raw number 1234 - change Makefile to read the name of the firmware file from the file update.scp instead of hardcoding it; this allows users to switch to another firmware by simply pasting it along with its accompanying update.scp into the x49gp directory - Enhance port G (keyboard) handling to remember the value of output bits across periods with these bits configured as input This fixes interaction with HPGCC3 keyboard routines, and it also fixes keys with eint==7 (assuming the stock firmware is in use) needing a double-tap to work unless pressed very shortly after another keypress (the latter broke inb5f93ed
) - Get rid of the deprecated function warning by switching from gdk_pixbuf_new_from_inline to gdk_pixbuf_new_from_data (based on code by chwdt) - Delete remaining now-redundant CVS files - Don't release all buttons anymore if there are still physical keys and/or the left mouse button are holding some down On the other hand, forcibly release all buttons when losing focus to avoid getting stuck in a state with buttons down when they are not held down by anything; this would happen due to missed events while not in focus - Add a context menu to the screen, containing only "Reset" and "Quit" items for now - Ensure that the files backing flash, sram, and s3c2410-sram exist and have the correct size when opening them Note that if the flash file does not exist, this will not fill it with the code that's supposed to be in there, obviously causing the calculator to crash. That's an improvement for later. - Allow the config system to fill not only numbers, but also strings (including filenames) with default values basename is excluded, but it's planned to be dropped entirely. - Add an "install" target to the Makefile - Implement a more generic command-line parser for substantially improved flexibility - Also adds a proper help option, though the manual referenced in the corresponding output (a manpage, hopefully) does not exist yet. - Drop the "basename" config property in favor of interpreting relative paths in the config as relative to the config file's location - Retire the "image" config property in favor of simply loading the image from next to the binary or from the install directory - Split the UI name property into name (affecting only the window title) and type (affecting the UI image and in the future also the default bootcode) properties - Change the default calculator type to the 50g everywhere, which probably matches today's user expectations better than the 49g+. - Create a flash file from the calculator model's appropriate boot file if it does not exist, relying on the bootcode to detect the absence of a firmware The bootcode will complain about the missing firmware and enter update mode, so the user needs to supply their favorite firmware version and point the bootcode's updater to it. The easiest way is probably pointing the emulated SD card at a directory containing the firmware and its accompanying update.scp file, and then starting the SD-based update. - Add SD mount / unmount options to the right-click / menu-key popup menu - Remove most of the old script-based config-generating system since the binary now has these capabilities as well - Add an applications menu item for installing - Keep some debug output on stderr and a huge vvfat.log file from showing up when not debugging x49gp itself - Allow (re-)connecting a debugger to a running session This is done through the right-click / menu-key popup menu. To avoid confusion due to the accidental clicks leading to an unresponsive interface (caused by waiting for the debugger to connect), this option is hidden unless option -d or its new companion -D (same as -d, but does not start the debug interface right away) is present. - Improved support for hardware keyboards - Update README.md, add manpage, rename other README files to TODO to reflect their contents
788 lines
16 KiB
C
788 lines
16 KiB
C
/* $Id: s3c2410_sdi.c,v 1.4 2008/12/11 12:18:17 ecd Exp $
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
|
|
#include <x49gp.h>
|
|
#include <s3c2410.h>
|
|
|
|
#include <block.h>
|
|
|
|
typedef struct {
|
|
uint32_t sdicon;
|
|
uint32_t sdipre;
|
|
uint32_t sdicarg;
|
|
uint32_t sdiccon;
|
|
uint32_t sdicsta;
|
|
uint32_t sdirsp0;
|
|
uint32_t sdirsp1;
|
|
uint32_t sdirsp2;
|
|
uint32_t sdirsp3;
|
|
uint32_t sdidtimer;
|
|
uint32_t sdibsize;
|
|
uint32_t sdidcon;
|
|
uint32_t sdidcnt;
|
|
uint32_t sdidsta;
|
|
uint32_t sdifsta;
|
|
uint32_t sdidat;
|
|
uint32_t sdiimsk;
|
|
|
|
unsigned int nr_regs;
|
|
s3c2410_offset_t *regs;
|
|
|
|
x49gp_t *x49gp;
|
|
|
|
char *filename;
|
|
BlockDriverState *bs;
|
|
int fd;
|
|
|
|
unsigned char *read_data;
|
|
uint32_t nr_read_data;
|
|
uint32_t read_offset;
|
|
unsigned int read_index;
|
|
|
|
unsigned char *write_data;
|
|
uint32_t nr_write_data;
|
|
uint32_t write_offset;
|
|
unsigned int write_index;
|
|
|
|
int multiple_block;
|
|
} s3c2410_sdi_t;
|
|
|
|
|
|
static int
|
|
s3c2410_sdi_data_init(s3c2410_sdi_t *sdi)
|
|
{
|
|
s3c2410_offset_t regs[] = {
|
|
S3C2410_OFFSET(SDI, SDICON, 0x00000000, sdi->sdicon),
|
|
S3C2410_OFFSET(SDI, SDIPRE, 0x00000000, sdi->sdipre),
|
|
S3C2410_OFFSET(SDI, SDICARG, 0x00000000, sdi->sdicarg),
|
|
S3C2410_OFFSET(SDI, SDICCON, 0x00000000, sdi->sdiccon),
|
|
S3C2410_OFFSET(SDI, SDICSTA, 0x00000000, sdi->sdicsta),
|
|
S3C2410_OFFSET(SDI, SDIRSP0, 0x00000000, sdi->sdirsp0),
|
|
S3C2410_OFFSET(SDI, SDIRSP1, 0x00000000, sdi->sdirsp1),
|
|
S3C2410_OFFSET(SDI, SDIRSP2, 0x00000000, sdi->sdirsp2),
|
|
S3C2410_OFFSET(SDI, SDIRSP3, 0x00000000, sdi->sdirsp3),
|
|
S3C2410_OFFSET(SDI, SDIDTIMER, 0x00002000, sdi->sdidtimer),
|
|
S3C2410_OFFSET(SDI, SDIBSIZE, 0x00000000, sdi->sdibsize),
|
|
S3C2410_OFFSET(SDI, SDIDCON, 0x00000000, sdi->sdidcon),
|
|
S3C2410_OFFSET(SDI, SDIDCNT, 0x00000000, sdi->sdidcnt),
|
|
S3C2410_OFFSET(SDI, SDIDSTA, 0x00000000, sdi->sdidsta),
|
|
S3C2410_OFFSET(SDI, SDIFSTA, 0x00000000, sdi->sdifsta),
|
|
S3C2410_OFFSET(SDI, SDIDAT, 0x00000000, sdi->sdidat),
|
|
S3C2410_OFFSET(SDI, SDIIMSK, 0x00000000, sdi->sdiimsk)
|
|
};
|
|
|
|
memset(sdi, 0, sizeof(s3c2410_sdi_t));
|
|
|
|
sdi->regs = malloc(sizeof(regs));
|
|
if (NULL == sdi->regs) {
|
|
fprintf(stderr, "%s:%u: Out of memory\n",
|
|
__FUNCTION__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
memcpy(sdi->regs, regs, sizeof(regs));
|
|
sdi->nr_regs = sizeof(regs) / sizeof(regs[0]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
sdcard_read(s3c2410_sdi_t *sdi)
|
|
{
|
|
uint32_t offset;
|
|
uint32_t size;
|
|
int error;
|
|
|
|
offset = sdi->read_offset;
|
|
size = sdi->nr_read_data;
|
|
|
|
#ifdef DEBUG_S3C2410_SDI
|
|
printf("SDI: card read %4u at %08x\n", size, offset);
|
|
#endif
|
|
|
|
sdi->nr_read_data = 0;
|
|
sdi->read_index = 0;
|
|
|
|
if ((sdi->fd < 0) && (sdi->bs == NULL)) {
|
|
return -ENODEV;
|
|
}
|
|
|
|
sdi->read_data = malloc(size);
|
|
if (NULL == sdi->read_data) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (sdi->bs) {
|
|
sdi->nr_read_data = bdrv_pread(sdi->bs, offset, sdi->read_data, size);
|
|
} else {
|
|
if (sdi->read_offset != lseek(sdi->fd, offset, SEEK_SET)) {
|
|
error = errno;
|
|
sdi->nr_read_data = 0;
|
|
free(sdi->read_data);
|
|
sdi->read_data = NULL;
|
|
return -error;
|
|
}
|
|
|
|
sdi->nr_read_data = read(sdi->fd, sdi->read_data, size);
|
|
}
|
|
|
|
if (sdi->nr_read_data != size) {
|
|
error = errno;
|
|
sdi->nr_read_data = 0;
|
|
free(sdi->read_data);
|
|
sdi->read_data = NULL;
|
|
return -error;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
sdcard_write_prepare(s3c2410_sdi_t *sdi)
|
|
{
|
|
sdi->write_index = 0;
|
|
|
|
if ((sdi->fd < 0) && (sdi->bs == NULL)) {
|
|
sdi->nr_write_data = 0;
|
|
return -ENODEV;
|
|
}
|
|
|
|
sdi->write_data = malloc(sdi->nr_write_data);
|
|
if (NULL == sdi->write_data) {
|
|
sdi->nr_write_data = 0;
|
|
return -ENOMEM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
sdcard_write(s3c2410_sdi_t *sdi)
|
|
{
|
|
uint32_t offset;
|
|
uint32_t size;
|
|
int error;
|
|
|
|
offset = sdi->write_offset;
|
|
size = sdi->nr_write_data;
|
|
|
|
#ifdef DEBUG_S3C2410_SDI
|
|
printf("SDI: card write %4u at %08x\n", size, offset);
|
|
#endif
|
|
|
|
sdi->write_index = 0;
|
|
|
|
if (sdi->bs) {
|
|
error = bdrv_pwrite(sdi->bs, offset, sdi->write_data, size);
|
|
} else {
|
|
if (sdi->fd < 0) {
|
|
free(sdi->write_data);
|
|
sdi->write_data = NULL;
|
|
return -ENODEV;
|
|
}
|
|
|
|
if (sdi->write_offset != lseek(sdi->fd, offset, SEEK_SET)) {
|
|
error = errno;
|
|
free(sdi->write_data);
|
|
sdi->write_data = NULL;
|
|
return -error;
|
|
}
|
|
|
|
error = write(sdi->fd, sdi->write_data, size);
|
|
}
|
|
|
|
if (error != size) {
|
|
error = errno;
|
|
free(sdi->write_data);
|
|
sdi->write_data = NULL;
|
|
return -error;
|
|
}
|
|
|
|
free(sdi->write_data);
|
|
sdi->write_data = NULL;
|
|
return 0;
|
|
}
|
|
|
|
static uint32_t
|
|
s3c2410_sdi_read(void *opaque, target_phys_addr_t offset)
|
|
{
|
|
s3c2410_sdi_t *sdi = opaque;
|
|
s3c2410_offset_t *reg;
|
|
unsigned int read_avail, write_avail;
|
|
|
|
#ifdef QEMU_OLD
|
|
offset -= S3C2410_SDI_BASE;
|
|
#endif
|
|
if (! S3C2410_OFFSET_OK(sdi, offset)) {
|
|
return ~(0);
|
|
}
|
|
|
|
reg = S3C2410_OFFSET_ENTRY(sdi, offset);
|
|
|
|
switch (offset) {
|
|
case S3C2410_SDI_SDIDAT:
|
|
read_avail = sdi->nr_read_data - sdi->read_index;
|
|
if (read_avail > 0) {
|
|
*(reg->datap) = sdi->read_data[sdi->read_index++] << 24;
|
|
if ((sdi->nr_read_data - sdi->read_index) > 0) {
|
|
*(reg->datap) |= sdi->read_data[sdi->read_index++] << 16;
|
|
}
|
|
if ((sdi->nr_read_data - sdi->read_index) > 0) {
|
|
*(reg->datap) |= sdi->read_data[sdi->read_index++] << 8;
|
|
}
|
|
if ((sdi->nr_read_data - sdi->read_index) > 0) {
|
|
*(reg->datap) |= sdi->read_data[sdi->read_index++] << 0;
|
|
}
|
|
|
|
if (sdi->read_index >= sdi->nr_read_data) {
|
|
sdi->read_index = 0;
|
|
free(sdi->read_data);
|
|
sdi->read_data = NULL;
|
|
|
|
if (sdi->multiple_block) {
|
|
sdi->read_offset += sdi->nr_read_data;
|
|
|
|
sdcard_read(sdi);
|
|
|
|
sdi->sdidsta |= (1 << 9) | (1 << 4);
|
|
} else {
|
|
sdi->nr_read_data = 0;
|
|
}
|
|
}
|
|
|
|
read_avail = sdi->nr_read_data - sdi->read_index;
|
|
|
|
sdi->sdidcnt = read_avail;
|
|
}
|
|
break;
|
|
|
|
case S3C2410_SDI_SDIFSTA:
|
|
*(reg->datap) = (1 << 13) | (1 << 10);
|
|
|
|
read_avail = sdi->nr_read_data - sdi->read_index;
|
|
if (read_avail > 63)
|
|
*(reg->datap) |= (1 << 12) | (1 << 8) | (1 << 7) | 0x40;
|
|
else if (read_avail > 31)
|
|
*(reg->datap) |= (1 << 12) | (1 << 9) | (1 << 7) | read_avail;
|
|
else
|
|
*(reg->datap) |= (1 << 12) | (1 << 9) | read_avail;
|
|
break;
|
|
|
|
case S3C2410_SDI_SDIDSTA:
|
|
*(reg->datap) &= ~(0x0f);
|
|
|
|
read_avail = sdi->nr_read_data - sdi->read_index;
|
|
if (read_avail) {
|
|
*(reg->datap) |= (1 << 0);
|
|
}
|
|
|
|
write_avail = sdi->nr_write_data - sdi->write_index;
|
|
if (write_avail) {
|
|
*(reg->datap) |= (1 << 1);
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG_S3C2410_SDI
|
|
printf("read %s [%08x] %s [%08lx] data %08x\n",
|
|
"s3c2410-sdi", S3C2410_SDI_BASE,
|
|
reg->name, (unsigned long) offset, *(reg->datap));
|
|
#endif
|
|
|
|
return *(reg->datap);
|
|
}
|
|
|
|
static void
|
|
s3c2410_sdi_write(void *opaque, target_phys_addr_t offset, uint32_t data)
|
|
{
|
|
s3c2410_sdi_t *sdi = opaque;
|
|
s3c2410_offset_t *reg;
|
|
unsigned int read_avail, write_avail;
|
|
|
|
#ifdef QEMU_OLD
|
|
offset -= S3C2410_SDI_BASE;
|
|
#endif
|
|
if (! S3C2410_OFFSET_OK(sdi, offset)) {
|
|
return;
|
|
}
|
|
|
|
reg = S3C2410_OFFSET_ENTRY(sdi, offset);
|
|
|
|
#ifdef DEBUG_S3C2410_SDI
|
|
printf("write %s [%08x] %s [%08lx] data %08x\n",
|
|
"s3c2410-sdi", S3C2410_SDI_BASE,
|
|
reg->name, (unsigned long) offset, data);
|
|
#endif
|
|
|
|
switch (offset) {
|
|
case S3C2410_SDI_SDICON:
|
|
*(reg->datap) = data & ~(2);
|
|
break;
|
|
|
|
case S3C2410_SDI_SDICCON:
|
|
*(reg->datap) = data;
|
|
|
|
#ifdef DEBUG_S3C2410_SDI
|
|
printf("SDI: cmd %02u, start %u, %s response %u, data %u, abort %u\n",
|
|
data & 0x3f, (data >> 8) & 1,
|
|
(data >> 10) & 1 ? "long" : "short",
|
|
(data >> 9) & 1,
|
|
(data >> 11) & 1, (data >> 12) & 1);
|
|
#endif
|
|
|
|
if (data & (1 << 8)) {
|
|
sdi->sdicsta |= (1 << 11);
|
|
} else {
|
|
sdi->sdicsta = 0;
|
|
sdi->sdirsp0 = 0;
|
|
sdi->sdirsp1 = 0;
|
|
sdi->sdirsp2 = 0;
|
|
sdi->sdirsp3 = 0;
|
|
data = 0;
|
|
}
|
|
|
|
sdi->sdicsta &= ~(1 << 12);
|
|
sdi->sdicsta &= ~(0xff);
|
|
|
|
if (data & (1 << 9)) {
|
|
sdi->sdicsta |= (1 << 9);
|
|
|
|
switch (data & 0x3f) {
|
|
case 0:
|
|
break;
|
|
|
|
case 1:
|
|
sdi->sdicsta |= 0x3f;
|
|
sdi->sdirsp0 = 0x80ff8000;
|
|
sdi->sdirsp1 = 0xff000000;
|
|
break;
|
|
|
|
case 2:
|
|
sdi->sdicsta |= 0x3f;
|
|
sdi->sdirsp0 = 0x02000053;
|
|
sdi->sdirsp1 = 0x444d3036;
|
|
sdi->sdirsp2 = 0x34011234;
|
|
sdi->sdirsp3 = 0x567813ff;
|
|
break;
|
|
|
|
case 3:
|
|
sdi->sdicsta |= 3;
|
|
sdi->sdirsp0 = 0x00000700;
|
|
sdi->sdirsp1 = 0xff000000;
|
|
break;
|
|
|
|
case 7:
|
|
sdi->sdicsta |= 7;
|
|
sdi->sdirsp0 = 0x00000900;
|
|
sdi->sdirsp1 = 0xff000000;
|
|
break;
|
|
|
|
case 9:
|
|
{
|
|
/* c_size_mult + 2
|
|
* blocks = (c_size + 1) * 2
|
|
*
|
|
* size = bl_len * blocks;
|
|
*/
|
|
uint32_t write_bl_len = 9;
|
|
uint32_t read_bl_len = 9;
|
|
uint32_t c_size_mult = 7;
|
|
uint32_t c_size = 256 - 1;
|
|
|
|
sdi->sdicsta |= 9;
|
|
/* 127 .. 96 */
|
|
sdi->sdirsp0 = 0x8c0f002a;
|
|
/* 95 .. 64 */
|
|
sdi->sdirsp1 = 0x0f508000 | ((c_size & 0xffc) >> 2) | ((read_bl_len & 0xf) << 16);
|
|
/* 63 .. 32 */
|
|
sdi->sdirsp2 = 0x2dd47c1f | ((c_size & 0x003) << 30) | ((c_size_mult & 7) << 15);
|
|
/* 31 .. 0 */
|
|
sdi->sdirsp3 = 0x8a0040ff | ((write_bl_len & 0xf) << 22);
|
|
break;
|
|
}
|
|
|
|
case 10:
|
|
sdi->sdicsta |= 10;
|
|
sdi->sdirsp0 = 0x02000053;
|
|
sdi->sdirsp1 = 0x444d3036;
|
|
sdi->sdirsp2 = 0x34011234;
|
|
sdi->sdirsp3 = 0x567813ff;
|
|
break;
|
|
|
|
case 12:
|
|
sdi->multiple_block = 0;
|
|
|
|
sdi->sdicsta |= 12;
|
|
sdi->sdirsp0 = 0x00000900;
|
|
sdi->sdirsp1 = 0xff000000;
|
|
break;
|
|
|
|
case 18:
|
|
sdi->multiple_block = 1;
|
|
/* fall through */
|
|
case 17:
|
|
sdi->read_offset = sdi->sdicarg;
|
|
sdi->nr_read_data = sdi->sdibsize & 0xfff;
|
|
|
|
sdcard_read(sdi);
|
|
|
|
read_avail = sdi->nr_read_data - sdi->read_index;
|
|
|
|
sdi->sdicsta |= data & 0x3f;
|
|
sdi->sdirsp0 = 0x00000b00;
|
|
sdi->sdirsp1 = 0xff000000;
|
|
sdi->sdidcnt = (1 << 12) | read_avail;
|
|
sdi->sdidsta |= (1 << 9) | (1 << 4);
|
|
break;
|
|
|
|
case 25:
|
|
sdi->multiple_block = 1;
|
|
/* fall through */
|
|
case 24:
|
|
sdi->write_offset = sdi->sdicarg;
|
|
sdi->nr_write_data = sdi->sdibsize & 0xfff;
|
|
|
|
sdcard_write_prepare(sdi);
|
|
|
|
write_avail = sdi->nr_write_data - sdi->write_index;
|
|
|
|
sdi->sdicsta |= data & 0x3f;
|
|
sdi->sdirsp0 = 0x00000d00;
|
|
sdi->sdirsp1 = 0xff000000;
|
|
sdi->sdidcnt = (1 << 12) | write_avail;
|
|
break;
|
|
|
|
default:
|
|
printf("unhandled SDcard CMD %u\n", (data & 0x3f));
|
|
|
|
sdi->sdicsta |= (1 << 10);
|
|
sdi->sdicsta &= ~(1 << 9);
|
|
|
|
// abort();
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case S3C2410_SDI_SDIDAT:
|
|
*(reg->datap) = data;
|
|
|
|
write_avail = sdi->nr_write_data - sdi->write_index;
|
|
if (write_avail > 0) {
|
|
sdi->write_data[sdi->write_index++] = (*(reg->datap) >> 24) & 0xff;
|
|
if ((sdi->nr_write_data - sdi->write_index) > 0) {
|
|
sdi->write_data[sdi->write_index++] = (*(reg->datap) >> 16) & 0xff;
|
|
}
|
|
if ((sdi->nr_write_data - sdi->write_index) > 0) {
|
|
sdi->write_data[sdi->write_index++] = (*(reg->datap) >> 8) & 0xff;
|
|
}
|
|
if ((sdi->nr_write_data - sdi->write_index) > 0) {
|
|
sdi->write_data[sdi->write_index++] = (*(reg->datap) >> 0) & 0xff;
|
|
}
|
|
|
|
if (sdi->write_index >= sdi->nr_write_data) {
|
|
sdcard_write(sdi);
|
|
|
|
if (sdi->multiple_block) {
|
|
sdi->write_offset += sdi->nr_write_data;
|
|
sdcard_write_prepare(sdi);
|
|
} else {
|
|
sdi->nr_write_data = 0;
|
|
}
|
|
|
|
sdi->sdidsta |= (1 << 9) | (1 << 4);
|
|
}
|
|
|
|
write_avail = sdi->nr_write_data - sdi->write_index;
|
|
|
|
sdi->sdidcnt = write_avail;
|
|
}
|
|
break;
|
|
|
|
case S3C2410_SDI_SDICSTA:
|
|
*(reg->datap) &= ~(data & 0xf00);
|
|
break;
|
|
|
|
case S3C2410_SDI_SDIDSTA:
|
|
*(reg->datap) &= ~(data & 0x3f8);
|
|
break;
|
|
|
|
case S3C2410_SDI_SDIFSTA:
|
|
/* ignore */
|
|
break;
|
|
|
|
default:
|
|
*(reg->datap) = data;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
s3c2410_sdi_unmount(x49gp_t *x49gp)
|
|
{
|
|
s3c2410_sdi_t *sdi = x49gp->s3c2410_sdi;
|
|
|
|
if (sdi->bs) {
|
|
bdrv_delete(sdi->bs);
|
|
sdi->bs = NULL;
|
|
}
|
|
|
|
if (sdi->fd >= 0) {
|
|
close(sdi->fd);
|
|
sdi->fd = -1;
|
|
}
|
|
|
|
g_free(sdi->filename);
|
|
sdi->filename = g_strdup("");
|
|
|
|
s3c2410_io_port_f_set_bit(x49gp, 3, 0);
|
|
}
|
|
|
|
int
|
|
s3c2410_sdi_mount(x49gp_t *x49gp, char *filename)
|
|
{
|
|
s3c2410_sdi_t *sdi = x49gp->s3c2410_sdi;
|
|
struct stat st;
|
|
char vvfat_name[1024];
|
|
int error = 0;
|
|
|
|
s3c2410_sdi_unmount(x49gp);
|
|
g_free(sdi->filename);
|
|
sdi->filename = filename;
|
|
|
|
if (strcmp(filename, "") && (stat(filename, &st) == 0)) {
|
|
if (S_ISDIR(st.st_mode)) {
|
|
sprintf(vvfat_name, "fat:rw:16:%s", filename);
|
|
sdi->bs = bdrv_new("");
|
|
if (sdi->bs) {
|
|
error = bdrv_open(sdi->bs, vvfat_name, 0);
|
|
if (error != 0) {
|
|
fprintf(stderr,
|
|
"%s:%u: bdrv_open %s: %d\n",
|
|
__FUNCTION__, __LINE__,
|
|
vvfat_name, error);
|
|
bdrv_delete(sdi->bs);
|
|
sdi->bs = NULL;
|
|
}
|
|
}
|
|
} else {
|
|
sdi->fd = open(filename, O_RDWR);
|
|
if (sdi->fd < 0) {
|
|
fprintf(stderr, "%s:%u: open %s: %s\n",
|
|
__FUNCTION__, __LINE__, filename,
|
|
strerror(errno));
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((sdi->bs != NULL) || (sdi->fd >= 0)) {
|
|
s3c2410_io_port_f_set_bit(x49gp, 3, 1);
|
|
} else {
|
|
s3c2410_io_port_f_set_bit(x49gp, 3, 0);
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
int
|
|
s3c2410_sdi_is_mounted(x49gp_t *x49gp)
|
|
{
|
|
s3c2410_sdi_t *sdi = x49gp->s3c2410_sdi;
|
|
|
|
return (sdi->bs != NULL) || (sdi->fd >= 0);
|
|
}
|
|
|
|
static int
|
|
s3c2410_sdi_load(x49gp_module_t *module, GKeyFile *key)
|
|
{
|
|
x49gp_t *x49gp = module->x49gp;
|
|
s3c2410_sdi_t *sdi = module->user_data;
|
|
s3c2410_offset_t *reg;
|
|
char *filename, *filepath;
|
|
int error, error2;
|
|
int i;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
sdi->fd = -1;
|
|
sdi->bs = NULL;
|
|
sdi->filename = NULL;
|
|
|
|
error = x49gp_module_get_filename(module, key, "filename", "",
|
|
&filename, &filepath);
|
|
if (strcmp(filename, "")) {
|
|
error2 = s3c2410_sdi_mount(x49gp, filepath);
|
|
if (0 == error) error = error2;
|
|
} else {
|
|
s3c2410_sdi_unmount(x49gp);
|
|
}
|
|
g_free(sdi->filename);
|
|
sdi->filename = filename;
|
|
|
|
for (i = 0; i < sdi->nr_regs; i++) {
|
|
reg = &sdi->regs[i];
|
|
|
|
if (NULL == reg->name)
|
|
continue;
|
|
|
|
if (x49gp_module_get_u32(module, key, reg->name,
|
|
reg->reset, reg->datap))
|
|
error = -EAGAIN;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
static int
|
|
s3c2410_sdi_save(x49gp_module_t *module, GKeyFile *key)
|
|
{
|
|
s3c2410_sdi_t *sdi = module->user_data;
|
|
s3c2410_offset_t *reg;
|
|
int i;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
x49gp_module_set_filename(module, key, "filename", sdi->filename);
|
|
|
|
for (i = 0; i < sdi->nr_regs; i++) {
|
|
reg = &sdi->regs[i];
|
|
|
|
if (NULL == reg->name)
|
|
continue;
|
|
|
|
x49gp_module_set_u32(module, key, reg->name, *(reg->datap));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
s3c2410_sdi_reset(x49gp_module_t *module, x49gp_reset_t reset)
|
|
{
|
|
s3c2410_sdi_t *sdi = module->user_data;
|
|
s3c2410_offset_t *reg;
|
|
int i;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
for (i = 0; i < sdi->nr_regs; i++) {
|
|
reg = &sdi->regs[i];
|
|
|
|
if (NULL == reg->name)
|
|
continue;
|
|
|
|
*(reg->datap) = reg->reset;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static CPUReadMemoryFunc *s3c2410_sdi_readfn[] =
|
|
{
|
|
s3c2410_sdi_read,
|
|
s3c2410_sdi_read,
|
|
s3c2410_sdi_read
|
|
};
|
|
|
|
static CPUWriteMemoryFunc *s3c2410_sdi_writefn[] =
|
|
{
|
|
s3c2410_sdi_write,
|
|
s3c2410_sdi_write,
|
|
s3c2410_sdi_write
|
|
};
|
|
|
|
static int
|
|
s3c2410_sdi_init(x49gp_module_t *module)
|
|
{
|
|
s3c2410_sdi_t *sdi;
|
|
int iotype;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
sdi = malloc(sizeof(s3c2410_sdi_t));
|
|
if (NULL == sdi) {
|
|
fprintf(stderr, "%s: %s:%u: Out of memory\n",
|
|
module->x49gp->progname, __FUNCTION__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
if (s3c2410_sdi_data_init(sdi)) {
|
|
free(sdi);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
module->user_data = sdi;
|
|
module->x49gp->s3c2410_sdi = sdi;
|
|
sdi->x49gp = module->x49gp;
|
|
|
|
#ifdef QEMU_OLD
|
|
iotype = cpu_register_io_memory(0, s3c2410_sdi_readfn,
|
|
s3c2410_sdi_writefn, sdi);
|
|
#else
|
|
iotype = cpu_register_io_memory(s3c2410_sdi_readfn,
|
|
s3c2410_sdi_writefn, sdi);
|
|
#endif
|
|
#ifdef DEBUG_S3C2410_SDI
|
|
printf("%s: iotype %08x\n", __FUNCTION__, iotype);
|
|
#endif
|
|
cpu_register_physical_memory(S3C2410_SDI_BASE, S3C2410_MAP_SIZE, iotype);
|
|
|
|
bdrv_init();
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
s3c2410_sdi_exit(x49gp_module_t *module)
|
|
{
|
|
s3c2410_sdi_t *sdi;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
if (module->user_data) {
|
|
sdi = module->user_data;
|
|
if (sdi->regs)
|
|
free(sdi->regs);
|
|
free(sdi);
|
|
}
|
|
|
|
x49gp_module_unregister(module);
|
|
free(module);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
x49gp_s3c2410_sdi_init(x49gp_t *x49gp)
|
|
{
|
|
x49gp_module_t *module;
|
|
|
|
if (x49gp_module_init(x49gp, "s3c2410-sdi",
|
|
s3c2410_sdi_init,
|
|
s3c2410_sdi_exit,
|
|
s3c2410_sdi_reset,
|
|
s3c2410_sdi_load,
|
|
s3c2410_sdi_save,
|
|
NULL, &module)) {
|
|
return -1;
|
|
}
|
|
|
|
return x49gp_module_register(module);
|
|
}
|