Search
lxdream.org :: lxdream/src/maple/vmu.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/maple/vmu.c
changeset 1088:cf3900ae8acc
prev1072:d82e04e6d497
next1172:43eef98ff265
author nkeynes
date Fri Dec 04 18:06:12 2009 +1000 (14 years ago)
permissions -rw-r--r--
last change Fix crash on vmu device create introduced in r1072 - config was being
initialised in the wrong order
file annotate diff log raw
nkeynes@1034
     1
/**
nkeynes@1035
     2
 * $Id$
nkeynes@1034
     3
 *
nkeynes@1034
     4
 * Implementation of the SEGA VMU device
nkeynes@1034
     5
 * Part No. HKT-7000
nkeynes@1034
     6
 * 
nkeynes@1034
     7
 * The standard VMU implements 3 functions - Clock, LCD, and memory card, 
nkeynes@1034
     8
 * in addition to having it's own little CPU, buttons, etc. The CPU isn't
nkeynes@1034
     9
 * implemented just yet.   
nkeynes@1034
    10
 *
nkeynes@1034
    11
 * Copyright (c) 2009 Nathan Keynes.
nkeynes@1034
    12
 *
nkeynes@1034
    13
 * This program is free software; you can redistribute it and/or modify
nkeynes@1034
    14
 * it under the terms of the GNU General Public License as published by
nkeynes@1034
    15
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@1034
    16
 * (at your option) any later version.
nkeynes@1034
    17
 *
nkeynes@1034
    18
 * This program is distributed in the hope that it will be useful,
nkeynes@1034
    19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@1034
    20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@1034
    21
 * GNU General Public License for more details.
nkeynes@1034
    22
 */
nkeynes@1034
    23
nkeynes@1034
    24
#include <assert.h>
nkeynes@1034
    25
#include <stdlib.h>
nkeynes@1034
    26
#include <stdio.h>
nkeynes@1034
    27
#include <string.h>
nkeynes@1034
    28
#include <errno.h>
nkeynes@1034
    29
#include <sys/mman.h>
nkeynes@1034
    30
#include <fcntl.h>
nkeynes@1034
    31
#include "display.h"
nkeynes@1034
    32
#include "maple/maple.h"
nkeynes@1034
    33
#include "vmu/vmuvol.h"
nkeynes@1034
    34
#include "vmu/vmulist.h"
nkeynes@1034
    35
nkeynes@1034
    36
#define VMU_LCD_SIZE (48*4)
nkeynes@1034
    37
#define VMU_BLOCK_COUNT 256
nkeynes@1034
    38
#define VMU_BLOCK_SIZE 512
nkeynes@1034
    39
#define VMU_PHASE_SIZE 128
nkeynes@1034
    40
#define VMU_CONFIG_ENTRIES 1
nkeynes@1034
    41
nkeynes@1034
    42
#define VMU_IDENT {          0x00, 0x00, 0x00, 0x0E,  0x7E, 0x7E, 0x3F, 0x40,  0x00, 0x05, 0x10, 0x00, \
nkeynes@1034
    43
	0x00, 0x0F, 0x41, 0x00,  0xFF, 0x00, 0x56, 0x69,  0x73, 0x75, 0x61, 0x6C,  0x20, 0x4D, 0x65, 0x6D, \
nkeynes@1034
    44
	0x6F, 0x72, 0x79, 0x20,  0x20, 0x20, 0x20, 0x20,  0x20, 0x20, 0x20, 0x20,  0x20, 0x20, 0x20, 0x20, \
nkeynes@1034
    45
	0x20, 0x20, 0x20, 0x20,  0x50, 0x72, 0x6F, 0x64,  0x75, 0x63, 0x65, 0x64,  0x20, 0x42, 0x79, 0x20, \
nkeynes@1034
    46
	0x6F, 0x72, 0x20, 0x55,  0x6E, 0x64, 0x65, 0x72,  0x20, 0x4C, 0x69, 0x63,  0x65, 0x6E, 0x73, 0x65, \
nkeynes@1034
    47
	0x20, 0x46, 0x72, 0x6F,  0x6D, 0x20, 0x53, 0x45,  0x47, 0x41, 0x20, 0x45,  0x4E, 0x54, 0x45, 0x52, \
nkeynes@1034
    48
	0x50, 0x52, 0x49, 0x53,  0x45, 0x53, 0x2C, 0x4C,  0x54, 0x44, 0x2E, 0x20,  0x20, 0x20, 0x20, 0x20, \
nkeynes@1034
    49
	0x7C, 0x00, 0x82, 0x00 }
nkeynes@1034
    50
#define VMU_VERSION {        0x56, 0x65, 0x72, 0x73,  0x69, 0x6F, 0x6E, 0x20,  0x31, 0x2E, 0x30, 0x30, \
nkeynes@1034
    51
	0x35, 0x2C, 0x31, 0x39,  0x39, 0x39, 0x2F, 0x30,  0x34, 0x2F, 0x31, 0x35,  0x2C, 0x33, 0x31, 0x35, \
nkeynes@1034
    52
	0x2D, 0x36, 0x32, 0x30,  0x38, 0x2D, 0x30, 0x33,  0x2C, 0x53, 0x45, 0x47,  0x41, 0x20, 0x56, 0x69, \
nkeynes@1034
    53
	0x73, 0x75, 0x61, 0x6C,  0x20, 0x4D, 0x65, 0x6D,  0x6F, 0x72, 0x79, 0x20,  0x53, 0x79, 0x73, 0x74, \
nkeynes@1034
    54
	0x65, 0x6D, 0x20, 0x42,  0x49, 0x4F, 0x53, 0x20,  0x50, 0x72, 0x6F, 0x64,  0x75, 0x63, 0x65, 0x64, \
nkeynes@1034
    55
	0x20, 0x62, 0x79, 0x20 }
nkeynes@1034
    56
nkeynes@1034
    57
static void vmu_destroy( maple_device_t dev );
nkeynes@1034
    58
static maple_device_t vmu_clone( maple_device_t dev );
nkeynes@1034
    59
static maple_device_t vmu_new();
nkeynes@1072
    60
static lxdream_config_group_t vmu_get_config( maple_device_t dev );
nkeynes@1072
    61
static gboolean vmu_set_config_value( void *data, lxdream_config_group_t group, unsigned int key,
nkeynes@1072
    62
                                      const gchar *oldvalue, const gchar *value );
nkeynes@1034
    63
static int vmu_get_condition( maple_device_t dev, int function, unsigned char *outbuf,
nkeynes@1034
    64
                              unsigned int *outlen );
nkeynes@1034
    65
static int vmu_get_meminfo( maple_device_t dev, int function, unsigned int pt, 
nkeynes@1034
    66
                            unsigned char *outbuf, unsigned int *outlen );
nkeynes@1034
    67
static void vmu_attach(struct maple_device *dev);
nkeynes@1034
    68
static void vmu_detach(struct maple_device *dev);
nkeynes@1034
    69
static int vmu_read_block(struct maple_device *dev, int function, unsigned int pt,
nkeynes@1034
    70
                   uint32_t block, unsigned int phase, 
nkeynes@1034
    71
                   unsigned char *outbuf, unsigned int *buflen);
nkeynes@1034
    72
static int vmu_write_block(struct maple_device *dev, int function, unsigned int pt,
nkeynes@1034
    73
                    uint32_t block, unsigned int phase, 
nkeynes@1034
    74
                    unsigned char *inbuf, unsigned int buflen);
nkeynes@1034
    75
nkeynes@1034
    76
typedef struct vmu_device {
nkeynes@1034
    77
    struct maple_device dev;
nkeynes@1034
    78
    vmu_volume_t vol;
nkeynes@1034
    79
    char lcd_bitmap[VMU_LCD_SIZE]; /* 48x32 bitmap */
nkeynes@1072
    80
    struct lxdream_config_group config;
nkeynes@1034
    81
} *vmu_device_t;
nkeynes@1034
    82
nkeynes@1072
    83
#define DEV_FROM_CONFIG_GROUP(grp)  ((vmu_device_t)(((char *)grp) - offsetof( struct vmu_device, config )))
nkeynes@1072
    84
nkeynes@1034
    85
struct maple_device_class vmu_class = { "Sega VMU", MAPLE_GRAB_DONTCARE, vmu_new };
nkeynes@1034
    86
nkeynes@1034
    87
static struct vmu_device base_vmu = {
nkeynes@1034
    88
        { MAPLE_DEVICE_TAG, &vmu_class,
nkeynes@1034
    89
          VMU_IDENT, VMU_VERSION, 
nkeynes@1072
    90
          vmu_get_config,
nkeynes@1034
    91
          vmu_attach, vmu_detach, vmu_destroy,
nkeynes@1034
    92
          vmu_clone, NULL, NULL, vmu_get_condition, NULL,
nkeynes@1034
    93
          vmu_get_meminfo, vmu_read_block, vmu_write_block, NULL, NULL },
nkeynes@1072
    94
          NULL, {0},
nkeynes@1072
    95
          {"Sega VMU", vmu_set_config_value, NULL, NULL,
nkeynes@1034
    96
          {{ "volume", N_("Volume"), CONFIG_TYPE_FILE },
nkeynes@1072
    97
           { NULL, CONFIG_TYPE_NONE }}} };
nkeynes@1072
    98
nkeynes@1072
    99
nkeynes@1034
   100
nkeynes@1034
   101
static maple_device_t vmu_new( )
nkeynes@1034
   102
{
nkeynes@1034
   103
    vmu_device_t dev = malloc( sizeof(struct vmu_device) );
nkeynes@1088
   104
    memcpy( dev, &base_vmu, sizeof(base_vmu) );
nkeynes@1072
   105
    dev->config.data = dev;
nkeynes@1034
   106
    return MAPLE_DEVICE(dev);
nkeynes@1034
   107
}
nkeynes@1034
   108
nkeynes@1034
   109
static maple_device_t vmu_clone( maple_device_t srcdevice )
nkeynes@1034
   110
{
nkeynes@1034
   111
    vmu_device_t src = (vmu_device_t)srcdevice;
nkeynes@1034
   112
    vmu_device_t dev = (vmu_device_t)vmu_new();
nkeynes@1072
   113
    lxdream_copy_config_group( &dev->config, &src->config );
nkeynes@1072
   114
    dev->config.data = dev;
nkeynes@1034
   115
    return MAPLE_DEVICE(dev);
nkeynes@1034
   116
}
nkeynes@1034
   117
nkeynes@1072
   118
static lxdream_config_group_t vmu_get_config( maple_device_t mdev )
nkeynes@1034
   119
{
nkeynes@1034
   120
    vmu_device_t dev = (vmu_device_t)mdev;
nkeynes@1072
   121
    return &dev->config;
nkeynes@1034
   122
}
nkeynes@1034
   123
nkeynes@1072
   124
static gboolean vmu_set_config_value( void *data, lxdream_config_group_t group, unsigned int key,
nkeynes@1072
   125
                                      const gchar *oldvalue, const gchar *value )
nkeynes@1034
   126
{
nkeynes@1072
   127
    vmu_device_t vmu = (vmu_device_t)data;
nkeynes@1034
   128
    assert( key < VMU_CONFIG_ENTRIES );
nkeynes@1034
   129
    
nkeynes@1034
   130
    if( vmu->vol != NULL ) {
nkeynes@1034
   131
        vmulist_detach_vmu(vmu->vol);
nkeynes@1034
   132
    }
nkeynes@1034
   133
    vmu->vol = vmulist_get_vmu_by_filename( value );
nkeynes@1034
   134
    if( vmu->vol != NULL ) {
nkeynes@1034
   135
        vmulist_attach_vmu(vmu->vol, "MAPLE");
nkeynes@1034
   136
    }
nkeynes@1072
   137
    return TRUE;
nkeynes@1034
   138
}
nkeynes@1034
   139
nkeynes@1034
   140
void vmu_attach(struct maple_device *dev)
nkeynes@1034
   141
{
nkeynes@1034
   142
    vmu_device_t vmu = (vmu_device_t)dev;
nkeynes@1072
   143
    if( vmu->config.params[0].value != NULL ) {
nkeynes@1072
   144
        vmu->vol = vmulist_get_vmu_by_filename(vmu->config.params[0].value);
nkeynes@1034
   145
        if( vmu->vol != NULL ) {
nkeynes@1034
   146
            vmulist_attach_vmu(vmu->vol, "MAPLE");
nkeynes@1034
   147
        }
nkeynes@1034
   148
    }
nkeynes@1034
   149
}
nkeynes@1034
   150
nkeynes@1034
   151
static void vmu_detach(struct maple_device *dev)
nkeynes@1034
   152
{
nkeynes@1034
   153
    vmu_device_t vmu = (vmu_device_t)dev;
nkeynes@1034
   154
    if( vmu->vol != NULL ) {
nkeynes@1034
   155
        vmulist_detach_vmu(vmu->vol);
nkeynes@1034
   156
        vmu->vol = NULL;
nkeynes@1034
   157
    }
nkeynes@1034
   158
}
nkeynes@1034
   159
nkeynes@1034
   160
static void vmu_destroy( maple_device_t dev )
nkeynes@1034
   161
{
nkeynes@1034
   162
    vmu_device_t vmu = (vmu_device_t)dev;
nkeynes@1034
   163
    free( dev );
nkeynes@1034
   164
}
nkeynes@1034
   165
nkeynes@1034
   166
static int vmu_get_condition(struct maple_device *dev, int function, 
nkeynes@1034
   167
                      unsigned char *outbuf, unsigned int *buflen)
nkeynes@1034
   168
{
nkeynes@1072
   169
    return 0;
nkeynes@1034
   170
}
nkeynes@1034
   171
static int vmu_set_condition(struct maple_device *dev, int function, 
nkeynes@1034
   172
                      unsigned char *inbuf, unsigned int buflen)
nkeynes@1034
   173
{
nkeynes@1034
   174
    return MAPLE_ERR_NO_RESPONSE; /* CHECKME */
nkeynes@1034
   175
}
nkeynes@1034
   176
nkeynes@1034
   177
static int vmu_get_meminfo(struct maple_device *dev, int function, unsigned int pt, 
nkeynes@1034
   178
                           unsigned char *outbuf, unsigned int *buflen)
nkeynes@1034
   179
{
nkeynes@1034
   180
    struct vmu_device *vmu = (struct vmu_device *)dev;
nkeynes@1034
   181
    switch(function) {
nkeynes@1034
   182
    case MAPLE_FUNC_MEMORY:
nkeynes@1034
   183
        if( vmu->vol != NULL ) {
nkeynes@1034
   184
            const struct vmu_volume_metadata *md = vmu_volume_get_metadata( vmu->vol, pt ); 
nkeynes@1034
   185
            memcpy( outbuf, md, sizeof(struct vmu_volume_metadata) );
nkeynes@1034
   186
            *buflen = sizeof(struct vmu_volume_metadata);
nkeynes@1034
   187
            return 0;
nkeynes@1034
   188
        } // Else fallthrough 
nkeynes@1034
   189
    case MAPLE_FUNC_LCD:
nkeynes@1034
   190
    case MAPLE_FUNC_CLOCK:
nkeynes@1034
   191
        return MAPLE_ERR_NO_RESPONSE;
nkeynes@1034
   192
    default:
nkeynes@1034
   193
        return MAPLE_ERR_FUNC_UNSUP;
nkeynes@1034
   194
    }
nkeynes@1034
   195
nkeynes@1034
   196
}
nkeynes@1034
   197
static int vmu_read_block(struct maple_device *dev, int function, unsigned int pt,
nkeynes@1034
   198
                   uint32_t block, unsigned int phase, 
nkeynes@1034
   199
                   unsigned char *outbuf, unsigned int *buflen)
nkeynes@1034
   200
{
nkeynes@1034
   201
    struct vmu_device *vmu = (struct vmu_device *)dev;
nkeynes@1034
   202
    switch( function ) {
nkeynes@1034
   203
    case MAPLE_FUNC_LCD:
nkeynes@1034
   204
        if( pt == 0 && block == 0 ) {
nkeynes@1034
   205
            *buflen = VMU_LCD_SIZE/4;
nkeynes@1034
   206
            memcpy( outbuf, vmu->lcd_bitmap, VMU_LCD_SIZE/4 );
nkeynes@1034
   207
        }
nkeynes@1034
   208
        return 0;
nkeynes@1034
   209
        break;
nkeynes@1034
   210
    case MAPLE_FUNC_MEMORY:
nkeynes@1034
   211
        if( vmu->vol != NULL ) {
nkeynes@1034
   212
            vmu_volume_read_block( vmu->vol, pt, block, outbuf );
nkeynes@1034
   213
            return 0;
nkeynes@1034
   214
        }
nkeynes@1034
   215
        // Else fallthrough for now
nkeynes@1034
   216
    case MAPLE_FUNC_CLOCK:
nkeynes@1034
   217
        return MAPLE_ERR_NO_RESPONSE; /* CHECKME */
nkeynes@1034
   218
    default:
nkeynes@1034
   219
        return MAPLE_ERR_FUNC_UNSUP;
nkeynes@1034
   220
    }
nkeynes@1034
   221
}
nkeynes@1034
   222
nkeynes@1034
   223
static int vmu_write_block(struct maple_device *dev, int function, unsigned int pt,
nkeynes@1034
   224
                    uint32_t block, unsigned int phase, 
nkeynes@1034
   225
                    unsigned char *inbuf, unsigned int buflen)
nkeynes@1034
   226
{
nkeynes@1034
   227
    struct vmu_device *vmu = (struct vmu_device *)dev;
nkeynes@1034
   228
    switch( function ) {
nkeynes@1034
   229
    case MAPLE_FUNC_LCD:
nkeynes@1034
   230
        if( pt == 0 && block == 0 && buflen == (VMU_LCD_SIZE/4) ) {
nkeynes@1034
   231
            memcpy( vmu->lcd_bitmap, inbuf, VMU_LCD_SIZE );
nkeynes@1034
   232
        }
nkeynes@1034
   233
        return 0;
nkeynes@1034
   234
        break;
nkeynes@1034
   235
    case MAPLE_FUNC_MEMORY:
nkeynes@1034
   236
        if( vmu->vol != NULL && buflen == (VMU_PHASE_SIZE/4) ) {
nkeynes@1034
   237
            vmu_volume_write_phase( vmu->vol, pt, block, phase, inbuf );
nkeynes@1034
   238
            return 0;
nkeynes@1034
   239
        } 
nkeynes@1034
   240
        // Else fallthrough for now
nkeynes@1034
   241
    case MAPLE_FUNC_CLOCK:
nkeynes@1034
   242
        return MAPLE_ERR_NO_RESPONSE; /* CHECKME */
nkeynes@1034
   243
    default:
nkeynes@1034
   244
        return MAPLE_ERR_FUNC_UNSUP;
nkeynes@1034
   245
    }
nkeynes@1034
   246
}
.