Search
lxdream.org :: lxdream/src/maple/vmu.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/maple/vmu.c
changeset 1034:7044e01148f0
next1035:e3093fd7d1da
author nkeynes
date Wed Jun 24 02:41:12 2009 +0000 (13 years ago)
permissions -rw-r--r--
last change Add initial VMU support
file annotate diff log raw
nkeynes@1034
     1
/**
nkeynes@1034
     2
 * $Id: vmu.c 858 2008-09-02 03:34:00Z nkeynes $
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@1034
    60
static lxdream_config_entry_t vmu_get_config( maple_device_t dev );
nkeynes@1034
    61
static void vmu_set_config_value( maple_device_t dev, unsigned int key, const gchar *value );
nkeynes@1034
    62
static int vmu_get_condition( maple_device_t dev, int function, unsigned char *outbuf,
nkeynes@1034
    63
                              unsigned int *outlen );
nkeynes@1034
    64
static int vmu_get_meminfo( maple_device_t dev, int function, unsigned int pt, 
nkeynes@1034
    65
                            unsigned char *outbuf, unsigned int *outlen );
nkeynes@1034
    66
static void vmu_attach(struct maple_device *dev);
nkeynes@1034
    67
static void vmu_detach(struct maple_device *dev);
nkeynes@1034
    68
static int vmu_read_block(struct maple_device *dev, int function, unsigned int pt,
nkeynes@1034
    69
                   uint32_t block, unsigned int phase, 
nkeynes@1034
    70
                   unsigned char *outbuf, unsigned int *buflen);
nkeynes@1034
    71
static int vmu_write_block(struct maple_device *dev, int function, unsigned int pt,
nkeynes@1034
    72
                    uint32_t block, unsigned int phase, 
nkeynes@1034
    73
                    unsigned char *inbuf, unsigned int buflen);
nkeynes@1034
    74
nkeynes@1034
    75
typedef struct vmu_device {
nkeynes@1034
    76
    struct maple_device dev;
nkeynes@1034
    77
    vmu_volume_t vol;
nkeynes@1034
    78
    char lcd_bitmap[VMU_LCD_SIZE]; /* 48x32 bitmap */
nkeynes@1034
    79
    struct lxdream_config_entry config[VMU_CONFIG_ENTRIES+1];
nkeynes@1034
    80
} *vmu_device_t;
nkeynes@1034
    81
nkeynes@1034
    82
struct maple_device_class vmu_class = { "Sega VMU", MAPLE_GRAB_DONTCARE, vmu_new };
nkeynes@1034
    83
nkeynes@1034
    84
static struct vmu_device base_vmu = {
nkeynes@1034
    85
        { MAPLE_DEVICE_TAG, &vmu_class,
nkeynes@1034
    86
          VMU_IDENT, VMU_VERSION, 
nkeynes@1034
    87
          vmu_get_config, vmu_set_config_value, 
nkeynes@1034
    88
          vmu_attach, vmu_detach, vmu_destroy,
nkeynes@1034
    89
          vmu_clone, NULL, NULL, vmu_get_condition, NULL,
nkeynes@1034
    90
          vmu_get_meminfo, vmu_read_block, vmu_write_block, NULL, NULL },
nkeynes@1034
    91
          NULL, {0}, 
nkeynes@1034
    92
          {{ "volume", N_("Volume"), CONFIG_TYPE_FILE },
nkeynes@1034
    93
           { NULL, CONFIG_TYPE_NONE }} };
nkeynes@1034
    94
nkeynes@1034
    95
static maple_device_t vmu_new( )
nkeynes@1034
    96
{
nkeynes@1034
    97
    vmu_device_t dev = malloc( sizeof(struct vmu_device) );
nkeynes@1034
    98
    memcpy( dev, &base_vmu, sizeof(base_vmu) );
nkeynes@1034
    99
    return MAPLE_DEVICE(dev);
nkeynes@1034
   100
}
nkeynes@1034
   101
nkeynes@1034
   102
static maple_device_t vmu_clone( maple_device_t srcdevice )
nkeynes@1034
   103
{
nkeynes@1034
   104
    vmu_device_t src = (vmu_device_t)srcdevice;
nkeynes@1034
   105
    vmu_device_t dev = (vmu_device_t)vmu_new();
nkeynes@1034
   106
    lxdream_copy_config_list( dev->config, src->config );
nkeynes@1034
   107
    return MAPLE_DEVICE(dev);
nkeynes@1034
   108
}
nkeynes@1034
   109
nkeynes@1034
   110
static lxdream_config_entry_t vmu_get_config( maple_device_t mdev )
nkeynes@1034
   111
{
nkeynes@1034
   112
    vmu_device_t dev = (vmu_device_t)mdev;
nkeynes@1034
   113
    return dev->config;
nkeynes@1034
   114
}
nkeynes@1034
   115
nkeynes@1034
   116
static void vmu_set_config_value( maple_device_t dev, unsigned int key, const gchar *value )
nkeynes@1034
   117
{
nkeynes@1034
   118
    vmu_device_t vmu = (vmu_device_t)dev;
nkeynes@1034
   119
    assert( key < VMU_CONFIG_ENTRIES );
nkeynes@1034
   120
    
nkeynes@1034
   121
    if( value == vmu->config[key].value ||
nkeynes@1034
   122
        value != NULL && vmu->config[key].value != NULL && strcmp(vmu->config[key].value, value) == 0 ) {
nkeynes@1034
   123
        return; /* Unchanged */
nkeynes@1034
   124
    }
nkeynes@1034
   125
nkeynes@1034
   126
    if( vmu->vol != NULL ) {
nkeynes@1034
   127
        vmulist_detach_vmu(vmu->vol);
nkeynes@1034
   128
    }
nkeynes@1034
   129
    lxdream_set_config_value( &vmu->config[key], value );
nkeynes@1034
   130
    vmu->vol = vmulist_get_vmu_by_filename( value );
nkeynes@1034
   131
    if( vmu->vol != NULL ) {
nkeynes@1034
   132
        vmulist_attach_vmu(vmu->vol, "MAPLE");
nkeynes@1034
   133
    }
nkeynes@1034
   134
}
nkeynes@1034
   135
nkeynes@1034
   136
void vmu_attach(struct maple_device *dev)
nkeynes@1034
   137
{
nkeynes@1034
   138
    vmu_device_t vmu = (vmu_device_t)dev;
nkeynes@1034
   139
    if( vmu->config[0].value != NULL ) {
nkeynes@1034
   140
        vmu->vol = vmulist_get_vmu_by_filename(vmu->config[0].value);
nkeynes@1034
   141
        if( vmu->vol != NULL ) {
nkeynes@1034
   142
            vmulist_attach_vmu(vmu->vol, "MAPLE");
nkeynes@1034
   143
        }
nkeynes@1034
   144
    }
nkeynes@1034
   145
}
nkeynes@1034
   146
nkeynes@1034
   147
static void vmu_detach(struct maple_device *dev)
nkeynes@1034
   148
{
nkeynes@1034
   149
    vmu_device_t vmu = (vmu_device_t)dev;
nkeynes@1034
   150
    if( vmu->vol != NULL ) {
nkeynes@1034
   151
        vmulist_detach_vmu(vmu->vol);
nkeynes@1034
   152
        vmu->vol = NULL;
nkeynes@1034
   153
    }
nkeynes@1034
   154
}
nkeynes@1034
   155
nkeynes@1034
   156
static void vmu_destroy( maple_device_t dev )
nkeynes@1034
   157
{
nkeynes@1034
   158
    vmu_device_t vmu = (vmu_device_t)dev;
nkeynes@1034
   159
    free( dev );
nkeynes@1034
   160
}
nkeynes@1034
   161
nkeynes@1034
   162
static int vmu_get_condition(struct maple_device *dev, int function, 
nkeynes@1034
   163
                      unsigned char *outbuf, unsigned int *buflen)
nkeynes@1034
   164
{
nkeynes@1034
   165
}
nkeynes@1034
   166
static int vmu_set_condition(struct maple_device *dev, int function, 
nkeynes@1034
   167
                      unsigned char *inbuf, unsigned int buflen)
nkeynes@1034
   168
{
nkeynes@1034
   169
    return MAPLE_ERR_NO_RESPONSE; /* CHECKME */
nkeynes@1034
   170
}
nkeynes@1034
   171
nkeynes@1034
   172
static int vmu_get_meminfo(struct maple_device *dev, int function, unsigned int pt, 
nkeynes@1034
   173
                           unsigned char *outbuf, unsigned int *buflen)
nkeynes@1034
   174
{
nkeynes@1034
   175
    struct vmu_device *vmu = (struct vmu_device *)dev;
nkeynes@1034
   176
    switch(function) {
nkeynes@1034
   177
    case MAPLE_FUNC_MEMORY:
nkeynes@1034
   178
        if( vmu->vol != NULL ) {
nkeynes@1034
   179
            const struct vmu_volume_metadata *md = vmu_volume_get_metadata( vmu->vol, pt ); 
nkeynes@1034
   180
            memcpy( outbuf, md, sizeof(struct vmu_volume_metadata) );
nkeynes@1034
   181
            *buflen = sizeof(struct vmu_volume_metadata);
nkeynes@1034
   182
            return 0;
nkeynes@1034
   183
        } // Else fallthrough 
nkeynes@1034
   184
    case MAPLE_FUNC_LCD:
nkeynes@1034
   185
    case MAPLE_FUNC_CLOCK:
nkeynes@1034
   186
        return MAPLE_ERR_NO_RESPONSE;
nkeynes@1034
   187
    default:
nkeynes@1034
   188
        return MAPLE_ERR_FUNC_UNSUP;
nkeynes@1034
   189
    }
nkeynes@1034
   190
nkeynes@1034
   191
}
nkeynes@1034
   192
static int vmu_read_block(struct maple_device *dev, int function, unsigned int pt,
nkeynes@1034
   193
                   uint32_t block, unsigned int phase, 
nkeynes@1034
   194
                   unsigned char *outbuf, unsigned int *buflen)
nkeynes@1034
   195
{
nkeynes@1034
   196
    struct vmu_device *vmu = (struct vmu_device *)dev;
nkeynes@1034
   197
    switch( function ) {
nkeynes@1034
   198
    case MAPLE_FUNC_LCD:
nkeynes@1034
   199
        if( pt == 0 && block == 0 ) {
nkeynes@1034
   200
            *buflen = VMU_LCD_SIZE/4;
nkeynes@1034
   201
            memcpy( outbuf, vmu->lcd_bitmap, VMU_LCD_SIZE/4 );
nkeynes@1034
   202
        }
nkeynes@1034
   203
        return 0;
nkeynes@1034
   204
        break;
nkeynes@1034
   205
    case MAPLE_FUNC_MEMORY:
nkeynes@1034
   206
        if( vmu->vol != NULL ) {
nkeynes@1034
   207
            vmu_volume_read_block( vmu->vol, pt, block, outbuf );
nkeynes@1034
   208
            return 0;
nkeynes@1034
   209
        }
nkeynes@1034
   210
        // Else fallthrough for now
nkeynes@1034
   211
    case MAPLE_FUNC_CLOCK:
nkeynes@1034
   212
        return MAPLE_ERR_NO_RESPONSE; /* CHECKME */
nkeynes@1034
   213
    default:
nkeynes@1034
   214
        return MAPLE_ERR_FUNC_UNSUP;
nkeynes@1034
   215
    }
nkeynes@1034
   216
}
nkeynes@1034
   217
nkeynes@1034
   218
static int vmu_write_block(struct maple_device *dev, int function, unsigned int pt,
nkeynes@1034
   219
                    uint32_t block, unsigned int phase, 
nkeynes@1034
   220
                    unsigned char *inbuf, unsigned int buflen)
nkeynes@1034
   221
{
nkeynes@1034
   222
    struct vmu_device *vmu = (struct vmu_device *)dev;
nkeynes@1034
   223
    switch( function ) {
nkeynes@1034
   224
    case MAPLE_FUNC_LCD:
nkeynes@1034
   225
        if( pt == 0 && block == 0 && buflen == (VMU_LCD_SIZE/4) ) {
nkeynes@1034
   226
            memcpy( vmu->lcd_bitmap, inbuf, VMU_LCD_SIZE );
nkeynes@1034
   227
        }
nkeynes@1034
   228
        return 0;
nkeynes@1034
   229
        break;
nkeynes@1034
   230
    case MAPLE_FUNC_MEMORY:
nkeynes@1034
   231
        if( vmu->vol != NULL && buflen == (VMU_PHASE_SIZE/4) ) {
nkeynes@1034
   232
            vmu_volume_write_phase( vmu->vol, pt, block, phase, inbuf );
nkeynes@1034
   233
            return 0;
nkeynes@1034
   234
        } 
nkeynes@1034
   235
        // Else fallthrough for now
nkeynes@1034
   236
    case MAPLE_FUNC_CLOCK:
nkeynes@1034
   237
        return MAPLE_ERR_NO_RESPONSE; /* CHECKME */
nkeynes@1034
   238
    default:
nkeynes@1034
   239
        return MAPLE_ERR_FUNC_UNSUP;
nkeynes@1034
   240
    }
nkeynes@1034
   241
}
.