Subversion Repositories HelenOS

Rev

Rev 2619 | Rev 2635 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 2619 Rev 2622
1
/*
1
/*
2
 * Copyright (c) 2007 Josef Cejka
2
 * Copyright (c) 2007 Josef Cejka
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
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
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.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
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
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
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
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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
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.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/**
29
/**
30
 * @defgroup devmap Device mapper.
30
 * @defgroup devmap Device mapper.
31
 * @brief   HelenOS device mapper.
31
 * @brief   HelenOS device mapper.
32
 * @{
32
 * @{
33
 */
33
 */
34
 
34
 
35
/** @file
35
/** @file
36
 */
36
 */
37
 
37
 
38
#include <ipc/services.h>
38
#include <ipc/services.h>
39
#include <ipc/ns.h>
39
#include <ipc/ns.h>
40
#include <async.h>
40
#include <async.h>
41
#include <stdio.h>
41
#include <stdio.h>
42
#include <errno.h>
42
#include <errno.h>
43
#include <bool.h>
43
#include <bool.h>
44
#include <futex.h>
44
#include <futex.h>
45
#include <stdlib.h>
45
#include <stdlib.h>
46
#include <string.h>
46
#include <string.h>
47
 
47
 
48
#include "devmap.h"
48
#include "devmap.h"
49
 
49
 
50
 
50
 
51
LIST_INITIALIZE(devices_list);
51
LIST_INITIALIZE(devices_list);
52
LIST_INITIALIZE(drivers_list);
52
LIST_INITIALIZE(drivers_list);
53
 
53
 
54
/* order of locking:
54
/* order of locking:
55
 * drivers_list_futex
55
 * drivers_list_futex
56
 * devices_list_futex
56
 * devices_list_futex
57
 * (devmap_driver_t *)->devices_futex
57
 * (devmap_driver_t *)->devices_futex
58
 * create_handle_futex
58
 * create_handle_futex
59
 **/
59
 **/
60
 
60
 
61
static atomic_t devices_list_futex = FUTEX_INITIALIZER;
61
static atomic_t devices_list_futex = FUTEX_INITIALIZER;
62
static atomic_t drivers_list_futex = FUTEX_INITIALIZER;
62
static atomic_t drivers_list_futex = FUTEX_INITIALIZER;
63
static atomic_t create_handle_futex = FUTEX_INITIALIZER;
63
static atomic_t create_handle_futex = FUTEX_INITIALIZER;
64
 
64
 
65
 
65
 
66
static int devmap_create_handle(void)
66
static int devmap_create_handle(void)
67
{
67
{
68
    static int last_handle = 0;
68
    static int last_handle = 0;
69
    int handle;
69
    int handle;
70
 
70
 
71
    /* TODO: allow reusing old handles after their unregistration
71
    /* TODO: allow reusing old handles after their unregistration
72
        and implement some version of LRU algorithm */
72
        and implement some version of LRU algorithm */
73
    /* FIXME: overflow */
73
    /* FIXME: overflow */
74
    futex_down(&create_handle_futex);  
74
    futex_down(&create_handle_futex);  
75
 
75
 
76
    last_handle += 1;
76
    last_handle += 1;
77
    handle = last_handle;
77
    handle = last_handle;
78
 
78
 
79
    futex_up(&create_handle_futex);
79
    futex_up(&create_handle_futex);
80
 
80
 
81
    return handle;
81
    return handle;
82
}
82
}
83
 
83
 
84
 
84
 
85
/** Initialize device mapper.
85
/** Initialize device mapper.
86
 *
86
 *
87
 *
87
 *
88
 */
88
 */
89
static int devmap_init()
89
static int devmap_init()
90
{
90
{
91
    /* TODO: */
91
    /* TODO: */
92
 
92
 
93
    return EOK;
93
    return EOK;
94
}
94
}
95
 
95
 
96
/** Find device with given name.
96
/** Find device with given name.
97
 *
97
 *
98
 */
98
 */
99
static devmap_device_t *devmap_device_find_name(const char *name)
99
static devmap_device_t *devmap_device_find_name(const char *name)
100
{
100
{
101
    link_t *item;
101
    link_t *item;
102
    devmap_device_t *device = NULL;
102
    devmap_device_t *device = NULL;
103
 
103
 
104
    item = devices_list.next;
104
    item = devices_list.next;
105
 
105
 
106
    while (item != &devices_list) {
106
    while (item != &devices_list) {
107
 
107
 
108
        device = list_get_instance(item, devmap_device_t, devices);
108
        device = list_get_instance(item, devmap_device_t, devices);
109
        if (0 == strcmp(device->name, name)) {
109
        if (0 == strcmp(device->name, name)) {
110
            break;
110
            break;
111
        }
111
        }
112
        item = item->next;
112
        item = item->next;
113
    }
113
    }
114
 
114
 
115
    if (item == &devices_list) {
115
    if (item == &devices_list) {
116
        printf("DEVMAP: no device named %s.\n", name);
116
        printf("DEVMAP: no device named %s.\n", name);
117
        return NULL;
117
        return NULL;
118
    }
118
    }
119
 
119
 
120
    device = list_get_instance(item, devmap_device_t, devices);
120
    device = list_get_instance(item, devmap_device_t, devices);
121
    return device;
121
    return device;
122
}
122
}
123
 
123
 
124
/** Find device with given handle.
124
/** Find device with given handle.
125
 * @todo: use hash table
125
 * @todo: use hash table
126
 */
126
 */
127
static devmap_device_t *devmap_device_find_handle(int handle)
127
static devmap_device_t *devmap_device_find_handle(int handle)
128
{
128
{
129
    link_t *item;
129
    link_t *item;
130
    devmap_device_t *device = NULL;
130
    devmap_device_t *device = NULL;
131
   
131
   
132
    futex_down(&devices_list_futex);
132
    futex_down(&devices_list_futex);
133
 
133
 
134
    item = (&devices_list)->next;
134
    item = (&devices_list)->next;
135
 
135
 
136
    while (item != &devices_list) {
136
    while (item != &devices_list) {
137
 
137
 
138
        device = list_get_instance(item, devmap_device_t, devices);
138
        device = list_get_instance(item, devmap_device_t, devices);
139
        if (device->handle == handle) {
139
        if (device->handle == handle) {
140
            break;
140
            break;
141
        }
141
        }
142
        item = item->next;
142
        item = item->next;
143
    }
143
    }
144
 
144
 
145
    if (item == &devices_list) {
145
    if (item == &devices_list) {
146
        futex_up(&devices_list_futex);
146
        futex_up(&devices_list_futex);
147
        return NULL;
147
        return NULL;
148
    }
148
    }
149
 
149
 
150
    device = list_get_instance(item, devmap_device_t, devices);
150
    device = list_get_instance(item, devmap_device_t, devices);
151
   
151
   
152
    futex_up(&devices_list_futex);
152
    futex_up(&devices_list_futex);
153
 
153
 
154
    return device;
154
    return device;
155
}
155
}
156
 
156
 
157
/**
157
/**
158
 * Unregister device and free it. It's assumed that driver's device list is
158
 * Unregister device and free it. It's assumed that driver's device list is
159
 * already locked.
159
 * already locked.
160
 */
160
 */
161
static int devmap_device_unregister_core(devmap_device_t *device)
161
static int devmap_device_unregister_core(devmap_device_t *device)
162
{
162
{
163
 
163
 
164
    list_remove(&(device->devices));
164
    list_remove(&(device->devices));
165
    list_remove(&(device->driver_devices));
165
    list_remove(&(device->driver_devices));
166
 
166
 
167
    free(device->name);
167
    free(device->name);
168
    free(device);
168
    free(device);
169
 
169
 
170
 
170
 
171
    return EOK;
171
    return EOK;
172
}
172
}
173
 
173
 
174
/**
174
/**
175
 * Read info about new driver and add it into linked list of registered
175
 * Read info about new driver and add it into linked list of registered
176
 * drivers.
176
 * drivers.
177
 */
177
 */
178
static void devmap_driver_register(devmap_driver_t **odriver)
178
static void devmap_driver_register(devmap_driver_t **odriver)
179
{
179
{
180
    size_t name_size;
180
    size_t name_size;
181
    ipc_callid_t callid;
181
    ipc_callid_t callid;
182
    ipc_call_t call;
182
    ipc_call_t call;
183
    devmap_driver_t *driver;
183
    devmap_driver_t *driver;
184
    ipc_callid_t iid;
184
    ipc_callid_t iid;
185
    ipc_call_t icall;
185
    ipc_call_t icall;
186
 
186
 
187
    *odriver = NULL;
187
    *odriver = NULL;
188
   
188
   
189
    iid = async_get_call(&icall);
189
    iid = async_get_call(&icall);
190
 
190
 
191
    if (IPC_GET_METHOD(icall) != DEVMAP_DRIVER_REGISTER) {
191
    if (IPC_GET_METHOD(icall) != DEVMAP_DRIVER_REGISTER) {
192
        ipc_answer_0(iid, EREFUSED);
192
        ipc_answer_0(iid, EREFUSED);
193
        return;
193
        return;
194
    }
194
    }
195
 
195
 
196
    if (NULL ==
196
    if (NULL ==
197
        (driver = (devmap_driver_t *)malloc(sizeof(devmap_driver_t)))) {
197
        (driver = (devmap_driver_t *)malloc(sizeof(devmap_driver_t)))) {
198
        ipc_answer_0(iid, ENOMEM);
198
        ipc_answer_0(iid, ENOMEM);
199
        return;
199
        return;
200
    }
200
    }
201
 
201
 
202
    /*
202
    /*
203
     * Get driver name
203
     * Get driver name
204
     */
204
     */
205
    if (!ipc_data_receive(&callid, NULL, &name_size)) {
205
    if (!ipc_data_receive(&callid, NULL, &name_size)) {
206
        printf("Unexpected request.\n");
206
        printf("Unexpected request.\n");
207
        free(driver);
207
        free(driver);
208
        ipc_answer_0(callid, EREFUSED);
208
        ipc_answer_0(callid, EREFUSED);
209
        ipc_answer_0(iid, EREFUSED);
209
        ipc_answer_0(iid, EREFUSED);
210
        return;
210
        return;
211
    }
211
    }
212
 
212
 
213
    if (name_size > DEVMAP_NAME_MAXLEN) {
213
    if (name_size > DEVMAP_NAME_MAXLEN) {
214
        printf("Too logn name: %u: maximum is %u.\n", name_size,
214
        printf("Too logn name: %u: maximum is %u.\n", name_size,
215
            DEVMAP_NAME_MAXLEN);
215
            DEVMAP_NAME_MAXLEN);
216
        free(driver);
216
        free(driver);
217
        ipc_answer_0(callid, EINVAL);
217
        ipc_answer_0(callid, EINVAL);
218
        ipc_answer_0(iid, EREFUSED);
218
        ipc_answer_0(iid, EREFUSED);
219
        return;
219
        return;
220
    }
220
    }
221
 
221
 
222
    /*
222
    /*
223
     * Allocate buffer for device name.
223
     * Allocate buffer for device name.
224
     */
224
     */
225
    if (NULL == (driver->name = (char *)malloc(name_size + 1))) {
225
    if (NULL == (driver->name = (char *)malloc(name_size + 1))) {
226
        printf("Cannot allocate space for driver name.\n");
226
        printf("Cannot allocate space for driver name.\n");
227
        free(driver);
227
        free(driver);
228
        ipc_answer_0(callid, ENOMEM);
228
        ipc_answer_0(callid, ENOMEM);
229
        ipc_answer_0(iid, EREFUSED);
229
        ipc_answer_0(iid, EREFUSED);
230
        return;
230
        return;
231
    }  
231
    }  
232
 
232
 
233
    /*
233
    /*
234
     * Send confirmation to sender and get data into buffer.
234
     * Send confirmation to sender and get data into buffer.
235
     */
235
     */
236
    if (EOK != ipc_data_deliver(callid, driver->name, name_size)) {
236
    if (EOK != ipc_data_deliver(callid, driver->name, name_size)) {
237
        printf("Cannot read driver name.\n");
237
        printf("Cannot read driver name.\n");
238
        free(driver->name);
238
        free(driver->name);
239
        free(driver);
239
        free(driver);
240
        ipc_answer_0(iid, EREFUSED);
240
        ipc_answer_0(iid, EREFUSED);
241
        return;
241
        return;
242
    }
242
    }
243
 
243
 
244
    driver->name[name_size] = 0;
244
    driver->name[name_size] = 0;
245
 
245
 
246
    printf("Read driver name: '%s'.\n", driver->name);
246
    printf("Read driver name: '%s'.\n", driver->name);
247
 
247
 
248
    /* Initialize futex for list of devices owned by this driver */
248
    /* Initialize futex for list of devices owned by this driver */
249
    futex_initialize(&(driver->devices_futex), 1);
249
    futex_initialize(&(driver->devices_futex), 1);
250
 
250
 
251
    /*
251
    /*
252
     * Initialize list of asociated devices
252
     * Initialize list of asociated devices
253
     */
253
     */
254
    list_initialize(&(driver->devices));
254
    list_initialize(&(driver->devices));
255
 
255
 
256
    /*
256
    /*
257
     * Create connection to the driver
257
     * Create connection to the driver
258
     */
258
     */
259
    callid = async_get_call(&call);
259
    callid = async_get_call(&call);
260
 
260
 
261
    if (IPC_M_CONNECT_TO_ME != IPC_GET_METHOD(call)) {
261
    if (IPC_M_CONNECT_TO_ME != IPC_GET_METHOD(call)) {
262
        printf("DEVMAP: Unexpected method: %u.\n",
262
        printf("DEVMAP: Unexpected method: %u.\n",
263
            IPC_GET_METHOD(call));
263
            IPC_GET_METHOD(call));
264
        ipc_answer_0(callid, ENOTSUP);
264
        ipc_answer_0(callid, ENOTSUP);
265
       
265
       
266
        free(driver->name);
266
        free(driver->name);
267
        free(driver);
267
        free(driver);
268
        ipc_answer_0(iid, ENOTSUP);
268
        ipc_answer_0(iid, ENOTSUP);
269
        return;
269
        return;
270
    }
270
    }
271
 
271
 
272
    driver->phone = IPC_GET_ARG3(call);
272
    driver->phone = IPC_GET_ARG3(call);
273
   
273
   
274
    ipc_answer_0(callid, EOK);
274
    ipc_answer_0(callid, EOK);
275
   
275
   
276
    list_initialize(&(driver->drivers));
276
    list_initialize(&(driver->drivers));
277
 
277
 
278
    futex_down(&drivers_list_futex);   
278
    futex_down(&drivers_list_futex);   
279
   
279
   
280
    /* TODO:
280
    /* TODO:
281
     * check that no driver with name equal to driver->name is registered
281
     * check that no driver with name equal to driver->name is registered
282
     */
282
     */
283
 
283
 
284
    /*
284
    /*
285
     * Insert new driver into list of registered drivers
285
     * Insert new driver into list of registered drivers
286
     */
286
     */
287
    list_append(&(driver->drivers), &drivers_list);
287
    list_append(&(driver->drivers), &drivers_list);
288
    futex_up(&drivers_list_futex); 
288
    futex_up(&drivers_list_futex); 
289
   
289
   
290
    ipc_answer_0(iid, EOK);
290
    ipc_answer_0(iid, EOK);
291
    printf("Driver registered.\n");
291
    printf("Driver registered.\n");
292
 
292
 
293
    *odriver = driver;
293
    *odriver = driver;
294
    return;
294
    return;
295
}
295
}
296
 
296
 
297
/** Unregister device driver, unregister all its devices and free driver
297
/** Unregister device driver, unregister all its devices and free driver
298
 * structure.
298
 * structure.
299
 */
299
 */
300
static int devmap_driver_unregister(devmap_driver_t *driver)
300
static int devmap_driver_unregister(devmap_driver_t *driver)
301
{
301
{
302
    devmap_device_t *device;
302
    devmap_device_t *device;
303
 
303
 
304
    if (NULL == driver) {
304
    if (NULL == driver) {
305
        printf("Error: driver == NULL.\n");
305
        printf("Error: driver == NULL.\n");
306
        return EEXISTS;
306
        return EEXISTS;
307
    }
307
    }
308
 
308
 
309
    printf("Unregister driver '%s'.\n", driver->name);
309
    printf("Unregister driver '%s'.\n", driver->name);
310
    futex_down(&drivers_list_futex);   
310
    futex_down(&drivers_list_futex);   
311
 
311
 
312
    ipc_hangup(driver->phone);
312
    ipc_hangup(driver->phone);
313
   
313
   
314
    /* remove it from list of drivers */
314
    /* remove it from list of drivers */
315
    list_remove(&(driver->drivers));
315
    list_remove(&(driver->drivers));
316
 
316
 
317
    /* unregister all its devices */
317
    /* unregister all its devices */
318
   
318
   
319
    futex_down(&devices_list_futex);   
319
    futex_down(&devices_list_futex);   
320
    futex_down(&(driver->devices_futex));
320
    futex_down(&(driver->devices_futex));
321
 
321
 
322
    while (!list_empty(&(driver->devices))) {
322
    while (!list_empty(&(driver->devices))) {
323
        device = list_get_instance(driver->devices.next,
323
        device = list_get_instance(driver->devices.next,
324
            devmap_device_t, driver_devices);
324
            devmap_device_t, driver_devices);
325
        printf("Unregister device '%s'.\n", device->name);
325
        printf("Unregister device '%s'.\n", device->name);
326
        devmap_device_unregister_core(device);
326
        devmap_device_unregister_core(device);
327
    }
327
    }
328
   
328
   
329
    futex_up(&(driver->devices_futex));
329
    futex_up(&(driver->devices_futex));
330
    futex_up(&devices_list_futex); 
330
    futex_up(&devices_list_futex); 
331
    futex_up(&drivers_list_futex); 
331
    futex_up(&drivers_list_futex); 
332
 
332
 
333
    /* free name and driver */
333
    /* free name and driver */
334
    if (NULL != driver->name) {
334
    if (NULL != driver->name) {
335
        free(driver->name);
335
        free(driver->name);
336
    }
336
    }
337
 
337
 
338
    free(driver);
338
    free(driver);
339
 
339
 
340
    printf("Driver unregistered.\n");
340
    printf("Driver unregistered.\n");
341
 
341
 
342
    return EOK;
342
    return EOK;
343
}
343
}
344
 
344
 
345
 
345
 
346
/** Register instance of device
346
/** Register instance of device
347
 *
347
 *
348
 */
348
 */
349
static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
349
static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
350
    devmap_driver_t *driver)
350
    devmap_driver_t *driver)
351
{
351
{
352
    ipc_callid_t callid;
352
    ipc_callid_t callid;
353
    size_t size;
353
    size_t size;
354
    devmap_device_t *device;
354
    devmap_device_t *device;
355
 
355
 
356
    if (NULL == driver) {
356
    if (NULL == driver) {
357
        printf("Invalid driver registration.\n");
357
        printf("Invalid driver registration.\n");
358
        ipc_answer_0(iid, EREFUSED);
358
        ipc_answer_0(iid, EREFUSED);
359
        return;
359
        return;
360
    }
360
    }
361
   
361
   
362
    /* Create new device entry */
362
    /* Create new device entry */
363
    if (NULL ==
363
    if (NULL ==
364
        (device = (devmap_device_t *)malloc(sizeof(devmap_device_t)))) {
364
        (device = (devmap_device_t *)malloc(sizeof(devmap_device_t)))) {
365
        printf("Cannot allocate new device.\n");
365
        printf("Cannot allocate new device.\n");
366
        ipc_answer_0(iid, ENOMEM);
366
        ipc_answer_0(iid, ENOMEM);
367
        return;
367
        return;
368
    }
368
    }
369
   
369
   
370
    /* Get device name */
370
    /* Get device name */
371
    if (!ipc_data_receive(&callid, NULL, &size)) {
371
    if (!ipc_data_receive(&callid, NULL, &size)) {
372
        free(device);
372
        free(device);
373
        printf("Cannot read device name.\n");
373
        printf("Cannot read device name.\n");
374
        ipc_answer_0(iid, EREFUSED);
374
        ipc_answer_0(iid, EREFUSED);
375
        return;
375
        return;
376
    }
376
    }
377
 
377
 
378
    if (size > DEVMAP_NAME_MAXLEN) {
378
    if (size > DEVMAP_NAME_MAXLEN) {
379
        printf("Too long device name: %u.\n", size);
379
        printf("Too long device name: %u.\n", size);
380
        free(device);
380
        free(device);
381
        ipc_answer_0(callid, EINVAL);
381
        ipc_answer_0(callid, EINVAL);
382
        ipc_answer_0(iid, EREFUSED);
382
        ipc_answer_0(iid, EREFUSED);
383
        return;
383
        return;
384
    }
384
    }
385
 
385
 
386
        /* +1 for terminating \0 */
386
        /* +1 for terminating \0 */
387
    device->name = (char *)malloc(size + 1);
387
    device->name = (char *)malloc(size + 1);
388
 
388
 
389
    if (NULL == device->name) {
389
    if (NULL == device->name) {
390
        printf("Cannot read device name.\n");
390
        printf("Cannot read device name.\n");
391
        free(device);
391
        free(device);
392
        ipc_answer_0(callid, ENOMEM);
392
        ipc_answer_0(callid, ENOMEM);
393
        ipc_answer_0(iid, EREFUSED);
393
        ipc_answer_0(iid, EREFUSED);
394
        return;
394
        return;
395
    }
395
    }
396
   
396
   
397
    ipc_data_deliver(callid, device->name, size);
397
    ipc_data_deliver(callid, device->name, size);
398
    device->name[size] = 0;
398
    device->name[size] = 0;
399
 
399
 
400
    list_initialize(&(device->devices));
400
    list_initialize(&(device->devices));
401
    list_initialize(&(device->driver_devices));
401
    list_initialize(&(device->driver_devices));
402
 
402
 
403
    futex_down(&devices_list_futex);   
403
    futex_down(&devices_list_futex);   
404
 
404
 
405
    /* Check that device with such name is not already registered */
405
    /* Check that device with such name is not already registered */
406
    if (NULL != devmap_device_find_name(device->name)) {
406
    if (NULL != devmap_device_find_name(device->name)) {
407
        printf("Device '%s' already registered.\n", device->name);
407
        printf("Device '%s' already registered.\n", device->name);
408
        futex_up(&devices_list_futex); 
408
        futex_up(&devices_list_futex); 
409
        free(device->name);
409
        free(device->name);
410
        free(device);
410
        free(device);
411
        ipc_answer_0(iid, EEXISTS);
411
        ipc_answer_0(iid, EEXISTS);
412
        return;
412
        return;
413
    }
413
    }
414
 
414
 
415
    /* Get unique device handle */
415
    /* Get unique device handle */
416
    device->handle = devmap_create_handle();
416
    device->handle = devmap_create_handle();
417
 
417
 
418
    device->driver = driver;
418
    device->driver = driver;
419
   
419
   
420
    /* Insert device into list of all devices  */
420
    /* Insert device into list of all devices  */
421
    list_append(&device->devices, &devices_list);
421
    list_append(&device->devices, &devices_list);
422
 
422
 
423
    /* Insert device into list of devices that belog to one driver */
423
    /* Insert device into list of devices that belog to one driver */
424
    futex_down(&device->driver->devices_futex);
424
    futex_down(&device->driver->devices_futex);
425
   
425
   
426
    list_append(&device->driver_devices, &device->driver->devices);
426
    list_append(&device->driver_devices, &device->driver->devices);
427
   
427
   
428
    futex_up(&device->driver->devices_futex);  
428
    futex_up(&device->driver->devices_futex);  
429
    futex_up(&devices_list_futex); 
429
    futex_up(&devices_list_futex); 
430
 
430
 
431
    printf("Device '%s' registered.\n", device->name); 
431
    printf("Device '%s' registered.\n", device->name); 
432
    ipc_answer_1(iid, EOK, device->handle);
432
    ipc_answer_1(iid, EOK, device->handle);
433
 
433
 
434
    return;
434
    return;
435
}
435
}
436
 
436
 
437
/**
437
/**
438
 *
438
 *
439
 */
439
 */
440
static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall,
440
static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall,
441
    devmap_driver_t *driver)
441
    devmap_driver_t *driver)
442
{
442
{
443
    /* TODO */
443
    /* TODO */
444
 
444
 
445
    return EOK;
445
    return EOK;
446
}
446
}
447
 
447
 
448
/** Connect client to the device.
448
/** Connect client to the device.
449
 * Find device driver owning requested device and forward
449
 * Find device driver owning requested device and forward
450
 * the message to it.
450
 * the message to it.
451
 *
451
 *
452
 *
452
 *
453
 */
453
 */
454
static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
454
static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
455
{
455
{
456
    devmap_device_t *dev;
456
    devmap_device_t *dev;
457
    int handle;
457
    int handle;
458
 
458
 
459
    /*
459
    /*
460
     * Get handle from request
460
     * Get handle from request
461
     */
461
     */
462
    handle = IPC_GET_ARG1(*call);
462
    handle = IPC_GET_ARG1(*call);
463
    dev = devmap_device_find_handle(handle);
463
    dev = devmap_device_find_handle(handle);
464
 
464
 
465
    if (NULL == dev) {
465
    if (NULL == dev) {
466
        printf("DEVMAP: No registered device with handle %d.\n",
466
        printf("DEVMAP: No registered device with handle %d.\n",
467
            handle);
467
            handle);
468
        ipc_answer_0(callid, ENOENT);
468
        ipc_answer_0(callid, ENOENT);
469
        return;
469
        return;
470
    }
470
    }
471
 
471
 
472
    /* FIXME: is this correct method how to pass argument on forwarding ?*/
472
    /* FIXME: is this correct method how to pass argument on forwarding ?*/
473
    ipc_forward_fast(callid, dev->driver->phone, (ipcarg_t)(dev->handle),
473
    ipc_forward_fast(callid, dev->driver->phone, (ipcarg_t)(dev->handle),
474
        0);
474
        0, IPC_FF_NONE);
475
    return;
475
    return;
476
}
476
}
477
 
477
 
478
/** Find handle for device instance identified by name.
478
/** Find handle for device instance identified by name.
479
 * In answer will be send EOK and device handle in arg1 or a error
479
 * In answer will be send EOK and device handle in arg1 or a error
480
 * code from errno.h.
480
 * code from errno.h.
481
 */
481
 */
482
static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall)
482
static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall)
483
{
483
{
484
    char *name = NULL;
484
    char *name = NULL;
485
    size_t name_size;
485
    size_t name_size;
486
    const devmap_device_t *dev;
486
    const devmap_device_t *dev;
487
    ipc_callid_t callid;
487
    ipc_callid_t callid;
488
    ipcarg_t retval;
488
    ipcarg_t retval;
489
   
489
   
490
   
490
   
491
    /*
491
    /*
492
     * Wait for incoming message with device name (but do not
492
     * Wait for incoming message with device name (but do not
493
     * read the name itself until the buffer is allocated).
493
     * read the name itself until the buffer is allocated).
494
     */
494
     */
495
    if (!ipc_data_receive(&callid, NULL, &name_size)) {
495
    if (!ipc_data_receive(&callid, NULL, &name_size)) {
496
        ipc_answer_0(callid, EREFUSED);
496
        ipc_answer_0(callid, EREFUSED);
497
        ipc_answer_0(iid, EREFUSED);
497
        ipc_answer_0(iid, EREFUSED);
498
        return;
498
        return;
499
    }
499
    }
500
 
500
 
501
    if (name_size > DEVMAP_NAME_MAXLEN) {
501
    if (name_size > DEVMAP_NAME_MAXLEN) {
502
        ipc_answer_0(callid, EINVAL);
502
        ipc_answer_0(callid, EINVAL);
503
        ipc_answer_0(iid, EREFUSED);
503
        ipc_answer_0(iid, EREFUSED);
504
        return;
504
        return;
505
    }
505
    }
506
 
506
 
507
    /*
507
    /*
508
     * Allocate buffer for device name.
508
     * Allocate buffer for device name.
509
     */
509
     */
510
    if (NULL == (name = (char *)malloc(name_size))) {
510
    if (NULL == (name = (char *)malloc(name_size))) {
511
        ipc_answer_0(callid, ENOMEM);
511
        ipc_answer_0(callid, ENOMEM);
512
        ipc_answer_0(iid, EREFUSED);
512
        ipc_answer_0(iid, EREFUSED);
513
        return;
513
        return;
514
    }  
514
    }  
515
 
515
 
516
    /*
516
    /*
517
     * Send confirmation to sender and get data into buffer.
517
     * Send confirmation to sender and get data into buffer.
518
     */
518
     */
519
    if (EOK != (retval = ipc_data_deliver(callid, name, name_size))) {
519
    if (EOK != (retval = ipc_data_deliver(callid, name, name_size))) {
520
        ipc_answer_0(iid, EREFUSED);
520
        ipc_answer_0(iid, EREFUSED);
521
        return;
521
        return;
522
    }
522
    }
523
 
523
 
524
    /*
524
    /*
525
     * Find device name in linked list of known devices.
525
     * Find device name in linked list of known devices.
526
     */
526
     */
527
    dev = devmap_device_find_name(name);
527
    dev = devmap_device_find_name(name);
528
 
528
 
529
    /*
529
    /*
530
     * Device was not found.
530
     * Device was not found.
531
     */
531
     */
532
    if (NULL == dev) {
532
    if (NULL == dev) {
533
        printf("DEVMAP: device %s has not been registered.\n", name);
533
        printf("DEVMAP: device %s has not been registered.\n", name);
534
        ipc_answer_0(iid, ENOENT);
534
        ipc_answer_0(iid, ENOENT);
535
        return;
535
        return;
536
    }
536
    }
537
 
537
 
538
    printf("DEVMAP: device %s has handler %d.\n", name, dev->handle);
538
    printf("DEVMAP: device %s has handler %d.\n", name, dev->handle);
539
       
539
       
540
    ipc_answer_1(iid, EOK, dev->handle);
540
    ipc_answer_1(iid, EOK, dev->handle);
541
 
541
 
542
    return;
542
    return;
543
}
543
}
544
 
544
 
545
/** Find name of device identified by id and send it to caller.
545
/** Find name of device identified by id and send it to caller.
546
 *
546
 *
547
 */
547
 */
548
static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall)
548
static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall)
549
{
549
{
550
    const devmap_device_t *device;
550
    const devmap_device_t *device;
551
    size_t name_size;
551
    size_t name_size;
552
 
552
 
553
    device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
553
    device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
554
 
554
 
555
    /*
555
    /*
556
     * Device not found.
556
     * Device not found.
557
     */
557
     */
558
    if (NULL == device) {
558
    if (NULL == device) {
559
        ipc_answer_0(iid, ENOENT);
559
        ipc_answer_0(iid, ENOENT);
560
        return;
560
        return;
561
    }  
561
    }  
562
 
562
 
563
    ipc_answer_0(iid, EOK);
563
    ipc_answer_0(iid, EOK);
564
 
564
 
565
    name_size = strlen(device->name);
565
    name_size = strlen(device->name);
566
 
566
 
567
 
567
 
568
/*  FIXME:
568
/*  FIXME:
569
    we have no channel from DEVMAP to client ->
569
    we have no channel from DEVMAP to client ->
570
    sending must be initiated by client
570
    sending must be initiated by client
571
 
571
 
572
    int rc = ipc_data_send(phone, device->name, name_size);
572
    int rc = ipc_data_send(phone, device->name, name_size);
573
    if (rc != EOK) {
573
    if (rc != EOK) {
574
        async_wait_for(req, NULL);
574
        async_wait_for(req, NULL);
575
        return rc;
575
        return rc;
576
    }
576
    }
577
*/ 
577
*/ 
578
    /* TODO: send name in response */
578
    /* TODO: send name in response */
579
 
579
 
580
    return;
580
    return;
581
}
581
}
582
 
582
 
583
/** Handle connection with device driver.
583
/** Handle connection with device driver.
584
 *
584
 *
585
 */
585
 */
586
static void
586
static void
587
devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
587
devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
588
{
588
{
589
    ipc_callid_t callid;
589
    ipc_callid_t callid;
590
    ipc_call_t call;
590
    ipc_call_t call;
591
    bool cont = true;
591
    bool cont = true;
592
    devmap_driver_t *driver = NULL;
592
    devmap_driver_t *driver = NULL;
593
 
593
 
594
    ipc_answer_0(iid, EOK);
594
    ipc_answer_0(iid, EOK);
595
 
595
 
596
    devmap_driver_register(&driver);
596
    devmap_driver_register(&driver);
597
 
597
 
598
    if (NULL == driver) {
598
    if (NULL == driver) {
599
        printf("DEVMAP: driver registration failed.\n");
599
        printf("DEVMAP: driver registration failed.\n");
600
        return;
600
        return;
601
    }
601
    }
602
   
602
   
603
    while (cont) {
603
    while (cont) {
604
        callid = async_get_call(&call);
604
        callid = async_get_call(&call);
605
 
605
 
606
        switch (IPC_GET_METHOD(call)) {
606
        switch (IPC_GET_METHOD(call)) {
607
        case IPC_M_PHONE_HUNGUP:
607
        case IPC_M_PHONE_HUNGUP:
608
            printf("DEVMAP: connection hung up.\n");
608
            printf("DEVMAP: connection hung up.\n");
609
            cont = false;
609
            cont = false;
610
            continue; /* Exit thread */
610
            continue; /* Exit thread */
611
        case DEVMAP_DRIVER_UNREGISTER:
611
        case DEVMAP_DRIVER_UNREGISTER:
612
            printf("DEVMAP: unregister driver.\n");
612
            printf("DEVMAP: unregister driver.\n");
613
            if (NULL == driver) {
613
            if (NULL == driver) {
614
                printf("DEVMAP: driver was not registered!\n");
614
                printf("DEVMAP: driver was not registered!\n");
615
                ipc_answer_0(callid, ENOENT);
615
                ipc_answer_0(callid, ENOENT);
616
            } else {
616
            } else {
617
                ipc_answer_0(callid, EOK);
617
                ipc_answer_0(callid, EOK);
618
            }
618
            }
619
            break;
619
            break;
620
        case DEVMAP_DEVICE_REGISTER:
620
        case DEVMAP_DEVICE_REGISTER:
621
            /* Register one instance of device */
621
            /* Register one instance of device */
622
            devmap_device_register(callid, &call, driver);
622
            devmap_device_register(callid, &call, driver);
623
            break;
623
            break;
624
        case DEVMAP_DEVICE_UNREGISTER:
624
        case DEVMAP_DEVICE_UNREGISTER:
625
            /* Remove instance of device identified by handler */
625
            /* Remove instance of device identified by handler */
626
            devmap_device_unregister(callid, &call, driver);
626
            devmap_device_unregister(callid, &call, driver);
627
            break;
627
            break;
628
        case DEVMAP_DEVICE_GET_HANDLE:
628
        case DEVMAP_DEVICE_GET_HANDLE:
629
            devmap_get_handle(callid, &call);
629
            devmap_get_handle(callid, &call);
630
            break;
630
            break;
631
        case DEVMAP_DEVICE_GET_NAME:
631
        case DEVMAP_DEVICE_GET_NAME:
632
            devmap_get_handle(callid, &call);
632
            devmap_get_handle(callid, &call);
633
            break;
633
            break;
634
        default:
634
        default:
635
            if (!(callid & IPC_CALLID_NOTIFICATION)) {
635
            if (!(callid & IPC_CALLID_NOTIFICATION)) {
636
                ipc_answer_0(callid, ENOENT);
636
                ipc_answer_0(callid, ENOENT);
637
            }
637
            }
638
        }
638
        }
639
    }
639
    }
640
   
640
   
641
    if (NULL != driver) {
641
    if (NULL != driver) {
642
        /*
642
        /*
643
         * Unregister the device driver and all its devices.
643
         * Unregister the device driver and all its devices.
644
         */
644
         */
645
        devmap_driver_unregister(driver);
645
        devmap_driver_unregister(driver);
646
        driver = NULL;
646
        driver = NULL;
647
    }
647
    }
648
   
648
   
649
}
649
}
650
 
650
 
651
/** Handle connection with device client.
651
/** Handle connection with device client.
652
 *
652
 *
653
 */
653
 */
654
static void
654
static void
655
devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
655
devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
656
{
656
{
657
    ipc_callid_t callid;
657
    ipc_callid_t callid;
658
    ipc_call_t call;
658
    ipc_call_t call;
659
    bool cont = true;
659
    bool cont = true;
660
 
660
 
661
    ipc_answer_0(iid, EOK); /* Accept connection */
661
    ipc_answer_0(iid, EOK); /* Accept connection */
662
 
662
 
663
    while (cont) {
663
    while (cont) {
664
        callid = async_get_call(&call);
664
        callid = async_get_call(&call);
665
 
665
 
666
        switch (IPC_GET_METHOD(call)) {
666
        switch (IPC_GET_METHOD(call)) {
667
        case IPC_M_PHONE_HUNGUP:
667
        case IPC_M_PHONE_HUNGUP:
668
            printf("DEVMAP: connection hung up.\n");
668
            printf("DEVMAP: connection hung up.\n");
669
            cont = false;
669
            cont = false;
670
            continue; /* Exit thread */
670
            continue; /* Exit thread */
671
 
671
 
672
        case DEVMAP_DEVICE_CONNECT_ME_TO:
672
        case DEVMAP_DEVICE_CONNECT_ME_TO:
673
            /* Connect client to selected device */
673
            /* Connect client to selected device */
674
            printf("DEVMAP: connect to device %d.\n",
674
            printf("DEVMAP: connect to device %d.\n",
675
                IPC_GET_ARG1(call));
675
                IPC_GET_ARG1(call));
676
            devmap_forward(callid, &call);
676
            devmap_forward(callid, &call);
677
            break;
677
            break;
678
 
678
 
679
        case DEVMAP_DEVICE_GET_HANDLE:
679
        case DEVMAP_DEVICE_GET_HANDLE:
680
            devmap_get_handle(callid, &call);
680
            devmap_get_handle(callid, &call);
681
 
681
 
682
            break;
682
            break;
683
        case DEVMAP_DEVICE_GET_NAME:
683
        case DEVMAP_DEVICE_GET_NAME:
684
            /* TODO */
684
            /* TODO */
685
            devmap_get_name(callid, &call);
685
            devmap_get_name(callid, &call);
686
            break;
686
            break;
687
        default:
687
        default:
688
            if (!(callid & IPC_CALLID_NOTIFICATION)) {
688
            if (!(callid & IPC_CALLID_NOTIFICATION)) {
689
                ipc_answer_0(callid, ENOENT);
689
                ipc_answer_0(callid, ENOENT);
690
            }
690
            }
691
        }
691
        }
692
    }
692
    }
693
}
693
}
694
 
694
 
695
/** Function for handling connections to devmap
695
/** Function for handling connections to devmap
696
 *
696
 *
697
 */
697
 */
698
static void
698
static void
699
devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
699
devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
700
{
700
{
701
 
701
 
702
    printf("DEVMAP: new connection.\n");
702
    printf("DEVMAP: new connection.\n");
703
 
703
 
704
        /* Select interface */
704
        /* Select interface */
705
    switch ((ipcarg_t)(IPC_GET_ARG1(*icall))) {
705
    switch ((ipcarg_t)(IPC_GET_ARG1(*icall))) {
706
    case DEVMAP_DRIVER:
706
    case DEVMAP_DRIVER:
707
        devmap_connection_driver(iid, icall);
707
        devmap_connection_driver(iid, icall);
708
        break;
708
        break;
709
    case DEVMAP_CLIENT:
709
    case DEVMAP_CLIENT:
710
        devmap_connection_client(iid, icall);
710
        devmap_connection_client(iid, icall);
711
        break;
711
        break;
712
    default:
712
    default:
713
        ipc_answer_0(iid, ENOENT); /* No such interface */
713
        ipc_answer_0(iid, ENOENT); /* No such interface */
714
        printf("DEVMAP: Unknown interface %u.\n",
714
        printf("DEVMAP: Unknown interface %u.\n",
715
            (ipcarg_t)(IPC_GET_ARG1(*icall)));
715
            (ipcarg_t)(IPC_GET_ARG1(*icall)));
716
    }
716
    }
717
 
717
 
718
    /* Cleanup */
718
    /* Cleanup */
719
   
719
   
720
    printf("DEVMAP: connection closed.\n");
720
    printf("DEVMAP: connection closed.\n");
721
    return;
721
    return;
722
}
722
}
723
 
723
 
724
/**
724
/**
725
 *
725
 *
726
 */
726
 */
727
int main(int argc, char *argv[])
727
int main(int argc, char *argv[])
728
{
728
{
729
    ipcarg_t phonead;
729
    ipcarg_t phonead;
730
 
730
 
731
    printf("DEVMAP: HelenOS device mapper.\n");
731
    printf("DEVMAP: HelenOS device mapper.\n");
732
 
732
 
733
    if (devmap_init() != 0) {
733
    if (devmap_init() != 0) {
734
        printf("Error while initializing DEVMAP service.\n");
734
        printf("Error while initializing DEVMAP service.\n");
735
        return -1;
735
        return -1;
736
    }
736
    }
737
 
737
 
738
        /* Set a handler of incomming connections */
738
        /* Set a handler of incomming connections */
739
    async_set_client_connection(devmap_connection);
739
    async_set_client_connection(devmap_connection);
740
 
740
 
741
    /* Register device mapper at naming service */
741
    /* Register device mapper at naming service */
742
    if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, &phonead) != 0)
742
    if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, &phonead) != 0)
743
        return -1;
743
        return -1;
744
   
744
   
745
    async_manager();
745
    async_manager();
746
    /* Never reached */
746
    /* Never reached */
747
    return 0;
747
    return 0;
748
}
748
}
749
 
749
 
750
/**
750
/**
751
 * @}
751
 * @}
752
 */
752
 */
753
 
753
 
754
 
754