source: mainline/uspace/srv/bd/gxe_bd/gxe_bd.c@ 4daee7a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4daee7a was 1ae74c6, checked in by Jan Vesely <jano.vesely@…>, 13 years ago

Fix ddi.h header includes.

  • Property mode set to 100644
File size: 7.5 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 <ddi.h>
40#include <async.h>
41#include <as.h>
42#include <bd_srv.h>
43#include <fibril_synch.h>
44#include <loc.h>
45#include <sys/types.h>
46#include <errno.h>
47#include <macros.h>
48#include <task.h>
49
50#define NAME "gxe_bd"
51#define NAMESPACE "bd"
52
53enum {
54 CTL_READ_START = 0,
55 CTL_WRITE_START = 1,
56};
57
58enum {
59 STATUS_FAILURE = 0
60};
61
62enum {
63 MAX_DISKS = 2
64};
65
66/** GXE disk hardware registers */
67typedef struct {
68 uint32_t offset_lo;
69 uint32_t pad0;
70 uint32_t offset_hi;
71 uint32_t pad1;
72
73 uint32_t disk_id;
74 uint32_t pad2[3];
75
76 uint32_t control;
77 uint32_t pad3[3];
78
79 uint32_t status;
80
81 uint32_t pad4[3];
82 uint8_t pad5[0x3fc0];
83
84 uint8_t buffer[512];
85} gxe_bd_hw_t;
86
87/** GXE block device soft state */
88typedef struct {
89 /** Block device service structure */
90 bd_srvs_t bds;
91 int disk_id;
92} gxe_bd_t;
93
94static const size_t block_size = 512;
95
96static uintptr_t dev_physical = 0x13000000;
97static gxe_bd_hw_t *dev;
98
99static service_id_t service_id[MAX_DISKS];
100
101static fibril_mutex_t dev_lock[MAX_DISKS];
102
103static gxe_bd_t gxe_bd[MAX_DISKS];
104
105static int gxe_bd_init(void);
106static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *);
107static int gxe_bd_read_block(int disk_id, uint64_t ba, void *buf);
108static int gxe_bd_write_block(int disk_id, uint64_t ba, const void *buf);
109
110static int gxe_bd_open(bd_srvs_t *, bd_srv_t *);
111static int gxe_bd_close(bd_srv_t *);
112static int gxe_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
113static int gxe_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
114static int gxe_bd_get_block_size(bd_srv_t *, size_t *);
115static int gxe_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
116
117static bd_ops_t gxe_bd_ops = {
118 .open = gxe_bd_open,
119 .close = gxe_bd_close,
120 .read_blocks = gxe_bd_read_blocks,
121 .write_blocks = gxe_bd_write_blocks,
122 .get_block_size = gxe_bd_get_block_size,
123 .get_num_blocks = gxe_bd_get_num_blocks
124};
125
126static gxe_bd_t *bd_srv_gxe(bd_srv_t *bd)
127{
128 return (gxe_bd_t *) bd->srvs->sarg;
129}
130
131int main(int argc, char **argv)
132{
133 printf(NAME ": GXemul disk driver\n");
134
135 if (gxe_bd_init() != EOK)
136 return -1;
137
138 printf(NAME ": Accepting connections\n");
139 task_retval(0);
140 async_manager();
141
142 /* Not reached */
143 return 0;
144}
145
146static int gxe_bd_init(void)
147{
148 async_set_client_connection(gxe_bd_connection);
149 int rc = loc_server_register(NAME);
150 if (rc != EOK) {
151 printf("%s: Unable to register driver.\n", NAME);
152 return rc;
153 }
154
155 void *vaddr;
156 rc = pio_enable((void *) dev_physical, sizeof(gxe_bd_hw_t), &vaddr);
157 if (rc != EOK) {
158 printf("%s: Could not initialize device I/O space.\n", NAME);
159 return rc;
160 }
161
162 dev = vaddr;
163
164 for (unsigned int i = 0; i < MAX_DISKS; i++) {
165 char name[16];
166
167 bd_srvs_init(&gxe_bd[i].bds);
168 gxe_bd[i].bds.ops = &gxe_bd_ops;
169 gxe_bd[i].bds.sarg = (void *)&gxe_bd[i];
170
171 snprintf(name, 16, "%s/disk%u", NAMESPACE, i);
172 rc = loc_service_register(name, &service_id[i]);
173 if (rc != EOK) {
174 printf("%s: Unable to register device %s.\n", NAME,
175 name);
176 return rc;
177 }
178
179 fibril_mutex_initialize(&dev_lock[i]);
180 }
181
182 return EOK;
183}
184
185static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
186{
187 service_id_t dsid;
188 int disk_id, i;
189
190 /* Get the device handle. */
191 dsid = IPC_GET_ARG1(*icall);
192
193 /* Determine which disk device is the client connecting to. */
194 disk_id = -1;
195 for (i = 0; i < MAX_DISKS; i++)
196 if (service_id[i] == dsid)
197 disk_id = i;
198
199 if (disk_id < 0) {
200 async_answer_0(iid, EINVAL);
201 return;
202 }
203
204 bd_conn(iid, icall, &gxe_bd[disk_id].bds);
205}
206
207/** Open device. */
208static int gxe_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
209{
210 return EOK;
211}
212
213/** Close device. */
214static int gxe_bd_close(bd_srv_t *bd)
215{
216 return EOK;
217}
218
219/** Read multiple blocks from the device. */
220static int gxe_bd_read_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
221 void *buf, size_t size)
222{
223 int disk_id = bd_srv_gxe(bd)->disk_id;
224 int rc;
225
226 if (size < cnt * block_size)
227 return EINVAL;
228
229 while (cnt > 0) {
230 rc = gxe_bd_read_block(disk_id, ba, buf);
231 if (rc != EOK)
232 return rc;
233
234 ++ba;
235 --cnt;
236 buf += block_size;
237 }
238
239 return EOK;
240}
241
242/** Write multiple blocks to the device. */
243static int gxe_bd_write_blocks(bd_srv_t *bd, aoff64_t ba, size_t cnt,
244 const void *buf, size_t size)
245{
246 int disk_id = bd_srv_gxe(bd)->disk_id;
247 int rc;
248
249 if (size < cnt * block_size)
250 return EINVAL;
251
252 while (cnt > 0) {
253 rc = gxe_bd_write_block(disk_id, ba, buf);
254 if (rc != EOK)
255 return rc;
256
257 ++ba;
258 --cnt;
259 buf += block_size;
260 }
261
262 return EOK;
263}
264
265/** Get device block size. */
266static int gxe_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
267{
268 *rsize = block_size;
269 return EOK;
270}
271
272/** Get number of blocks on device. */
273static int gxe_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
274{
275 return ENOTSUP;
276}
277
278/** Read a block from the device. */
279static int gxe_bd_read_block(int disk_id, uint64_t ba, void *buf)
280{
281 uint32_t status;
282 uint64_t byte_addr;
283 size_t i;
284 uint32_t w;
285
286 byte_addr = ba * block_size;
287
288 fibril_mutex_lock(&dev_lock[disk_id]);
289 pio_write_32(&dev->offset_lo, (uint32_t) byte_addr);
290 pio_write_32(&dev->offset_hi, byte_addr >> 32);
291 pio_write_32(&dev->disk_id, disk_id);
292 pio_write_32(&dev->control, CTL_READ_START);
293
294 status = pio_read_32(&dev->status);
295 if (status == STATUS_FAILURE) {
296 fibril_mutex_unlock(&dev_lock[disk_id]);
297 return EIO;
298 }
299
300 for (i = 0; i < block_size; i++) {
301 ((uint8_t *) buf)[i] = w = pio_read_8(&dev->buffer[i]);
302 }
303
304 fibril_mutex_unlock(&dev_lock[disk_id]);
305 return EOK;
306}
307
308/** Write a block to the device. */
309static int gxe_bd_write_block(int disk_id, uint64_t ba, const void *buf)
310{
311 uint32_t status;
312 uint64_t byte_addr;
313 size_t i;
314
315 byte_addr = ba * block_size;
316
317 fibril_mutex_lock(&dev_lock[disk_id]);
318
319 for (i = 0; i < block_size; i++) {
320 pio_write_8(&dev->buffer[i], ((const uint8_t *) buf)[i]);
321 }
322
323 pio_write_32(&dev->offset_lo, (uint32_t) byte_addr);
324 pio_write_32(&dev->offset_hi, byte_addr >> 32);
325 pio_write_32(&dev->disk_id, disk_id);
326 pio_write_32(&dev->control, CTL_WRITE_START);
327
328 status = pio_read_32(&dev->status);
329 if (status == STATUS_FAILURE) {
330 fibril_mutex_unlock(&dev_lock[disk_id]);
331 return EIO;
332 }
333
334 fibril_mutex_unlock(&dev_lock[disk_id]);
335 return EOK;
336}
337
338/**
339 * @}
340 */
Note: See TracBrowser for help on using the repository browser.