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