filename | src/maple/vmu.c |
changeset | 1172:43eef98ff265 |
prev | 1088:cf3900ae8acc |
next | 1298:d0eb2307b847 |
author | Nathan Keynes <nkeynes@lxdream.org> |
date | Wed May 11 08:45:31 2011 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | Fix returned maple packet length for VMU block reads and get-mem-info Fix returned block-id in block reads to match the input block-id. |
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 if( vmu_volume_read_block( vmu->vol, pt, block, outbuf ) ) {
213 *buflen = VMU_BLOCK_SIZE/4;
214 }
215 return 0;
216 }
217 // Else fallthrough for now
218 case MAPLE_FUNC_CLOCK:
219 return MAPLE_ERR_NO_RESPONSE; /* CHECKME */
220 default:
221 return MAPLE_ERR_FUNC_UNSUP;
222 }
223 }
225 static int vmu_write_block(struct maple_device *dev, int function, unsigned int pt,
226 uint32_t block, unsigned int phase,
227 unsigned char *inbuf, unsigned int buflen)
228 {
229 struct vmu_device *vmu = (struct vmu_device *)dev;
230 switch( function ) {
231 case MAPLE_FUNC_LCD:
232 if( pt == 0 && block == 0 && buflen == (VMU_LCD_SIZE/4) ) {
233 memcpy( vmu->lcd_bitmap, inbuf, VMU_LCD_SIZE );
234 }
235 return 0;
236 break;
237 case MAPLE_FUNC_MEMORY:
238 if( vmu->vol != NULL && buflen == (VMU_PHASE_SIZE/4) ) {
239 vmu_volume_write_phase( vmu->vol, pt, block, phase, inbuf );
240 return 0;
241 }
242 // Else fallthrough for now
243 case MAPLE_FUNC_CLOCK:
244 return MAPLE_ERR_NO_RESPONSE; /* CHECKME */
245 default:
246 return MAPLE_ERR_FUNC_UNSUP;
247 }
248 }
.