source: mainline/uspace/srv/bd/gxe_bd/gxe_bd.c@ 8559fa0

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8559fa0 was f73b291, checked in by Martin Decky <martin@…>, 13 years ago

libblock.{c|h} → block.{c|h}

  • Property mode set to 100644
File size: 7.6 KB
Line 
1/*
2 * Copyright (c) 2009 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup bd
30 * @{
31 */
32
33/**
34 * @file
35 * @brief GXemul disk driver
36 */
37
38#include <stdio.h>
39#include <libarch/ddi.h>
40#include <ddi.h>
41#include <async.h>
42#include <as.h>
43#include <bd_srv.h>
44#include <fibril_synch.h>
45#include <loc.h>
46#include <sys/types.h>
47#include <errno.h>
48#include <macros.h>
49#include <task.h>
50
51#define NAME "gxe_bd"
52#define NAMESPACE "bd"
53
54enum {
55 CTL_READ_START = 0,
56 CTL_WRITE_START = 1,
57};
58
59enum {
60 STATUS_FAILURE = 0
61};
62
63enum {
64 MAX_DISKS = 2
65};
66
67/** GXE disk hardware registers */
68typedef struct {
69 uint32_t offset_lo;
70 uint32_t pad0;
71 uint32_t offset_hi;
72 uint32_t pad1;
73
74 uint32_t disk_id;
75 uint32_t pad2[3];
76
77 uint32_t control;
78 uint32_t pad3[3];
79
80 uint32_t status;
81
82 uint32_t pad4[3];
83 uint8_t pad5[0x3fc0];
84
85 uint8_t buffer[512];
86} gxe_bd_hw_t;
87
88/** GXE block device soft state */
89typedef struct {
90 /** Block device service structure */
91 bd_srvs_t bds;
92 int disk_id;
93} gxe_bd_t;
94
95static const size_t block_size = 512;
96
97static uintptr_t dev_physical = 0x13000000;
98static gxe_bd_hw_t *dev;
99
100static service_id_t service_id[MAX_DISKS];
101
102static fibril_mutex_t dev_lock[MAX_DISKS];
103
104static gxe_bd_t gxe_bd[MAX_DISKS];
105
106static int gxe_bd_init(void);
107static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *);
108static int gxe_bd_read_block(int disk_id, uint64_t ba, void *buf);
109static int gxe_bd_write_block(int disk_id, uint64_t ba, const void *buf);
110
111static int gxe_bd_open(bd_srvs_t *, bd_srv_t *);
112static int gxe_bd_close(bd_srv_t *);
113static int gxe_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
114static int gxe_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
115static int gxe_bd_get_block_size(bd_srv_t *, size_t *);
116static int gxe_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
117
118static bd_ops_t gxe_bd_ops = {
119 .open = gxe_bd_open,
120 .close = gxe_bd_close,
121 .read_blocks = gxe_bd_read_blocks,
122 .write_blocks = gxe_bd_write_blocks,
123 .get_block_size = gxe_bd_get_block_size,
124 .get_num_blocks = gxe_bd_get_num_blocks
125};
126
127static gxe_bd_t *bd_srv_gxe(bd_srv_t *bd)
128{
129 return (gxe_bd_t *) bd->srvs->sarg;
130}
131
132int main(int argc, char **argv)
133{
134 printf(NAME ": GXemul disk driver\n");
135
136 if (gxe_bd_init() != EOK)
137 return -1;
138
139 printf(NAME ": Accepting connections\n");
140 task_retval(0);
141 async_manager();
142
143 /* Not reached */
144 return 0;
145}
146
147static int gxe_bd_init(void)
148{
149 async_set_client_connection(gxe_bd_connection);
150 int rc = loc_server_register(NAME);
151 if (rc != EOK) {
152 printf("%s: Unable to register driver.\n", NAME);
153 return rc;
154 }
155
156 void *vaddr;
157 rc = pio_enable((void *) dev_physical, sizeof(gxe_bd_hw_t), &vaddr);
158 if (rc != EOK) {
159 printf("%s: Could not initialize device I/O space.\n", NAME);
160 return rc;
161 }
162
163 dev = vaddr;
164
165 for (unsigned int i = 0; i < MAX_DISKS; i++) {
166 char name[16];
167
168 bd_srvs_init(&gxe_bd[i].bds);
169 gxe_bd[i].bds.ops = &gxe_bd_ops;
170 gxe_bd[i].bds.sarg = (void *)&gxe_bd[i];
171
172 snprintf(name, 16, "%s/disk%u", NAMESPACE, i);
173 rc = loc_service_register(name, &service_id[i]);
174 if (rc != EOK) {
175 printf("%s: Unable to register device %s.\n", NAME,
176 name);
177 return rc;
178 }
179
180 fibril_mutex_initialize(&dev_lock[i]);
181 }
182
183 return EOK;
184}
185
186static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
187{
188 service_id_t dsid;
189 int disk_id, i;
190
191 /* Get the device handle. */
192 dsid = IPC_GET_ARG1(*icall);
193
194 /* Determine which disk device is the client connecting to. */
195 disk_id = -1;
196 for (i = 0; i < MAX_DISKS; i++)
197 if (service_id[i] == dsid)
198 disk_id = i;
199
200 if (disk_id < 0) {
201 async_answer_0(iid, EINVAL);
202 return;
203 }
204
205 bd_conn(iid, icall, &gxe_bd[disk_id].bds);
206}
207
208/** Open device. */
209static int gxe_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
210{
211 return EOK;
212}
213
214/** Close device. */
215static int gxe_bd_close(bd_srv_t *bd)
216{
217 return EOK;
218}
219
220/** Read multiple blocks from the device. */
221static int gxe_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
222 void *buf, size_t size)
223{
224 int disk_id = bd_srv_gxe(bd)->disk_id;
225 int rc;
226
227 if (size < cnt * block_size)
228 return EINVAL;
229
230 while (cnt > 0) {
231 rc = gxe_bd_read_block(disk_id, ba, buf);
232 if (rc != EOK)
233 return rc;
234
235 ++ba;
236 --cnt;
237 buf += block_size;
238 }
239
240 return EOK;
241}
242
243/** Write multiple blocks to the device. */
244static int gxe_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
245 const void *buf, size_t size)
246{
247 int disk_id = bd_srv_gxe(bd)->disk_id;
248 int rc;
249
250 if (size < cnt * block_size)
251 return EINVAL;
252
253 while (cnt > 0) {
254 rc = gxe_bd_write_block(disk_id, ba, buf);
255 if (rc != EOK)
256 return rc;
257
258 ++ba;
259 --cnt;
260 buf += block_size;
261 }
262
263 return EOK;
264}
265
266/** Get device block size. */
267static int gxe_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
268{
269 *rsize = block_size;
270 return EOK;
271}
272
273/** Get number of blocks on device. */
274static int gxe_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
275{
276 return ENOTSUP;
277}
278
279/** Read a block from the device. */
280static int gxe_bd_read_block(int disk_id, uint64_t ba, void *buf)
281{
282 uint32_t status;
283 uint64_t byte_addr;
284 size_t i;
285 uint32_t w;
286
287 byte_addr = ba * block_size;
288
289 fibril_mutex_lock(&dev_lock[disk_id]);
290 pio_write_32(&dev->offset_lo, (uint32_t) byte_addr);
291 pio_write_32(&dev->offset_hi, byte_addr >> 32);
292 pio_write_32(&dev->disk_id, disk_id);
293 pio_write_32(&dev->control, CTL_READ_START);
294
295 status = pio_read_32(&dev->status);
296 if (status == STATUS_FAILURE) {
297 fibril_mutex_unlock(&dev_lock[disk_id]);
298 return EIO;
299 }
300
301 for (i = 0; i < block_size; i++) {
302 ((uint8_t *) buf)[i] = w = pio_read_8(&dev->buffer[i]);
303 }
304
305 fibril_mutex_unlock(&dev_lock[disk_id]);
306 return EOK;
307}
308
309/** Write a block to the device. */
310static int gxe_bd_write_block(int disk_id, uint64_t ba, const void *buf)
311{
312 uint32_t status;
313 uint64_t byte_addr;
314 size_t i;
315
316 byte_addr = ba * block_size;
317
318 fibril_mutex_lock(&dev_lock[disk_id]);
319
320 for (i = 0; i < block_size; i++) {
321 pio_write_8(&dev->buffer[i], ((const uint8_t *) buf)[i]);
322 }
323
324 pio_write_32(&dev->offset_lo, (uint32_t) byte_addr);
325 pio_write_32(&dev->offset_hi, byte_addr >> 32);
326 pio_write_32(&dev->disk_id, disk_id);
327 pio_write_32(&dev->control, CTL_WRITE_START);
328
329 status = pio_read_32(&dev->status);
330 if (status == STATUS_FAILURE) {
331 fibril_mutex_unlock(&dev_lock[disk_id]);
332 return EIO;
333 }
334
335 fibril_mutex_unlock(&dev_lock[disk_id]);
336 return EOK;
337}
338
339/**
340 * @}
341 */
Note: See TracBrowser for help on using the repository browser.