Subversion Repositories HelenOS

Rev

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

Rev 2594 Rev 2598
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
/** Unregister device and free it. Its assumed that driver's device list
158
 * Unregister device and free it. It's assumed that driver's device list is
158
 * is already locked.
159
 * already locked.
159
 *
-
 
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
/** Read info about new driver and add it into linked list of registered drivers.
175
 * Read info about new driver and add it into linked list of registered
-
 
176
 * drivers.
175
 */
177
 */
176
static void devmap_driver_register(devmap_driver_t **odriver)
178
static void devmap_driver_register(devmap_driver_t **odriver)
177
{
179
{
178
    size_t name_size;
180
    size_t name_size;
179
    ipc_callid_t callid;
181
    ipc_callid_t callid;
180
    ipc_call_t call;
182
    ipc_call_t call;
181
    devmap_driver_t *driver;
183
    devmap_driver_t *driver;
182
    ipc_callid_t iid;
184
    ipc_callid_t iid;
183
    ipc_call_t icall;
185
    ipc_call_t icall;
184
 
186
 
185
    *odriver = NULL;
187
    *odriver = NULL;
186
   
188
   
187
    iid = async_get_call(&icall);
189
    iid = async_get_call(&icall);
188
 
190
 
189
    if (IPC_GET_METHOD(icall) != DEVMAP_DRIVER_REGISTER) {
191
    if (IPC_GET_METHOD(icall) != DEVMAP_DRIVER_REGISTER) {
190
        ipc_answer_fast(iid, EREFUSED, 0, 0);
192
        ipc_answer_fast(iid, EREFUSED, 0, 0);
191
        return;
193
        return;
192
    }
194
    }
193
 
195
 
-
 
196
    if (NULL ==
194
    if (NULL == (driver = (devmap_driver_t *)malloc(sizeof(devmap_driver_t)))) {
197
        (driver = (devmap_driver_t *)malloc(sizeof(devmap_driver_t)))) {
195
        ipc_answer_fast(iid, ENOMEM, 0, 0);
198
        ipc_answer_fast(iid, ENOMEM, 0, 0);
196
        return;
199
        return;
197
    }
200
    }
198
 
201
 
199
    /*
202
    /*
200
     * Get driver name
203
     * Get driver name
201
     */
204
     */
202
    if (!ipc_data_receive(&callid, &call, NULL, &name_size)) {
205
    if (!ipc_data_receive(&callid, &call, NULL, &name_size)) {
203
        printf("Unexpected request: %u.\n", IPC_GET_METHOD(call));
206
        printf("Unexpected request: %u.\n", IPC_GET_METHOD(call));
204
        free(driver);
207
        free(driver);
205
        ipc_answer_fast(callid, EREFUSED, 0, 0);
208
        ipc_answer_fast(callid, EREFUSED, 0, 0);
206
        ipc_answer_fast(iid, EREFUSED, 0, 0);
209
        ipc_answer_fast(iid, EREFUSED, 0, 0);
207
        return;
210
        return;
208
    }
211
    }
209
 
212
 
210
    if (name_size > DEVMAP_NAME_MAXLEN) {
213
    if (name_size > DEVMAP_NAME_MAXLEN) {
211
        printf("Too logn name: %u: maximum is %u.\n", name_size, DEVMAP_NAME_MAXLEN);
214
        printf("Too logn name: %u: maximum is %u.\n", name_size,
-
 
215
            DEVMAP_NAME_MAXLEN);
212
        free(driver);
216
        free(driver);
213
        ipc_answer_fast(callid, EINVAL, 0, 0);
217
        ipc_answer_fast(callid, EINVAL, 0, 0);
214
        ipc_answer_fast(iid, EREFUSED, 0, 0);
218
        ipc_answer_fast(iid, EREFUSED, 0, 0);
215
        return;
219
        return;
216
    }
220
    }
217
 
221
 
218
    /*
222
    /*
219
     * Allocate buffer for device name.
223
     * Allocate buffer for device name.
220
     */
224
     */
221
    if (NULL == (driver->name = (char *)malloc(name_size + 1))) {
225
    if (NULL == (driver->name = (char *)malloc(name_size + 1))) {
222
        printf("Cannot allocate space for driver name.\n");
226
        printf("Cannot allocate space for driver name.\n");
223
        free(driver);
227
        free(driver);
224
        ipc_answer_fast(callid, ENOMEM, 0, 0);
228
        ipc_answer_fast(callid, ENOMEM, 0, 0);
225
        ipc_answer_fast(iid, EREFUSED, 0, 0);
229
        ipc_answer_fast(iid, EREFUSED, 0, 0);
226
        return;
230
        return;
227
    }  
231
    }  
228
 
232
 
229
    /*
233
    /*
230
     * Send confirmation to sender and get data into buffer.
234
     * Send confirmation to sender and get data into buffer.
231
     */
235
     */
232
    if (EOK != ipc_data_deliver(callid, &call, driver->name, name_size)) {
236
    if (EOK != ipc_data_deliver(callid, &call, driver->name, name_size)) {
233
        printf("Cannot read driver name.\n");
237
        printf("Cannot read driver name.\n");
234
        free(driver->name);
238
        free(driver->name);
235
        free(driver);
239
        free(driver);
236
        ipc_answer_fast(iid, EREFUSED, 0, 0);
240
        ipc_answer_fast(iid, EREFUSED, 0, 0);
237
        return;
241
        return;
238
    }
242
    }
239
 
243
 
240
    driver->name[name_size] = 0;
244
    driver->name[name_size] = 0;
241
 
245
 
242
    printf("Read driver name: '%s'.\n", driver->name);
246
    printf("Read driver name: '%s'.\n", driver->name);
243
 
247
 
244
    /* Initialize futex for list of devices owned by this driver */
248
    /* Initialize futex for list of devices owned by this driver */
245
    futex_initialize(&(driver->devices_futex) ,1);
249
    futex_initialize(&(driver->devices_futex), 1);
246
 
250
 
247
    /*
251
    /*
248
     * Initialize list of asociated devices
252
     * Initialize list of asociated devices
249
     */
253
     */
250
    list_initialize(&(driver->devices));
254
    list_initialize(&(driver->devices));
251
 
255
 
252
    /*
256
    /*
253
     * Create connection to the driver
257
     * Create connection to the driver
254
     */
258
     */
255
    callid = async_get_call(&call);
259
    callid = async_get_call(&call);
256
 
260
 
257
    if (IPC_M_CONNECT_TO_ME != IPC_GET_METHOD(call)) {
261
    if (IPC_M_CONNECT_TO_ME != IPC_GET_METHOD(call)) {
258
        printf("DevMap: Unexpected method: %u.\n", \
262
        printf("DevMap: Unexpected method: %u.\n",
259
            IPC_GET_METHOD(call));
263
            IPC_GET_METHOD(call));
260
        ipc_answer_fast(callid, ENOTSUP, 0, 0);
264
        ipc_answer_fast(callid, ENOTSUP, 0, 0);
261
       
265
       
262
        free(driver->name);
266
        free(driver->name);
263
        free(driver);
267
        free(driver);
264
        ipc_answer_fast(iid, ENOTSUP, 0, 0);
268
        ipc_answer_fast(iid, ENOTSUP, 0, 0);
265
        return;
269
        return;
266
    }
270
    }
267
 
271
 
268
    driver->phone = IPC_GET_ARG3(call);
272
    driver->phone = IPC_GET_ARG3(call);
269
   
273
   
270
    ipc_answer_fast(callid, EOK, 0, 0);
274
    ipc_answer_fast(callid, EOK, 0, 0);
271
   
275
   
272
    list_initialize(&(driver->drivers));
276
    list_initialize(&(driver->drivers));
273
 
277
 
274
    futex_down(&drivers_list_futex);   
278
    futex_down(&drivers_list_futex);   
275
   
279
   
-
 
280
    /* TODO:
276
    /* TODO: check that no driver with name equals to driver->name is registered */
281
     * check that no driver with name equal to driver->name is registered
-
 
282
     */
277
 
283
 
278
    /*
284
    /*
279
     * Insert new driver into list of registered drivers
285
     * Insert new driver into list of registered drivers
280
     */
286
     */
281
    list_append(&(driver->drivers), &drivers_list);
287
    list_append(&(driver->drivers), &drivers_list);
282
    futex_up(&drivers_list_futex); 
288
    futex_up(&drivers_list_futex); 
283
   
289
   
284
    ipc_answer_fast(iid, EOK, 0, 0);
290
    ipc_answer_fast(iid, EOK, 0, 0);
285
    printf("Driver registered.\n");
291
    printf("Driver registered.\n");
286
 
292
 
287
    *odriver = driver;
293
    *odriver = driver;
288
    return;
294
    return;
289
}
295
}
290
 
296
 
291
/** Unregister device driver, unregister all its devices and free driver structure.
297
/** Unregister device driver, unregister all its devices and free driver structure.
292
 *
298
 *
293
 */
299
 */
294
static int devmap_driver_unregister(devmap_driver_t *driver)
300
static int devmap_driver_unregister(devmap_driver_t *driver)
295
{
301
{
296
    devmap_device_t *device;
302
    devmap_device_t *device;
297
 
303
 
298
    if (NULL == driver) {
304
    if (NULL == driver) {
299
        printf("Error: driver == NULL.\n");
305
        printf("Error: driver == NULL.\n");
300
        return EEXISTS;
306
        return EEXISTS;
301
    }
307
    }
302
 
308
 
303
    printf("Unregister driver '%s'.\n", driver->name);
309
    printf("Unregister driver '%s'.\n", driver->name);
304
    futex_down(&drivers_list_futex);   
310
    futex_down(&drivers_list_futex);   
305
 
311
 
306
    ipc_hangup(driver->phone);
312
    ipc_hangup(driver->phone);
307
   
313
   
308
    /* remove it from list of drivers */
314
    /* remove it from list of drivers */
309
    list_remove(&(driver->drivers));
315
    list_remove(&(driver->drivers));
310
 
316
 
311
    /* unregister all its devices */
317
    /* unregister all its devices */
312
   
318
   
313
    futex_down(&devices_list_futex);   
319
    futex_down(&devices_list_futex);   
314
    futex_down(&(driver->devices_futex));
320
    futex_down(&(driver->devices_futex));
315
 
321
 
316
    while (!list_empty(&(driver->devices))) {
322
    while (!list_empty(&(driver->devices))) {
317
        device = list_get_instance(driver->devices.next, devmap_device_t, driver_devices);
323
        device = list_get_instance(driver->devices.next,
-
 
324
            devmap_device_t, driver_devices);
318
        printf("Unregister device '%s'.\n", device->name);
325
        printf("Unregister device '%s'.\n", device->name);
319
        devmap_device_unregister_core(device);
326
        devmap_device_unregister_core(device);
320
    }
327
    }
321
   
328
   
322
    futex_up(&(driver->devices_futex));
329
    futex_up(&(driver->devices_futex));
323
    futex_up(&devices_list_futex); 
330
    futex_up(&devices_list_futex); 
324
    futex_up(&drivers_list_futex); 
331
    futex_up(&drivers_list_futex); 
325
 
332
 
326
    /* free name and driver */
333
    /* free name and driver */
327
    if (NULL != driver->name) {
334
    if (NULL != driver->name) {
328
        free(driver->name);
335
        free(driver->name);
329
    }
336
    }
330
 
337
 
331
    free(driver);
338
    free(driver);
332
 
339
 
333
    printf("Driver unregistered.\n");
340
    printf("Driver unregistered.\n");
334
 
341
 
335
    return EOK;
342
    return EOK;
336
}
343
}
337
 
344
 
338
 
345
 
339
/** Register instance of device
346
/** Register instance of device
340
 *
347
 *
341
 */
348
 */
342
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,
343
        devmap_driver_t *driver)
350
        devmap_driver_t *driver)
344
{
351
{
345
    ipc_callid_t callid;
352
    ipc_callid_t callid;
346
    ipc_call_t call;
353
    ipc_call_t call;
347
    size_t size;
354
    size_t size;
348
    devmap_device_t *device;
355
    devmap_device_t *device;
349
 
356
 
350
    if (NULL == driver) {
357
    if (NULL == driver) {
351
        printf("Invalid driver registration.\n");
358
        printf("Invalid driver registration.\n");
352
        ipc_answer_fast(iid, EREFUSED, 0, 0);
359
        ipc_answer_fast(iid, EREFUSED, 0, 0);
353
        return;
360
        return;
354
    }
361
    }
355
   
362
   
356
    /* Create new device entry */
363
    /* Create new device entry */
-
 
364
    if (NULL ==
357
    if (NULL == (device = (devmap_device_t *)malloc(sizeof(devmap_device_t)))) {
365
        (device = (devmap_device_t *)malloc(sizeof(devmap_device_t)))) {
358
        printf("Cannot allocate new device.\n");
366
        printf("Cannot allocate new device.\n");
359
        ipc_answer_fast(iid, ENOMEM, 0, 0);
367
        ipc_answer_fast(iid, ENOMEM, 0, 0);
360
        return;
368
        return;
361
    }
369
    }
362
   
370
   
363
    /* Get device name */
371
    /* Get device name */
364
    if (!ipc_data_receive(&callid, &call, NULL, &size)) {
372
    if (!ipc_data_receive(&callid, &call, NULL, &size)) {
365
        free(device);
373
        free(device);
366
        printf("Cannot read device name.\n");
374
        printf("Cannot read device name.\n");
367
        ipc_answer_fast(iid, EREFUSED, 0, 0);
375
        ipc_answer_fast(iid, EREFUSED, 0, 0);
368
        return;
376
        return;
369
    }
377
    }
370
 
378
 
371
    if (size > DEVMAP_NAME_MAXLEN) {
379
    if (size > DEVMAP_NAME_MAXLEN) {
372
        printf("Too long device name: %u.\n", size);
380
        printf("Too long device name: %u.\n", size);
373
        free(device);
381
        free(device);
374
        ipc_answer_fast(callid, EINVAL, 0, 0);
382
        ipc_answer_fast(callid, EINVAL, 0, 0);
375
        ipc_answer_fast(iid, EREFUSED, 0, 0);
383
        ipc_answer_fast(iid, EREFUSED, 0, 0);
376
        return;
384
        return;
377
    }
385
    }
378
 
386
 
379
        /* +1 for terminating \0 */
387
        /* +1 for terminating \0 */
380
    device->name = (char *)malloc(size + 1);
388
    device->name = (char *)malloc(size + 1);
381
 
389
 
382
    if (NULL == device->name) {
390
    if (NULL == device->name) {
383
        printf("Cannot read device name.\n");
391
        printf("Cannot read device name.\n");
384
        free(device);
392
        free(device);
385
        ipc_answer_fast(callid, ENOMEM, 0, 0);
393
        ipc_answer_fast(callid, ENOMEM, 0, 0);
386
        ipc_answer_fast(iid, EREFUSED, 0, 0);
394
        ipc_answer_fast(iid, EREFUSED, 0, 0);
387
        return;
395
        return;
388
    }
396
    }
389
   
397
   
390
    ipc_data_deliver(callid, &call, device->name, size);
398
    ipc_data_deliver(callid, &call, device->name, size);
391
    device->name[size] = 0;
399
    device->name[size] = 0;
392
 
400
 
393
    list_initialize(&(device->devices));
401
    list_initialize(&(device->devices));
394
    list_initialize(&(device->driver_devices));
402
    list_initialize(&(device->driver_devices));
395
 
403
 
396
    futex_down(&devices_list_futex);   
404
    futex_down(&devices_list_futex);   
397
 
405
 
398
    /* Check that device with such name is not already registered */
406
    /* Check that device with such name is not already registered */
399
    if (NULL != devmap_device_find_name(device->name)) {
407
    if (NULL != devmap_device_find_name(device->name)) {
400
        printf("Device '%s' already registered.\n", device->name);
408
        printf("Device '%s' already registered.\n", device->name);
401
        futex_up(&devices_list_futex); 
409
        futex_up(&devices_list_futex); 
402
        free(device->name);
410
        free(device->name);
403
        free(device);
411
        free(device);
404
        ipc_answer_fast(iid, EEXISTS, 0, 0);
412
        ipc_answer_fast(iid, EEXISTS, 0, 0);
405
        return;
413
        return;
406
    }
414
    }
407
 
415
 
408
    /* Get unique device handle */
416
    /* Get unique device handle */
409
    device->handle = devmap_create_handle();
417
    device->handle = devmap_create_handle();
410
 
418
 
411
    device->driver = driver;
419
    device->driver = driver;
412
   
420
   
413
    /* Insert device into list of all devices  */
421
    /* Insert device into list of all devices  */
414
    list_append(&(device->devices), &devices_list);
422
    list_append(&(device->devices), &devices_list);
415
 
423
 
416
    /* Insert device into list of devices that belog to one driver */
424
    /* Insert device into list of devices that belog to one driver */
417
    futex_down(&(device->driver->devices_futex));  
425
    futex_down(&(device->driver->devices_futex));  
418
   
426
   
419
    list_append(&(device->driver_devices), &(device->driver->devices));
427
    list_append(&(device->driver_devices), &(device->driver->devices));
420
   
428
   
421
    futex_up(&(device->driver->devices_futex));
429
    futex_up(&(device->driver->devices_futex));
422
    futex_up(&devices_list_futex); 
430
    futex_up(&devices_list_futex); 
423
 
431
 
424
    printf("Device '%s' registered.\n", device->name); 
432
    printf("Device '%s' registered.\n", device->name); 
425
    ipc_answer_fast(iid, EOK, device->handle, 0);
433
    ipc_answer_fast(iid, EOK, device->handle, 0);
426
 
434
 
427
    return;
435
    return;
428
}
436
}
429
 
437
 
430
/**
438
/**
431
 *
439
 *
432
 */
440
 */
433
static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall,
441
static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall,
434
    devmap_driver_t *driver)
442
    devmap_driver_t *driver)
435
{
443
{
436
    /* TODO */
444
    /* TODO */
437
 
445
 
438
    return EOK;
446
    return EOK;
439
}
447
}
440
 
448
 
441
/** Connect client to the device.
449
/** Connect client to the device.
442
 * Find device driver owning requested device and forward
450
 * Find device driver owning requested device and forward
443
 * the message to it.
451
 * the message to it.
444
 *
452
 *
445
 *
453
 *
446
 */
454
 */
447
static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
455
static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
448
{
456
{
449
    devmap_device_t *dev;
457
    devmap_device_t *dev;
450
    int handle;
458
    int handle;
451
 
459
 
452
    /*
460
    /*
453
     * Get handle from request
461
     * Get handle from request
454
     */
462
     */
455
    handle = IPC_GET_ARG1(*call);
463
    handle = IPC_GET_ARG1(*call);
456
    dev = devmap_device_find_handle(handle);
464
    dev = devmap_device_find_handle(handle);
457
 
465
 
458
    if (NULL == dev) {
466
    if (NULL == dev) {
459
        printf("DevMap: No registered device with handle %d.\n", handle);
467
        printf("DevMap: No registered device with handle %d.\n",
-
 
468
            handle);
460
        ipc_answer_fast(callid, ENOENT, 0, 0);
469
        ipc_answer_fast(callid, ENOENT, 0, 0);
461
        return;
470
        return;
462
    }
471
    }
463
 
472
 
464
        /* FIXME: is this correct method how to pass argument on forwarding ?*/
473
    /* FIXME: is this correct method how to pass argument on forwarding ?*/
465
    ipc_forward_fast(callid, dev->driver->phone, (ipcarg_t)(dev->handle), 0);
474
    ipc_forward_fast(callid, dev->driver->phone, (ipcarg_t)(dev->handle),
-
 
475
        0);
466
    return;
476
    return;
467
}
477
}
468
 
478
 
469
/** Find handle for device instance identified by name.
479
/** Find handle for device instance identified by name.
470
 * In answer will be send EOK and device handle in arg1 or a error
480
 * In answer will be send EOK and device handle in arg1 or a error
471
 * code from errno.h.
481
 * code from errno.h.
472
 */
482
 */
473
static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall)
483
static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall)
474
{
484
{
475
    char *name = NULL;
485
    char *name = NULL;
476
    size_t name_size;
486
    size_t name_size;
477
    const devmap_device_t *dev;
487
    const devmap_device_t *dev;
478
    ipc_callid_t callid;
488
    ipc_callid_t callid;
479
    ipc_call_t call;
489
    ipc_call_t call;
480
    ipcarg_t retval;
490
    ipcarg_t retval;
481
   
491
   
482
   
492
   
483
    /*
493
    /*
484
     * Wait for incoming message with device name (but do not
494
     * Wait for incoming message with device name (but do not
485
     * read the name itself until the buffer is allocated).
495
     * read the name itself until the buffer is allocated).
486
     */
496
     */
487
    if (!ipc_data_receive(&callid, &call, NULL, &name_size)) {
497
    if (!ipc_data_receive(&callid, &call, NULL, &name_size)) {
488
        ipc_answer_fast(callid, EREFUSED, 0, 0);
498
        ipc_answer_fast(callid, EREFUSED, 0, 0);
489
        ipc_answer_fast(iid, EREFUSED, 0, 0);
499
        ipc_answer_fast(iid, EREFUSED, 0, 0);
490
        return;
500
        return;
491
    }
501
    }
492
 
502
 
493
    if (name_size > DEVMAP_NAME_MAXLEN) {
503
    if (name_size > DEVMAP_NAME_MAXLEN) {
494
        ipc_answer_fast(callid, EINVAL, 0, 0);
504
        ipc_answer_fast(callid, EINVAL, 0, 0);
495
        ipc_answer_fast(iid, EREFUSED, 0, 0);
505
        ipc_answer_fast(iid, EREFUSED, 0, 0);
496
        return;
506
        return;
497
    }
507
    }
498
 
508
 
499
    /*
509
    /*
500
     * Allocate buffer for device name.
510
     * Allocate buffer for device name.
501
     */
511
     */
502
    if (NULL == (name = (char *)malloc(name_size))) {
512
    if (NULL == (name = (char *)malloc(name_size))) {
503
        ipc_answer_fast(callid, ENOMEM, 0, 0);
513
        ipc_answer_fast(callid, ENOMEM, 0, 0);
504
        ipc_answer_fast(iid, EREFUSED, 0, 0);
514
        ipc_answer_fast(iid, EREFUSED, 0, 0);
505
        return;
515
        return;
506
    }  
516
    }  
507
 
517
 
508
    /*
518
    /*
509
     * Send confirmation to sender and get data into buffer.
519
     * Send confirmation to sender and get data into buffer.
510
     */
520
     */
511
    if (EOK != (retval = ipc_data_deliver(callid, &call, name, name_size))) {
521
    if (EOK != (retval = ipc_data_deliver(callid, &call, name,
-
 
522
        name_size))) {
512
        ipc_answer_fast(iid, EREFUSED, 0, 0);
523
        ipc_answer_fast(iid, EREFUSED, 0, 0);
513
        return;
524
        return;
514
    }
525
    }
515
 
526
 
516
    /*
527
    /*
517
     * Find device name in linked list of known devices.
528
     * Find device name in linked list of known devices.
518
     */
529
     */
519
    dev = devmap_device_find_name(name);
530
    dev = devmap_device_find_name(name);
520
 
531
 
521
    /*
532
    /*
522
     * Device was not found.
533
     * Device was not found.
523
     */
534
     */
524
    if (NULL == dev) {
535
    if (NULL == dev) {
525
        printf("DevMap: device %s has not been registered.\n", name);
536
        printf("DevMap: device %s has not been registered.\n", name);
526
        ipc_answer_fast(iid, ENOENT, 0, 0);
537
        ipc_answer_fast(iid, ENOENT, 0, 0);
527
        return;
538
        return;
528
    }
539
    }
529
 
540
 
530
    printf("DevMap: device %s has handler %d.\n", name, dev->handle);
541
    printf("DevMap: device %s has handler %d.\n", name, dev->handle);
531
       
542
       
532
    ipc_answer_fast(iid, EOK, dev->handle, 0);
543
    ipc_answer_fast(iid, EOK, dev->handle, 0);
533
 
544
 
534
    return;
545
    return;
535
}
546
}
536
 
547
 
537
/** Find name of device identified by id and send it to caller.
548
/** Find name of device identified by id and send it to caller.
538
 *
549
 *
539
 */
550
 */
540
static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall)
551
static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall)
541
{
552
{
542
    const devmap_device_t *device;
553
    const devmap_device_t *device;
543
    size_t name_size;
554
    size_t name_size;
544
 
555
 
545
    device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
556
    device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
546
 
557
 
547
    /*
558
    /*
548
     * Device not found.
559
     * Device not found.
549
     */
560
     */
550
    if (NULL == device) {
561
    if (NULL == device) {
551
        ipc_answer_fast(iid, ENOENT, 0, 0);
562
        ipc_answer_fast(iid, ENOENT, 0, 0);
552
        return;
563
        return;
553
    }  
564
    }  
554
 
565
 
555
    ipc_answer_fast(iid, EOK, 0, 0);
566
    ipc_answer_fast(iid, EOK, 0, 0);
556
 
567
 
557
    name_size = strlen(device->name);
568
    name_size = strlen(device->name);
558
 
569
 
559
 
570
 
560
/*  FIXME:
571
/*  FIXME:
561
    we have no channel from DevMap to client ->
572
    we have no channel from DevMap to client ->
562
    sending must be initiated by client
573
    sending must be initiated by client
563
 
574
 
564
    int rc = ipc_data_send(phone, device->name, name_size);
575
    int rc = ipc_data_send(phone, device->name, name_size);
565
    if (rc != EOK) {
576
    if (rc != EOK) {
566
        async_wait_for(req, NULL);
577
        async_wait_for(req, NULL);
567
        return rc;
578
        return rc;
568
    }
579
    }
569
*/ 
580
*/ 
570
    /* TODO: send name in response */
581
    /* TODO: send name in response */
571
 
582
 
572
    return;
583
    return;
573
}
584
}
574
 
585
 
575
/** Handle connection with device driver.
586
/** Handle connection with device driver.
576
 *
587
 *
577
 */
588
 */
578
static void
589
static void
579
devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
590
devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
580
{
591
{
581
    ipc_callid_t callid;
592
    ipc_callid_t callid;
582
    ipc_call_t call;
593
    ipc_call_t call;
583
    bool cont = true;
594
    bool cont = true;
584
    devmap_driver_t *driver = NULL;
595
    devmap_driver_t *driver = NULL;
585
 
596
 
586
    ipc_answer_fast(iid, EOK, 0, 0);
597
    ipc_answer_fast(iid, EOK, 0, 0);
587
 
598
 
588
    devmap_driver_register(&driver);
599
    devmap_driver_register(&driver);
589
 
600
 
590
    if (NULL == driver) {
601
    if (NULL == driver) {
591
        printf("DevMap: driver registration failed.\n");
602
        printf("DevMap: driver registration failed.\n");
592
        return;
603
        return;
593
    }
604
    }
594
   
605
   
595
    while (cont) {
606
    while (cont) {
596
        callid = async_get_call(&call);
607
        callid = async_get_call(&call);
597
 
608
 
598
        switch (IPC_GET_METHOD(call)) {
609
        switch (IPC_GET_METHOD(call)) {
599
        case IPC_M_PHONE_HUNGUP:
610
        case IPC_M_PHONE_HUNGUP:
600
            printf("DevMap: connection hung up.\n");
611
            printf("DevMap: connection hung up.\n");
601
            cont = false;
612
            cont = false;
602
            continue; /* Exit thread */
613
            continue; /* Exit thread */
603
        case DEVMAP_DRIVER_UNREGISTER:
614
        case DEVMAP_DRIVER_UNREGISTER:
604
            printf("DevMap: unregister driver.\n");
615
            printf("DevMap: unregister driver.\n");
605
            if (NULL == driver) {
616
            if (NULL == driver) {
606
                printf("DevMap: driver was not registered!\n");
617
                printf("DevMap: driver was not registered!\n");
607
                ipc_answer_fast(callid, ENOENT, 0, 0);
618
                ipc_answer_fast(callid, ENOENT, 0, 0);
608
            } else {
619
            } else {
609
                ipc_answer_fast(callid, EOK, 0, 0);
620
                ipc_answer_fast(callid, EOK, 0, 0);
610
            }
621
            }
611
            break;
622
            break;
612
        case DEVMAP_DEVICE_REGISTER:
623
        case DEVMAP_DEVICE_REGISTER:
613
            /* Register one instance of device */
624
            /* Register one instance of device */
614
            devmap_device_register(callid, &call, driver);
625
            devmap_device_register(callid, &call, driver);
615
            break;
626
            break;
616
        case DEVMAP_DEVICE_UNREGISTER:
627
        case DEVMAP_DEVICE_UNREGISTER:
617
            /* Remove instance of device identified by handler */
628
            /* Remove instance of device identified by handler */
618
            devmap_device_unregister(callid, &call, driver);
629
            devmap_device_unregister(callid, &call, driver);
619
            break;
630
            break;
620
        case DEVMAP_DEVICE_GET_HANDLE:
631
        case DEVMAP_DEVICE_GET_HANDLE:
621
            devmap_get_handle(callid, &call);
632
            devmap_get_handle(callid, &call);
622
            break;
633
            break;
623
        case DEVMAP_DEVICE_GET_NAME:
634
        case DEVMAP_DEVICE_GET_NAME:
624
            devmap_get_handle(callid, &call);
635
            devmap_get_handle(callid, &call);
625
            break;
636
            break;
626
        default:
637
        default:
627
            if (!(callid & IPC_CALLID_NOTIFICATION)) {
638
            if (!(callid & IPC_CALLID_NOTIFICATION)) {
628
                ipc_answer_fast(callid, ENOENT, 0, 0);
639
                ipc_answer_fast(callid, ENOENT, 0, 0);
629
            }
640
            }
630
        }
641
        }
631
    }
642
    }
632
   
643
   
633
    if (NULL != driver) {
644
    if (NULL != driver) {
634
            /*
645
            /*
635
             * Unregister the device driver and all its devices.
646
             * Unregister the device driver and all its devices.
636
             */
647
             */
637
        devmap_driver_unregister(driver);
648
        devmap_driver_unregister(driver);
638
        driver = NULL;
649
        driver = NULL;
639
    }
650
    }
640
   
651
   
641
}
652
}
642
 
653
 
643
/** Handle connection with device client.
654
/** Handle connection with device client.
644
 *
655
 *
645
 */
656
 */
646
static void
657
static void
647
devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
658
devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
648
{
659
{
649
    ipc_callid_t callid;
660
    ipc_callid_t callid;
650
    ipc_call_t call;
661
    ipc_call_t call;
651
    bool cont = true;
662
    bool cont = true;
652
 
663
 
653
    ipc_answer_fast(iid, EOK, 0, 0); /* Accept connection */
664
    ipc_answer_fast(iid, EOK, 0, 0); /* Accept connection */
654
 
665
 
655
    while (cont) {
666
    while (cont) {
656
        callid = async_get_call(&call);
667
        callid = async_get_call(&call);
657
 
668
 
658
        switch (IPC_GET_METHOD(call)) {
669
        switch (IPC_GET_METHOD(call)) {
659
        case IPC_M_PHONE_HUNGUP:
670
        case IPC_M_PHONE_HUNGUP:
660
            printf("DevMap: connection hung up.\n");
671
            printf("DevMap: connection hung up.\n");
661
            cont = false;
672
            cont = false;
662
            continue; /* Exit thread */
673
            continue; /* Exit thread */
663
 
674
 
664
        case DEVMAP_DEVICE_CONNECT_ME_TO:
675
        case DEVMAP_DEVICE_CONNECT_ME_TO:
665
            /* Connect client to selected device */
676
            /* Connect client to selected device */
666
            printf("DevMap: connect to device %d.\n", IPC_GET_ARG1(call));
677
            printf("DevMap: connect to device %d.\n",
-
 
678
                IPC_GET_ARG1(call));
667
            devmap_forward(callid, &call);
679
            devmap_forward(callid, &call);
668
            break;
680
            break;
669
 
681
 
670
        case DEVMAP_DEVICE_GET_HANDLE:
682
        case DEVMAP_DEVICE_GET_HANDLE:
671
            devmap_get_handle(callid, &call);
683
            devmap_get_handle(callid, &call);
672
 
684
 
673
            break;
685
            break;
674
        case DEVMAP_DEVICE_GET_NAME:
686
        case DEVMAP_DEVICE_GET_NAME:
675
            /* TODO */
687
            /* TODO */
676
            devmap_get_name(callid, &call);
688
            devmap_get_name(callid, &call);
677
            break;
689
            break;
678
        default:
690
        default:
679
            if (!(callid & IPC_CALLID_NOTIFICATION)) {
691
            if (!(callid & IPC_CALLID_NOTIFICATION)) {
680
                ipc_answer_fast(callid, ENOENT, 0, 0);
692
                ipc_answer_fast(callid, ENOENT, 0, 0);
681
            }
693
            }
682
        }
694
        }
683
    }
695
    }
684
}
696
}
685
 
697
 
686
/** Function for handling connections to devmap
698
/** Function for handling connections to devmap
687
 *
699
 *
688
 */
700
 */
689
static void
701
static void
690
devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
702
devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
691
{
703
{
692
 
704
 
693
    printf("DevMap: new connection.\n");
705
    printf("DevMap: new connection.\n");
694
 
706
 
695
        /* Select interface */
707
        /* Select interface */
696
    switch ((ipcarg_t)(IPC_GET_ARG1(*icall))) {
708
    switch ((ipcarg_t)(IPC_GET_ARG1(*icall))) {
697
        case DEVMAP_DRIVER:
709
    case DEVMAP_DRIVER:
698
            devmap_connection_driver(iid, icall);
710
        devmap_connection_driver(iid, icall);
699
            break;
711
        break;
700
        case DEVMAP_CLIENT:
712
    case DEVMAP_CLIENT:
701
            devmap_connection_client(iid, icall);
713
        devmap_connection_client(iid, icall);
702
            break;
714
        break;
703
        default:
715
    default:
704
            ipc_answer_fast(iid, ENOENT, 0, 0); /* No such interface */
716
        ipc_answer_fast(iid, ENOENT, 0, 0); /* No such interface */
705
            printf("DevMap: Unknown interface %u.\n", \
717
        printf("DevMap: Unknown interface %u.\n",
706
                (ipcarg_t)(IPC_GET_ARG1(*icall)));
718
            (ipcarg_t)(IPC_GET_ARG1(*icall)));
707
    }
719
    }
708
 
720
 
709
    /* Cleanup */
721
    /* Cleanup */
710
   
722
   
711
    printf("DevMap: connection closed.\n");
723
    printf("DevMap: connection closed.\n");
712
    return;
724
    return;
713
}
725
}
714
 
726
 
715
/**
727
/**
716
 *
728
 *
717
 */
729
 */
718
int main(int argc, char *argv[])
730
int main(int argc, char *argv[])
719
{
731
{
720
    ipcarg_t phonead;
732
    ipcarg_t phonead;
721
 
733
 
722
    printf("DevMap: HelenOS device mapper.\n");
734
    printf("DevMap: HelenOS device mapper.\n");
723
 
735
 
724
    if (devmap_init() != 0) {
736
    if (devmap_init() != 0) {
725
        printf("Error while initializing DevMap service.\n");
737
        printf("Error while initializing DevMap service.\n");
726
        return -1;
738
        return -1;
727
    }
739
    }
728
 
740
 
729
        /* Set a handler of incomming connections */
741
        /* Set a handler of incomming connections */
730
    async_set_client_connection(devmap_connection);
742
    async_set_client_connection(devmap_connection);
731
 
743
 
732
        /* Register device mapper at naming service */
744
    /* Register device mapper at naming service */
733
    if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, &phonead) != 0)
745
    if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, &phonead) != 0)
734
        return -1;
746
        return -1;
735
   
747
   
736
    async_manager();
748
    async_manager();
737
    /* Never reached */
749
    /* Never reached */
738
    return 0;
750
    return 0;
739
}
751
}
740
 
752
 
741
/**
753
/**
742
 * @}
754
 * @}
743
 */
755
 */
744
 
756
 
745
 
757