Search
lxdream.org :: lxdream/src/maple/vmu.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/maple/vmu.c
changeset 1298:d0eb2307b847
prev1172:43eef98ff265
author nkeynes
date Wed Feb 04 08:38:23 2015 +1000 (5 years ago)
permissions -rw-r--r--
last change Fix assorted compile warnings reported by Clang
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@1298
    65
static int vmu_set_condition(struct maple_device *dev, int function, 
nkeynes@1298
    66
                      unsigned char *inbuf, unsigned int buflen);
nkeynes@1034
    67
static int vmu_get_meminfo( maple_device_t dev, int function, unsigned int pt, 
nkeynes@1034
    68
                            unsigned char *outbuf, unsigned int *outlen );
nkeynes@1034
    69
static void vmu_attach(struct maple_device *dev);
nkeynes@1034
    70
static void vmu_detach(struct maple_device *dev);
nkeynes@1034
    71
static int vmu_read_block(struct maple_device *dev, int function, unsigned int pt,
nkeynes@1034
    72
                   uint32_t block, unsigned int phase, 
nkeynes@1034
    73
                   unsigned char *outbuf, unsigned int *buflen);
nkeynes@1034
    74
static int vmu_write_block(struct maple_device *dev, int function, unsigned int pt,
nkeynes@1034
    75
                    uint32_t block, unsigned int phase, 
nkeynes@1034
    76
                    unsigned char *inbuf, unsigned int buflen);
nkeynes@1034
    77
nkeynes@1034
    78
typedef struct vmu_device {
nkeynes@1034
    79
    struct maple_device dev;
nkeynes@1034
    80
    vmu_volume_t vol;
nkeynes@1034
    81
    char lcd_bitmap[VMU_LCD_SIZE]; /* 48x32 bitmap */
nkeynes@1072
    82
    struct lxdream_config_group config;
nkeynes@1034
    83
} *vmu_device_t;
nkeynes@1034
    84
nkeynes@1072
    85
#define DEV_FROM_CONFIG_GROUP(grp)  ((vmu_device_t)(((char *)grp) - offsetof( struct vmu_device, config )))
nkeynes@1072
    86
nkeynes@1034
    87
struct maple_device_class vmu_class = { "Sega VMU", MAPLE_GRAB_DONTCARE, vmu_new };
nkeynes@1034
    88
nkeynes@1034
    89
static struct vmu_device base_vmu = {
nkeynes@1034
    90
        { MAPLE_DEVICE_TAG, &vmu_class,
nkeynes@1034
    91
          VMU_IDENT, VMU_VERSION, 
nkeynes@1072
    92
          vmu_get_config,
nkeynes@1034
    93
          vmu_attach, vmu_detach, vmu_destroy,
nkeynes@1298
    94
          vmu_clone, NULL, NULL, vmu_get_condition, vmu_set_condition,
nkeynes@1034
    95
          vmu_get_meminfo, vmu_read_block, vmu_write_block, NULL, NULL },
nkeynes@1072
    96
          NULL, {0},
nkeynes@1072
    97
          {"Sega VMU", vmu_set_config_value, NULL, NULL,
nkeynes@1034
    98
          {{ "volume", N_("Volume"), CONFIG_TYPE_FILE },
nkeynes@1072
    99
           { NULL, CONFIG_TYPE_NONE }}} };
nkeynes@1072
   100
nkeynes@1072
   101
nkeynes@1034
   102
nkeynes@1034
   103
static maple_device_t vmu_new( )
nkeynes@1034
   104
{
nkeynes@1034
   105
    vmu_device_t dev = malloc( sizeof(struct vmu_device) );
nkeynes@1088
   106
    memcpy( dev, &base_vmu, sizeof(base_vmu) );
nkeynes@1072
   107
    dev->config.data = dev;
nkeynes@1034
   108
    return MAPLE_DEVICE(dev);
nkeynes@1034
   109
}
nkeynes@1034
   110
nkeynes@1034
   111
static maple_device_t vmu_clone( maple_device_t srcdevice )
nkeynes@1034
   112
{
nkeynes@1034
   113
    vmu_device_t src = (vmu_device_t)srcdevice;
nkeynes@1034
   114
    vmu_device_t dev = (vmu_device_t)vmu_new();
nkeynes@1072
   115
    lxdream_copy_config_group( &dev->config, &src->config );
nkeynes@1072
   116
    dev->config.data = dev;
nkeynes@1034
   117
    return MAPLE_DEVICE(dev);
nkeynes@1034
   118
}
nkeynes@1034
   119
nkeynes@1072
   120
static lxdream_config_group_t vmu_get_config( maple_device_t mdev )
nkeynes@1034
   121
{
nkeynes@1034
   122
    vmu_device_t dev = (vmu_device_t)mdev;
nkeynes@1072
   123
    return &dev->config;
nkeynes@1034
   124
}
nkeynes@1034
   125
nkeynes@1072
   126
static gboolean vmu_set_config_value( void *data, lxdream_config_group_t group, unsigned int key,
nkeynes@1072
   127
                                      const gchar *oldvalue, const gchar *value )
nkeynes@1034
   128
{
nkeynes@1072
   129
    vmu_device_t vmu = (vmu_device_t)data;
nkeynes@1034
   130
    assert( key < VMU_CONFIG_ENTRIES );
nkeynes@1034
   131
    
nkeynes@1034
   132
    if( vmu->vol != NULL ) {
nkeynes@1034
   133
        vmulist_detach_vmu(vmu->vol);
nkeynes@1034
   134
    }
nkeynes@1034
   135
    vmu->vol = vmulist_get_vmu_by_filename( value );
nkeynes@1034
   136
    if( vmu->vol != NULL ) {
nkeynes@1034
   137
        vmulist_attach_vmu(vmu->vol, "MAPLE");
nkeynes@1034
   138
    }
nkeynes@1072
   139
    return TRUE;
nkeynes@1034
   140
}
nkeynes@1034
   141
nkeynes@1034
   142
void vmu_attach(struct maple_device *dev)
nkeynes@1034
   143
{
nkeynes@1034
   144
    vmu_device_t vmu = (vmu_device_t)dev;
nkeynes@1072
   145
    if( vmu->config.params[0].value != NULL ) {
nkeynes@1072
   146
        vmu->vol = vmulist_get_vmu_by_filename(vmu->config.params[0].value);
nkeynes@1034
   147
        if( vmu->vol != NULL ) {
nkeynes@1034
   148
            vmulist_attach_vmu(vmu->vol, "MAPLE");
nkeynes@1034
   149
        }
nkeynes@1034
   150
    }
nkeynes@1034
   151
}
nkeynes@1034
   152
nkeynes@1034
   153
static void vmu_detach(struct maple_device *dev)
nkeynes@1034
   154
{
nkeynes@1034
   155
    vmu_device_t vmu = (vmu_device_t)dev;
nkeynes@1034
   156
    if( vmu->vol != NULL ) {
nkeynes@1034
   157
        vmulist_detach_vmu(vmu->vol);
nkeynes@1034
   158
        vmu->vol = NULL;
nkeynes@1034
   159
    }
nkeynes@1034
   160
}
nkeynes@1034
   161
nkeynes@1034
   162
static void vmu_destroy( maple_device_t dev )
nkeynes@1034
   163
{
nkeynes@1034
   164
    vmu_device_t vmu = (vmu_device_t)dev;
nkeynes@1298
   165
    free( vmu );
nkeynes@1034
   166
}
nkeynes@1034
   167
nkeynes@1034
   168
static int vmu_get_condition(struct maple_device *dev, int function, 
nkeynes@1034
   169
                      unsigned char *outbuf, unsigned int *buflen)
nkeynes@1034
   170
{
nkeynes@1072
   171
    return 0;
nkeynes@1034
   172
}
nkeynes@1034
   173
static int vmu_set_condition(struct maple_device *dev, int function, 
nkeynes@1034
   174
                      unsigned char *inbuf, unsigned int buflen)
nkeynes@1034
   175
{
nkeynes@1034
   176
    return MAPLE_ERR_NO_RESPONSE; /* CHECKME */
nkeynes@1034
   177
}
nkeynes@1034
   178
nkeynes@1034
   179
static int vmu_get_meminfo(struct maple_device *dev, int function, unsigned int pt, 
nkeynes@1034
   180
                           unsigned char *outbuf, unsigned int *buflen)
nkeynes@1034
   181
{
nkeynes@1034
   182
    struct vmu_device *vmu = (struct vmu_device *)dev;
nkeynes@1034
   183
    switch(function) {
nkeynes@1034
   184
    case MAPLE_FUNC_MEMORY:
nkeynes@1034
   185
        if( vmu->vol != NULL ) {
nkeynes@1034
   186
            const struct vmu_volume_metadata *md = vmu_volume_get_metadata( vmu->vol, pt ); 
nkeynes@1034
   187
            memcpy( outbuf, md, sizeof(struct vmu_volume_metadata) );
nkeynes@1034
   188
            *buflen = sizeof(struct vmu_volume_metadata);
nkeynes@1034
   189
            return 0;
nkeynes@1034
   190
        } // Else fallthrough 
nkeynes@1034
   191
    case MAPLE_FUNC_LCD:
nkeynes@1034
   192
    case MAPLE_FUNC_CLOCK:
nkeynes@1034
   193
        return MAPLE_ERR_NO_RESPONSE;
nkeynes@1034
   194
    default:
nkeynes@1034
   195
        return MAPLE_ERR_FUNC_UNSUP;
nkeynes@1034
   196
    }
nkeynes@1034
   197
nkeynes@1034
   198
}
nkeynes@1034
   199
static int vmu_read_block(struct maple_device *dev, int function, unsigned int pt,
nkeynes@1034
   200
                   uint32_t block, unsigned int phase, 
nkeynes@1034
   201
                   unsigned char *outbuf, unsigned int *buflen)
nkeynes@1034
   202
{
nkeynes@1034
   203
    struct vmu_device *vmu = (struct vmu_device *)dev;
nkeynes@1034
   204
    switch( function ) {
nkeynes@1034
   205
    case MAPLE_FUNC_LCD:
nkeynes@1034
   206
        if( pt == 0 && block == 0 ) {
nkeynes@1034
   207
            *buflen = VMU_LCD_SIZE/4;
nkeynes@1034
   208
            memcpy( outbuf, vmu->lcd_bitmap, VMU_LCD_SIZE/4 );
nkeynes@1034
   209
        }
nkeynes@1034
   210
        return 0;
nkeynes@1034
   211
        break;
nkeynes@1034
   212
    case MAPLE_FUNC_MEMORY:
nkeynes@1034
   213
        if( vmu->vol != NULL ) {
nkeynes@1172
   214
            if( vmu_volume_read_block( vmu->vol, pt, block, outbuf ) ) {
nkeynes@1172
   215
                *buflen = VMU_BLOCK_SIZE/4;
nkeynes@1172
   216
            }
nkeynes@1034
   217
            return 0;
nkeynes@1034
   218
        }
nkeynes@1034
   219
        // Else fallthrough for now
nkeynes@1034
   220
    case MAPLE_FUNC_CLOCK:
nkeynes@1034
   221
        return MAPLE_ERR_NO_RESPONSE; /* CHECKME */
nkeynes@1034
   222
    default:
nkeynes@1034
   223
        return MAPLE_ERR_FUNC_UNSUP;
nkeynes@1034
   224
    }
nkeynes@1034
   225
}
nkeynes@1034
   226
nkeynes@1034
   227
static int vmu_write_block(struct maple_device *dev, int function, unsigned int pt,
nkeynes@1034
   228
                    uint32_t block, unsigned int phase, 
nkeynes@1034
   229
                    unsigned char *inbuf, unsigned int buflen)
nkeynes@1034
   230
{
nkeynes@1034
   231
    struct vmu_device *vmu = (struct vmu_device *)dev;
nkeynes@1034
   232
    switch( function ) {
nkeynes@1034
   233
    case MAPLE_FUNC_LCD:
nkeynes@1034
   234
        if( pt == 0 && block == 0 && buflen == (VMU_LCD_SIZE/4) ) {
nkeynes@1034
   235
            memcpy( vmu->lcd_bitmap, inbuf, VMU_LCD_SIZE );
nkeynes@1034
   236
        }
nkeynes@1034
   237
        return 0;
nkeynes@1034
   238
        break;
nkeynes@1034
   239
    case MAPLE_FUNC_MEMORY:
nkeynes@1034
   240
        if( vmu->vol != NULL && buflen == (VMU_PHASE_SIZE/4) ) {
nkeynes@1034
   241
            vmu_volume_write_phase( vmu->vol, pt, block, phase, inbuf );
nkeynes@1034
   242
            return 0;
nkeynes@1034
   243
        } 
nkeynes@1034
   244
        // Else fallthrough for now
nkeynes@1034
   245
    case MAPLE_FUNC_CLOCK:
nkeynes@1034
   246
        return MAPLE_ERR_NO_RESPONSE; /* CHECKME */
nkeynes@1034
   247
    default:
nkeynes@1034
   248
        return MAPLE_ERR_FUNC_UNSUP;
nkeynes@1034
   249
    }
nkeynes@1034
   250
}
.