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