00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00038 #include <stdio.h>
00039 #include <libarch/ddi.h>
00040 #include <ddi.h>
00041 #include <ipc/bd.h>
00042 #include <async.h>
00043 #include <as.h>
00044 #include <fibril_synch.h>
00045 #include <devmap.h>
00046 #include <sys/types.h>
00047 #include <errno.h>
00048 #include <macros.h>
00049 #include <task.h>
00050
00051 #define NAME "gxe_bd"
00052 #define NAMESPACE "bd"
00053
00054 enum {
00055 CTL_READ_START = 0,
00056 CTL_WRITE_START = 1,
00057 };
00058
00059 enum {
00060 STATUS_FAILURE = 0
00061 };
00062
00063 enum {
00064 MAX_DISKS = 2
00065 };
00066
00067 typedef struct {
00068 uint32_t offset_lo;
00069 uint32_t pad0;
00070 uint32_t offset_hi;
00071 uint32_t pad1;
00072
00073 uint32_t disk_id;
00074 uint32_t pad2[3];
00075
00076 uint32_t control;
00077 uint32_t pad3[3];
00078
00079 uint32_t status;
00080
00081 uint32_t pad4[3];
00082 uint8_t pad5[0x3fc0];
00083
00084 uint8_t buffer[512];
00085 } gxe_bd_t;
00086
00087
00088 static const size_t block_size = 512;
00089 static size_t comm_size;
00090
00091 static uintptr_t dev_physical = 0x13000000;
00092 static gxe_bd_t *dev;
00093
00094 static devmap_handle_t devmap_handle[MAX_DISKS];
00095
00096 static fibril_mutex_t dev_lock[MAX_DISKS];
00097
00098 static int gxe_bd_init(void);
00099 static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall);
00100 static int gxe_bd_read_blocks(int disk_id, uint64_t ba, unsigned cnt,
00101 void *buf);
00102 static int gxe_bd_write_blocks(int disk_id, uint64_t ba, unsigned cnt,
00103 const void *buf);
00104 static int gxe_bd_read_block(int disk_id, uint64_t ba, void *buf);
00105 static int gxe_bd_write_block(int disk_id, uint64_t ba, const void *buf);
00106
00107 int main(int argc, char **argv)
00108 {
00109 printf(NAME ": GXemul disk driver\n");
00110
00111 if (gxe_bd_init() != EOK)
00112 return -1;
00113
00114 printf(NAME ": Accepting connections\n");
00115 task_retval(0);
00116 async_manager();
00117
00118
00119 return 0;
00120 }
00121
00122 static int gxe_bd_init(void)
00123 {
00124 void *vaddr;
00125 int rc, i;
00126 char name[16];
00127
00128 rc = devmap_driver_register(NAME, gxe_bd_connection);
00129 if (rc < 0) {
00130 printf(NAME ": Unable to register driver.\n");
00131 return rc;
00132 }
00133
00134 rc = pio_enable((void *) dev_physical, sizeof(gxe_bd_t), &vaddr);
00135 if (rc != EOK) {
00136 printf(NAME ": Could not initialize device I/O space.\n");
00137 return rc;
00138 }
00139
00140 dev = vaddr;
00141
00142 for (i = 0; i < MAX_DISKS; i++) {
00143 snprintf(name, 16, "%s/disk%d", NAMESPACE, i);
00144 rc = devmap_device_register(name, &devmap_handle[i]);
00145 if (rc != EOK) {
00146 printf(NAME ": Unable to register device %s.\n", name);
00147 return rc;
00148 }
00149 fibril_mutex_initialize(&dev_lock[i]);
00150 }
00151
00152 return EOK;
00153 }
00154
00155 static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall)
00156 {
00157 void *fs_va = NULL;
00158 ipc_callid_t callid;
00159 ipc_call_t call;
00160 sysarg_t method;
00161 devmap_handle_t dh;
00162 unsigned int flags;
00163 int retval;
00164 uint64_t ba;
00165 unsigned cnt;
00166 int disk_id, i;
00167
00168
00169 dh = IPC_GET_ARG1(*icall);
00170
00171
00172 disk_id = -1;
00173 for (i = 0; i < MAX_DISKS; i++)
00174 if (devmap_handle[i] == dh)
00175 disk_id = i;
00176
00177 if (disk_id < 0) {
00178 async_answer_0(iid, EINVAL);
00179 return;
00180 }
00181
00182
00183 async_answer_0(iid, EOK);
00184
00185 if (!async_share_out_receive(&callid, &comm_size, &flags)) {
00186 async_answer_0(callid, EHANGUP);
00187 return;
00188 }
00189
00190 if (comm_size < block_size) {
00191 async_answer_0(callid, EHANGUP);
00192 return;
00193 }
00194
00195 fs_va = as_get_mappable_page(comm_size);
00196 if (fs_va == NULL) {
00197 async_answer_0(callid, EHANGUP);
00198 return;
00199 }
00200
00201 (void) async_share_out_finalize(callid, fs_va);
00202
00203 while (1) {
00204 callid = async_get_call(&call);
00205 method = IPC_GET_IMETHOD(call);
00206 switch (method) {
00207 case IPC_M_PHONE_HUNGUP:
00208
00209 async_answer_0(callid, EOK);
00210 return;
00211 case BD_READ_BLOCKS:
00212 ba = MERGE_LOUP32(IPC_GET_ARG1(call),
00213 IPC_GET_ARG2(call));
00214 cnt = IPC_GET_ARG3(call);
00215 if (cnt * block_size > comm_size) {
00216 retval = ELIMIT;
00217 break;
00218 }
00219 retval = gxe_bd_read_blocks(disk_id, ba, cnt, fs_va);
00220 break;
00221 case BD_WRITE_BLOCKS:
00222 ba = MERGE_LOUP32(IPC_GET_ARG1(call),
00223 IPC_GET_ARG2(call));
00224 cnt = IPC_GET_ARG3(call);
00225 if (cnt * block_size > comm_size) {
00226 retval = ELIMIT;
00227 break;
00228 }
00229 retval = gxe_bd_write_blocks(disk_id, ba, cnt, fs_va);
00230 break;
00231 case BD_GET_BLOCK_SIZE:
00232 async_answer_1(callid, EOK, block_size);
00233 continue;
00234 case BD_GET_NUM_BLOCKS:
00235 retval = ENOTSUP;
00236 break;
00237 default:
00238 retval = EINVAL;
00239 break;
00240 }
00241 async_answer_0(callid, retval);
00242 }
00243 }
00244
00246 static int gxe_bd_read_blocks(int disk_id, uint64_t ba, unsigned cnt,
00247 void *buf) {
00248
00249 int rc;
00250
00251 while (cnt > 0) {
00252 rc = gxe_bd_read_block(disk_id, ba, buf);
00253 if (rc != EOK)
00254 return rc;
00255
00256 ++ba;
00257 --cnt;
00258 buf += block_size;
00259 }
00260
00261 return EOK;
00262 }
00263
00265 static int gxe_bd_write_blocks(int disk_id, uint64_t ba, unsigned cnt,
00266 const void *buf) {
00267
00268 int rc;
00269
00270 while (cnt > 0) {
00271 rc = gxe_bd_write_block(disk_id, ba, buf);
00272 if (rc != EOK)
00273 return rc;
00274
00275 ++ba;
00276 --cnt;
00277 buf += block_size;
00278 }
00279
00280 return EOK;
00281 }
00282
00284 static int gxe_bd_read_block(int disk_id, uint64_t ba, void *buf)
00285 {
00286 uint32_t status;
00287 uint64_t byte_addr;
00288 size_t i;
00289 uint32_t w;
00290
00291 byte_addr = ba * block_size;
00292
00293 fibril_mutex_lock(&dev_lock[disk_id]);
00294 pio_write_32(&dev->offset_lo, (uint32_t) byte_addr);
00295 pio_write_32(&dev->offset_hi, byte_addr >> 32);
00296 pio_write_32(&dev->disk_id, disk_id);
00297 pio_write_32(&dev->control, CTL_READ_START);
00298
00299 status = pio_read_32(&dev->status);
00300 if (status == STATUS_FAILURE) {
00301 fibril_mutex_unlock(&dev_lock[disk_id]);
00302 return EIO;
00303 }
00304
00305 for (i = 0; i < block_size; i++) {
00306 ((uint8_t *) buf)[i] = w = pio_read_8(&dev->buffer[i]);
00307 }
00308
00309 fibril_mutex_unlock(&dev_lock[disk_id]);
00310 return EOK;
00311 }
00312
00314 static int gxe_bd_write_block(int disk_id, uint64_t ba, const void *buf)
00315 {
00316 uint32_t status;
00317 uint64_t byte_addr;
00318 size_t i;
00319
00320 byte_addr = ba * block_size;
00321
00322 fibril_mutex_lock(&dev_lock[disk_id]);
00323
00324 for (i = 0; i < block_size; i++) {
00325 pio_write_8(&dev->buffer[i], ((const uint8_t *) buf)[i]);
00326 }
00327
00328 pio_write_32(&dev->offset_lo, (uint32_t) byte_addr);
00329 pio_write_32(&dev->offset_hi, byte_addr >> 32);
00330 pio_write_32(&dev->disk_id, disk_id);
00331 pio_write_32(&dev->control, CTL_WRITE_START);
00332
00333 status = pio_read_32(&dev->status);
00334 if (status == STATUS_FAILURE) {
00335 fibril_mutex_unlock(&dev_lock[disk_id]);
00336 return EIO;
00337 }
00338
00339 fibril_mutex_unlock(&dev_lock[disk_id]);
00340 return EOK;
00341 }
00342