mirror of
https://github.com/gwenhael-le-moine/x49gp.git
synced 2024-12-25 21:58:49 +01:00
858 lines
21 KiB
C
858 lines
21 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>
|
|
|
|
//#define DEBUG_S3C2410_SDI 1
|
|
|
|
|
|
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;
|
|
int acmd;
|
|
int card_state;
|
|
} 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;
|
|
|
|
if (! S3C2410_OFFSET_OK(sdi, offset)) {
|
|
return ~(0);
|
|
}
|
|
|
|
reg = S3C2410_OFFSET_ENTRY(sdi, offset);
|
|
|
|
switch (offset) {
|
|
case S3C2410_SDI_SDIDAT:
|
|
if( (sdi->sdidcon&0x3000)==0x2000) {
|
|
read_avail = sdi->nr_read_data - sdi->read_index;
|
|
if (read_avail > 0) {
|
|
*(reg->datap) = sdi->read_data[sdi->read_index++] << ((sdi->sdicon&0x10)? 24:0);
|
|
if ((sdi->nr_read_data - sdi->read_index) > 0) {
|
|
*(reg->datap) |= sdi->read_data[sdi->read_index++] << ((sdi->sdicon&0x10)? 16:8);
|
|
}
|
|
if ((sdi->nr_read_data - sdi->read_index) > 0) {
|
|
*(reg->datap) |= sdi->read_data[sdi->read_index++] << ((sdi->sdicon&0x10)? 8:16);
|
|
}
|
|
if ((sdi->nr_read_data - sdi->read_index) > 0) {
|
|
*(reg->datap) |= sdi->read_data[sdi->read_index++] << ((sdi->sdicon&0x10)? 0:24);
|
|
}
|
|
|
|
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->multiple_block;
|
|
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;
|
|
sdi->sdidcon&=~0x3000;
|
|
}
|
|
}
|
|
|
|
read_avail = sdi->nr_read_data - sdi->read_index;
|
|
|
|
sdi->sdidcnt = read_avail;
|
|
}
|
|
else *(reg->datap)=0;
|
|
}
|
|
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) &= ~(0x03);
|
|
if( (sdi->sdidcon&0x3000)==0x1000) {
|
|
*(reg->datap) |= (1 << 3);
|
|
sdi->sdidcon&=~0x3000; // BACK TO READY STATE
|
|
}
|
|
read_avail = sdi->nr_read_data - sdi->read_index;
|
|
if ( ((sdi->sdidcon&0x3000)==0x2000) && read_avail) {
|
|
*(reg->datap) |= (1 << 0);
|
|
}
|
|
|
|
write_avail = sdi->nr_write_data - sdi->write_index;
|
|
if ( ((sdi->sdidcon&0x3000)==0x3000) && 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;
|
|
|
|
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)+(sdi->acmd<<8)) {
|
|
case 256:
|
|
case 0:
|
|
sdi->acmd=0;
|
|
sdi->card_state=0;
|
|
break;
|
|
|
|
case 1:
|
|
sdi->sdicsta |= 0x3f;
|
|
sdi->sdirsp0 = 0x80ff8000;
|
|
sdi->sdirsp1 = 0xff000000;
|
|
break;
|
|
|
|
case 2:
|
|
sdi->card_state=2;
|
|
sdi->sdicsta |= 0x3f;
|
|
sdi->sdirsp0 = 0x02000053;
|
|
sdi->sdirsp1 = 0x444d3036;
|
|
sdi->sdirsp2 = 0x34011234;
|
|
sdi->sdirsp3 = 0x567813ff;
|
|
break;
|
|
|
|
case 3:
|
|
sdi->card_state=3;
|
|
sdi->sdicsta |= 3;
|
|
sdi->sdirsp0 = sdi->card_state<<9;
|
|
if(sdi->card_state==5) sdi->sdirsp0 |=0x100;
|
|
if(sdi->acmd) sdi->sdirsp0|=0x20;
|
|
sdi->sdirsp0|=0x12340000; // PUBLISHED RCA NUMBER
|
|
sdi->sdirsp1 = 0xff000000;
|
|
break;
|
|
|
|
case 7:
|
|
sdi->sdicsta |= 7;
|
|
sdi->sdirsp0 = 0x00000900;
|
|
sdi->sdirsp1 = 0xff000000;
|
|
break;
|
|
case 8:
|
|
sdi->sdicsta |=0x400; // SEND TIMEOUT IMMEDIATELY
|
|
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 = 4096 - 1;
|
|
|
|
sdi->sdicsta |= 9;
|
|
/* 127 .. 96 */
|
|
sdi->sdirsp0 = 0x000f005a;
|
|
/* 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->nr_read_data=sdi->nr_write_data=0;
|
|
sdi->write_index=sdi->read_index=0;
|
|
if(sdi->read_data) {
|
|
free(sdi->read_data);
|
|
sdi->read_data = NULL;
|
|
}
|
|
sdi->sdidcon&=0x3000;
|
|
sdi->sdicsta |= 12;
|
|
sdi->sdirsp0 = 0x00000900;
|
|
sdi->sdirsp1 = 0xff000000;
|
|
break;
|
|
case 16:
|
|
sdi->sdicsta |= 16;
|
|
sdi->sdicsta |= data & 0x3f;
|
|
sdi->sdirsp0 = sdi->card_state<<9;
|
|
if(sdi->card_state==5) sdi->sdirsp0 |=0x100;
|
|
if(sdi->acmd) sdi->sdirsp0|=0x20;
|
|
sdi->sdirsp1 = 0xff000000;
|
|
break;
|
|
|
|
case 18:
|
|
sdi->multiple_block = sdi->sdicarg;
|
|
/* 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 23:
|
|
|
|
|
|
case 25:
|
|
sdi->multiple_block = sdi->sdicarg;
|
|
/* 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;
|
|
case 256+55:
|
|
case 55:
|
|
sdi->acmd=1;
|
|
sdi->sdicsta |= data & 0x3f;
|
|
sdi->sdirsp0 = sdi->card_state<<9;
|
|
if(sdi->card_state==5) sdi->sdirsp0 |=0x100;
|
|
if(sdi->acmd) sdi->sdirsp0|=0x20;
|
|
sdi->sdirsp1 = 0xff000000;
|
|
break;
|
|
case 256+41:
|
|
// ACMD41
|
|
sdi->card_state= 1; // READY
|
|
sdi->sdicsta |= data & 0x3f;
|
|
sdi->sdirsp0 = 0x80ff8000;
|
|
sdi->sdirsp1 = 0xff000000;
|
|
sdi->acmd=0;
|
|
break;
|
|
|
|
case 256+42:
|
|
// ACMD42
|
|
sdi->sdicsta |= data & 0x3f;
|
|
sdi->sdirsp0 = sdi->card_state<<9;
|
|
if(sdi->card_state==5) sdi->sdirsp0 |=0x100;
|
|
if(sdi->acmd) sdi->sdirsp0|=0x20;
|
|
sdi->sdirsp1 = 0xff000000;
|
|
break;
|
|
|
|
case 256+51:
|
|
// ACMD51
|
|
sdi->sdicsta |= 51;
|
|
sdi->sdirsp0 = 0x0;
|
|
sdi->sdirsp1 = 0x01050000;
|
|
sdi->sdirsp2 = 0x0;
|
|
sdi->sdirsp3 = 0x0;
|
|
sdi->acmd=0;
|
|
break;
|
|
|
|
default:
|
|
printf("unhandled SDcard CMD %u\n", (data & 0x3f));
|
|
|
|
sdi->sdicsta |= (1 << 10);
|
|
sdi->sdicsta &= ~(1 << 9);
|
|
sdi->acmd=0;
|
|
|
|
// abort();
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case S3C2410_SDI_SDIDAT:
|
|
*(reg->datap) = data;
|
|
if((sdi->sdidcon&0x3000)==0x3000) {
|
|
write_avail = sdi->nr_write_data - sdi->write_index;
|
|
if (write_avail > 0) {
|
|
sdi->write_data[sdi->write_index++] = (*(reg->datap) >> ((sdi->sdicon&0x10)? 24:0)) & 0xff;
|
|
if ((sdi->nr_write_data - sdi->write_index) > 0) {
|
|
sdi->write_data[sdi->write_index++] = (*(reg->datap) >> ((sdi->sdicon&0x10)? 16:8)) & 0xff;
|
|
}
|
|
if ((sdi->nr_write_data - sdi->write_index) > 0) {
|
|
sdi->write_data[sdi->write_index++] = (*(reg->datap) >> ((sdi->sdicon&0x10)? 8:16)) & 0xff;
|
|
}
|
|
if ((sdi->nr_write_data - sdi->write_index) > 0) {
|
|
sdi->write_data[sdi->write_index++] = (*(reg->datap) >> ((sdi->sdicon&0x10)? 0:24)) & 0xff;
|
|
}
|
|
|
|
if (sdi->write_index >= sdi->nr_write_data) {
|
|
sdcard_write(sdi);
|
|
if(sdi->multiple_block) sdi->multiple_block--;
|
|
if (sdi->multiple_block) {
|
|
sdi->write_offset += sdi->nr_write_data;
|
|
sdcard_write_prepare(sdi);
|
|
} else {
|
|
sdi->nr_write_data = 0;
|
|
sdi->sdidcon&=~0x3000;
|
|
}
|
|
|
|
sdi->sdidsta |= (1 << 9) | (1 << 4) | (1<<3);
|
|
}
|
|
|
|
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 & 0x7fc);
|
|
break;
|
|
|
|
case S3C2410_SDI_SDIFSTA:
|
|
case S3C2410_SDI_SDIDCNT:
|
|
/* 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;
|
|
|
|
iotype = cpu_register_io_memory(s3c2410_sdi_readfn,
|
|
s3c2410_sdi_writefn, sdi);
|
|
#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);
|
|
}
|