Subversion Repositories HelenOS

Rev

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

Rev 3080 Rev 3386
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
#include <ipc/devmap.h>
47
#include <ipc/devmap.h>
48
 
48
 
49
#define NAME "devmap"
49
#define NAME "devmap"
50
 
50
 
51
 
51
 
52
LIST_INITIALIZE(devices_list);
52
LIST_INITIALIZE(devices_list);
53
LIST_INITIALIZE(drivers_list);
53
LIST_INITIALIZE(drivers_list);
54
 
54
 
55
/* order of locking:
55
/* order of locking:
56
 * drivers_list_futex
56
 * drivers_list_futex
57
 * devices_list_futex
57
 * devices_list_futex
58
 * (devmap_driver_t *)->devices_futex
58
 * (devmap_driver_t *)->devices_futex
59
 * create_handle_futex
59
 * create_handle_futex
60
 **/
60
 **/
61
 
61
 
62
static atomic_t devices_list_futex = FUTEX_INITIALIZER;
62
static atomic_t devices_list_futex = FUTEX_INITIALIZER;
63
static atomic_t drivers_list_futex = FUTEX_INITIALIZER;
63
static atomic_t drivers_list_futex = FUTEX_INITIALIZER;
64
static atomic_t create_handle_futex = FUTEX_INITIALIZER;
64
static atomic_t create_handle_futex = FUTEX_INITIALIZER;
65
 
65
 
66
 
66
 
67
static int devmap_create_handle(void)
67
static int devmap_create_handle(void)
68
{
68
{
69
    static int last_handle = 0;
69
    static int last_handle = 0;
70
    int handle;
70
    int handle;
71
 
71
 
72
    /* TODO: allow reusing old handles after their unregistration
72
    /* TODO: allow reusing old handles after their unregistration
73
        and implement some version of LRU algorithm */
73
        and implement some version of LRU algorithm */
74
    /* FIXME: overflow */
74
    /* FIXME: overflow */
75
    futex_down(&create_handle_futex);  
75
    futex_down(&create_handle_futex);  
76
 
76
 
77
    last_handle += 1;
77
    last_handle += 1;
78
    handle = last_handle;
78
    handle = last_handle;
79
 
79
 
80
    futex_up(&create_handle_futex);
80
    futex_up(&create_handle_futex);
81
 
81
 
82
    return handle;
82
    return handle;
83
}
83
}
84
 
84
 
85
 
85
 
86
/** Initialize device mapper.
86
/** Initialize device mapper.
87
 *
87
 *
88
 *
88
 *
89
 */
89
 */
90
static int devmap_init()
90
static int devmap_init()
91
{
91
{
92
    /* TODO: */
92
    /* TODO: */
93
 
93
 
94
    return EOK;
94
    return EOK;
95
}
95
}
96
 
96
 
97
/** Find device with given name.
97
/** Find device with given name.
98
 *
98
 *
99
 */
99
 */
100
static devmap_device_t *devmap_device_find_name(const char *name)
100
static devmap_device_t *devmap_device_find_name(const char *name)
101
{
101
{
102
    link_t *item;
102
    link_t *item;
103
    devmap_device_t *device = NULL;
103
    devmap_device_t *device = NULL;
104
 
104
 
105
    item = devices_list.next;
105
    item = devices_list.next;
106
 
106
 
107
    while (item != &devices_list) {
107
    while (item != &devices_list) {
108
 
108
 
109
        device = list_get_instance(item, devmap_device_t, devices);
109
        device = list_get_instance(item, devmap_device_t, devices);
110
        if (0 == strcmp(device->name, name)) {
110
        if (0 == strcmp(device->name, name)) {
111
            break;
111
            break;
112
        }
112
        }
113
        item = item->next;
113
        item = item->next;
114
    }
114
    }
115
 
115
 
116
    if (item == &devices_list)
116
    if (item == &devices_list)
117
        return NULL;
117
        return NULL;
118
 
118
 
119
    device = list_get_instance(item, devmap_device_t, devices);
119
    device = list_get_instance(item, devmap_device_t, devices);
120
    return device;
120
    return device;
121
}
121
}
122
 
122
 
123
/** Find device with given handle.
123
/** Find device with given handle.
124
 * @todo: use hash table
124
 * @todo: use hash table
125
 */
125
 */
126
static devmap_device_t *devmap_device_find_handle(int handle)
126
static devmap_device_t *devmap_device_find_handle(int handle)
127
{
127
{
128
    link_t *item;
128
    link_t *item;
129
    devmap_device_t *device = NULL;
129
    devmap_device_t *device = NULL;
130
   
130
   
131
    futex_down(&devices_list_futex);
131
    futex_down(&devices_list_futex);
132
 
132
 
133
    item = (&devices_list)->next;
133
    item = (&devices_list)->next;
134
 
134
 
135
    while (item != &devices_list) {
135
    while (item != &devices_list) {
136
 
136
 
137
        device = list_get_instance(item, devmap_device_t, devices);
137
        device = list_get_instance(item, devmap_device_t, devices);
138
        if (device->handle == handle) {
138
        if (device->handle == handle) {
139
            break;
139
            break;
140
        }
140
        }
141
        item = item->next;
141
        item = item->next;
142
    }
142
    }
143
 
143
 
144
    if (item == &devices_list) {
144
    if (item == &devices_list) {
145
        futex_up(&devices_list_futex);
145
        futex_up(&devices_list_futex);
146
        return NULL;
146
        return NULL;
147
    }
147
    }
148
 
148
 
149
    device = list_get_instance(item, devmap_device_t, devices);
149
    device = list_get_instance(item, devmap_device_t, devices);
150
   
150
   
151
    futex_up(&devices_list_futex);
151
    futex_up(&devices_list_futex);
152
 
152
 
153
    return device;
153
    return device;
154
}
154
}
155
 
155
 
156
/**
156
/**
157
 * Unregister device and free it. It's assumed that driver's device list is
157
 * Unregister device and free it. It's assumed that driver's device list is
158
 * already locked.
158
 * already locked.
159
 */
159
 */
160
static int devmap_device_unregister_core(devmap_device_t *device)
160
static int devmap_device_unregister_core(devmap_device_t *device)
161
{
161
{
162
 
162
 
163
    list_remove(&(device->devices));
163
    list_remove(&(device->devices));
164
    list_remove(&(device->driver_devices));
164
    list_remove(&(device->driver_devices));
165
 
165
 
166
    free(device->name);
166
    free(device->name);
167
    free(device);
167
    free(device);
168
 
168
 
169
 
169
 
170
    return EOK;
170
    return EOK;
171
}
171
}
172
 
172
 
173
/**
173
/**
174
 * Read info about new driver and add it into linked list of registered
174
 * Read info about new driver and add it into linked list of registered
175
 * drivers.
175
 * drivers.
176
 */
176
 */
177
static void devmap_driver_register(devmap_driver_t **odriver)
177
static void devmap_driver_register(devmap_driver_t **odriver)
178
{
178
{
179
    size_t name_size;
179
    size_t name_size;
180
    ipc_callid_t callid;
180
    ipc_callid_t callid;
181
    ipc_call_t call;
181
    ipc_call_t call;
182
    devmap_driver_t *driver;
182
    devmap_driver_t *driver;
183
    ipc_callid_t iid;
183
    ipc_callid_t iid;
184
    ipc_call_t icall;
184
    ipc_call_t icall;
185
 
185
 
186
    *odriver = NULL;
186
    *odriver = NULL;
187
   
187
   
188
    iid = async_get_call(&icall);
188
    iid = async_get_call(&icall);
189
 
189
 
190
    if (IPC_GET_METHOD(icall) != DEVMAP_DRIVER_REGISTER) {
190
    if (IPC_GET_METHOD(icall) != DEVMAP_DRIVER_REGISTER) {
191
        ipc_answer_0(iid, EREFUSED);
191
        ipc_answer_0(iid, EREFUSED);
192
        return;
192
        return;
193
    }
193
    }
194
 
194
 
195
    if (NULL ==
195
    if (NULL ==
196
        (driver = (devmap_driver_t *)malloc(sizeof(devmap_driver_t)))) {
196
        (driver = (devmap_driver_t *)malloc(sizeof(devmap_driver_t)))) {
197
        ipc_answer_0(iid, ENOMEM);
197
        ipc_answer_0(iid, ENOMEM);
198
        return;
198
        return;
199
    }
199
    }
200
 
200
 
201
    /*
201
    /*
202
     * Get driver name
202
     * Get driver name
203
     */
203
     */
204
    if (!ipc_data_write_receive(&callid, &name_size)) {
204
    if (!ipc_data_write_receive(&callid, &name_size)) {
205
        free(driver);
205
        free(driver);
206
        ipc_answer_0(callid, EREFUSED);
206
        ipc_answer_0(callid, EREFUSED);
207
        ipc_answer_0(iid, EREFUSED);
207
        ipc_answer_0(iid, EREFUSED);
208
        return;
208
        return;
209
    }
209
    }
210
 
210
 
211
    if (name_size > DEVMAP_NAME_MAXLEN) {
211
    if (name_size > DEVMAP_NAME_MAXLEN) {
212
        free(driver);
212
        free(driver);
213
        ipc_answer_0(callid, EINVAL);
213
        ipc_answer_0(callid, EINVAL);
214
        ipc_answer_0(iid, EREFUSED);
214
        ipc_answer_0(iid, EREFUSED);
215
        return;
215
        return;
216
    }
216
    }
217
 
217
 
218
    /*
218
    /*
219
     * Allocate buffer for device name.
219
     * Allocate buffer for device name.
220
     */
220
     */
221
    if (NULL == (driver->name = (char *)malloc(name_size + 1))) {
221
    if (NULL == (driver->name = (char *)malloc(name_size + 1))) {
222
        free(driver);
222
        free(driver);
223
        ipc_answer_0(callid, ENOMEM);
223
        ipc_answer_0(callid, ENOMEM);
224
        ipc_answer_0(iid, EREFUSED);
224
        ipc_answer_0(iid, EREFUSED);
225
        return;
225
        return;
226
    }  
226
    }  
227
 
227
 
228
    /*
228
    /*
229
     * Send confirmation to sender and get data into buffer.
229
     * Send confirmation to sender and get data into buffer.
230
     */
230
     */
231
    if (EOK != ipc_data_write_finalize(callid, driver->name, name_size)) {
231
    if (EOK != ipc_data_write_finalize(callid, driver->name, name_size)) {
232
        free(driver->name);
232
        free(driver->name);
233
        free(driver);
233
        free(driver);
234
        ipc_answer_0(iid, EREFUSED);
234
        ipc_answer_0(iid, EREFUSED);
235
        return;
235
        return;
236
    }
236
    }
237
 
237
 
238
    driver->name[name_size] = 0;
238
    driver->name[name_size] = 0;
239
 
239
 
240
    /* Initialize futex for list of devices owned by this driver */
240
    /* Initialize futex for list of devices owned by this driver */
241
    futex_initialize(&(driver->devices_futex), 1);
241
    futex_initialize(&(driver->devices_futex), 1);
242
 
242
 
243
    /*
243
    /*
244
     * Initialize list of asociated devices
244
     * Initialize list of asociated devices
245
     */
245
     */
246
    list_initialize(&(driver->devices));
246
    list_initialize(&(driver->devices));
247
 
247
 
248
    /*
248
    /*
249
     * Create connection to the driver
249
     * Create connection to the driver
250
     */
250
     */
251
    callid = async_get_call(&call);
251
    callid = async_get_call(&call);
252
 
252
 
253
    if (IPC_M_CONNECT_TO_ME != IPC_GET_METHOD(call)) {
253
    if (IPC_M_CONNECT_TO_ME != IPC_GET_METHOD(call)) {
254
        ipc_answer_0(callid, ENOTSUP);
254
        ipc_answer_0(callid, ENOTSUP);
255
       
255
       
256
        free(driver->name);
256
        free(driver->name);
257
        free(driver);
257
        free(driver);
258
        ipc_answer_0(iid, ENOTSUP);
258
        ipc_answer_0(iid, ENOTSUP);
259
        return;
259
        return;
260
    }
260
    }
261
 
261
 
262
    driver->phone = IPC_GET_ARG5(call);
262
    driver->phone = IPC_GET_ARG5(call);
263
   
263
   
264
    ipc_answer_0(callid, EOK);
264
    ipc_answer_0(callid, EOK);
265
   
265
   
266
    list_initialize(&(driver->drivers));
266
    list_initialize(&(driver->drivers));
267
 
267
 
268
    futex_down(&drivers_list_futex);   
268
    futex_down(&drivers_list_futex);   
269
   
269
   
270
    /* TODO:
270
    /* TODO:
271
     * check that no driver with name equal to driver->name is registered
271
     * check that no driver with name equal to driver->name is registered
272
     */
272
     */
273
 
273
 
274
    /*
274
    /*
275
     * Insert new driver into list of registered drivers
275
     * Insert new driver into list of registered drivers
276
     */
276
     */
277
    list_append(&(driver->drivers), &drivers_list);
277
    list_append(&(driver->drivers), &drivers_list);
278
    futex_up(&drivers_list_futex); 
278
    futex_up(&drivers_list_futex); 
279
   
279
   
280
    ipc_answer_0(iid, EOK);
280
    ipc_answer_0(iid, EOK);
281
 
281
 
282
    *odriver = driver;
282
    *odriver = driver;
283
}
283
}
284
 
284
 
285
/** Unregister device driver, unregister all its devices and free driver
285
/** Unregister device driver, unregister all its devices and free driver
286
 * structure.
286
 * structure.
287
 */
287
 */
288
static int devmap_driver_unregister(devmap_driver_t *driver)
288
static int devmap_driver_unregister(devmap_driver_t *driver)
289
{
289
{
290
    devmap_device_t *device;
290
    devmap_device_t *device;
291
 
291
 
292
    if (NULL == driver)
292
    if (NULL == driver)
293
        return EEXISTS;
293
        return EEXISTS;
294
   
294
   
295
    futex_down(&drivers_list_futex);   
295
    futex_down(&drivers_list_futex);   
296
 
296
 
297
    ipc_hangup(driver->phone);
297
    ipc_hangup(driver->phone);
298
   
298
   
299
    /* remove it from list of drivers */
299
    /* remove it from list of drivers */
300
    list_remove(&(driver->drivers));
300
    list_remove(&(driver->drivers));
301
 
301
 
302
    /* unregister all its devices */
302
    /* unregister all its devices */
303
   
303
   
304
    futex_down(&devices_list_futex);   
304
    futex_down(&devices_list_futex);   
305
    futex_down(&(driver->devices_futex));
305
    futex_down(&(driver->devices_futex));
306
 
306
 
307
    while (!list_empty(&(driver->devices))) {
307
    while (!list_empty(&(driver->devices))) {
308
        device = list_get_instance(driver->devices.next,
308
        device = list_get_instance(driver->devices.next,
309
            devmap_device_t, driver_devices);
309
            devmap_device_t, driver_devices);
310
        devmap_device_unregister_core(device);
310
        devmap_device_unregister_core(device);
311
    }
311
    }
312
   
312
   
313
    futex_up(&(driver->devices_futex));
313
    futex_up(&(driver->devices_futex));
314
    futex_up(&devices_list_futex); 
314
    futex_up(&devices_list_futex); 
315
    futex_up(&drivers_list_futex); 
315
    futex_up(&drivers_list_futex); 
316
 
316
 
317
    /* free name and driver */
317
    /* free name and driver */
318
    if (NULL != driver->name) {
318
    if (NULL != driver->name) {
319
        free(driver->name);
319
        free(driver->name);
320
    }
320
    }
321
 
321
 
322
    free(driver);
322
    free(driver);
323
 
323
 
324
    return EOK;
324
    return EOK;
325
}
325
}
326
 
326
 
327
 
327
 
328
/** Register instance of device
328
/** Register instance of device
329
 *
329
 *
330
 */
330
 */
331
static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
331
static void devmap_device_register(ipc_callid_t iid, ipc_call_t *icall,
332
    devmap_driver_t *driver)
332
    devmap_driver_t *driver)
333
{
333
{
334
    ipc_callid_t callid;
334
    ipc_callid_t callid;
335
    size_t size;
335
    size_t size;
336
    devmap_device_t *device;
336
    devmap_device_t *device;
337
 
337
 
338
    if (NULL == driver) {
338
    if (NULL == driver) {
339
        ipc_answer_0(iid, EREFUSED);
339
        ipc_answer_0(iid, EREFUSED);
340
        return;
340
        return;
341
    }
341
    }
342
   
342
   
343
    /* Create new device entry */
343
    /* Create new device entry */
344
    if (NULL ==
344
    if (NULL ==
345
        (device = (devmap_device_t *) malloc(sizeof(devmap_device_t)))) {
345
        (device = (devmap_device_t *) malloc(sizeof(devmap_device_t)))) {
346
        ipc_answer_0(iid, ENOMEM);
346
        ipc_answer_0(iid, ENOMEM);
347
        return;
347
        return;
348
    }
348
    }
349
   
349
   
350
    /* Get device name */
350
    /* Get device name */
351
    if (!ipc_data_write_receive(&callid, &size)) {
351
    if (!ipc_data_write_receive(&callid, &size)) {
352
        free(device);
352
        free(device);
353
        ipc_answer_0(iid, EREFUSED);
353
        ipc_answer_0(iid, EREFUSED);
354
        return;
354
        return;
355
    }
355
    }
356
 
356
 
357
    if (size > DEVMAP_NAME_MAXLEN) {
357
    if (size > DEVMAP_NAME_MAXLEN) {
358
        free(device);
358
        free(device);
359
        ipc_answer_0(callid, EINVAL);
359
        ipc_answer_0(callid, EINVAL);
360
        ipc_answer_0(iid, EREFUSED);
360
        ipc_answer_0(iid, EREFUSED);
361
        return;
361
        return;
362
    }
362
    }
363
   
363
   
364
    /* +1 for terminating \0 */
364
    /* +1 for terminating \0 */
365
    device->name = (char *) malloc(size + 1);
365
    device->name = (char *) malloc(size + 1);
366
 
366
 
367
    if (NULL == device->name) {
367
    if (NULL == device->name) {
368
        free(device);
368
        free(device);
369
        ipc_answer_0(callid, ENOMEM);
369
        ipc_answer_0(callid, ENOMEM);
370
        ipc_answer_0(iid, EREFUSED);
370
        ipc_answer_0(iid, EREFUSED);
371
        return;
371
        return;
372
    }
372
    }
373
   
373
   
374
    ipc_data_write_finalize(callid, device->name, size);
374
    ipc_data_write_finalize(callid, device->name, size);
375
    device->name[size] = 0;
375
    device->name[size] = 0;
376
 
376
 
377
    list_initialize(&(device->devices));
377
    list_initialize(&(device->devices));
378
    list_initialize(&(device->driver_devices));
378
    list_initialize(&(device->driver_devices));
379
 
379
 
380
    futex_down(&devices_list_futex);   
380
    futex_down(&devices_list_futex);   
381
 
381
 
382
    /* Check that device with such name is not already registered */
382
    /* Check that device with such name is not already registered */
383
    if (NULL != devmap_device_find_name(device->name)) {
383
    if (NULL != devmap_device_find_name(device->name)) {
384
        printf(NAME ": Device '%s' already registered\n", device->name);
384
        printf(NAME ": Device '%s' already registered\n", device->name);
385
        futex_up(&devices_list_futex); 
385
        futex_up(&devices_list_futex); 
386
        free(device->name);
386
        free(device->name);
387
        free(device);
387
        free(device);
388
        ipc_answer_0(iid, EEXISTS);
388
        ipc_answer_0(iid, EEXISTS);
389
        return;
389
        return;
390
    }
390
    }
391
 
391
 
392
    /* Get unique device handle */
392
    /* Get unique device handle */
393
    device->handle = devmap_create_handle();
393
    device->handle = devmap_create_handle();
394
 
394
 
395
    device->driver = driver;
395
    device->driver = driver;
396
   
396
   
397
    /* Insert device into list of all devices  */
397
    /* Insert device into list of all devices  */
398
    list_append(&device->devices, &devices_list);
398
    list_append(&device->devices, &devices_list);
399
 
399
 
400
    /* Insert device into list of devices that belog to one driver */
400
    /* Insert device into list of devices that belog to one driver */
401
    futex_down(&device->driver->devices_futex);
401
    futex_down(&device->driver->devices_futex);
402
   
402
   
403
    list_append(&device->driver_devices, &device->driver->devices);
403
    list_append(&device->driver_devices, &device->driver->devices);
404
   
404
   
405
    futex_up(&device->driver->devices_futex);  
405
    futex_up(&device->driver->devices_futex);  
406
    futex_up(&devices_list_futex); 
406
    futex_up(&devices_list_futex); 
407
 
407
 
408
    ipc_answer_1(iid, EOK, device->handle);
408
    ipc_answer_1(iid, EOK, device->handle);
409
}
409
}
410
 
410
 
411
/**
411
/**
412
 *
412
 *
413
 */
413
 */
414
static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall,
414
static int devmap_device_unregister(ipc_callid_t iid, ipc_call_t *icall,
415
    devmap_driver_t *driver)
415
    devmap_driver_t *driver)
416
{
416
{
417
    /* TODO */
417
    /* TODO */
418
 
418
 
419
    return EOK;
419
    return EOK;
420
}
420
}
421
 
421
 
422
/** Connect client to the device.
422
/** Connect client to the device.
423
 * Find device driver owning requested device and forward
423
 * Find device driver owning requested device and forward
424
 * the message to it.
424
 * the message to it.
425
 */
425
 */
426
static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
426
static void devmap_forward(ipc_callid_t callid, ipc_call_t *call)
427
{
427
{
428
    devmap_device_t *dev;
428
    devmap_device_t *dev;
429
    int handle;
429
    int handle;
430
 
430
 
431
    /*
431
    /*
432
     * Get handle from request
432
     * Get handle from request
433
     */
433
     */
434
    handle = IPC_GET_ARG2(*call);
434
    handle = IPC_GET_ARG2(*call);
435
    dev = devmap_device_find_handle(handle);
435
    dev = devmap_device_find_handle(handle);
436
 
436
 
437
    if (NULL == dev) {
437
    if (NULL == dev) {
438
        ipc_answer_0(callid, ENOENT);
438
        ipc_answer_0(callid, ENOENT);
439
        return;
439
        return;
440
    }
440
    }
441
 
441
 
442
    ipc_forward_fast(callid, dev->driver->phone, (ipcarg_t)(dev->handle),
442
    ipc_forward_fast(callid, dev->driver->phone, (ipcarg_t)(dev->handle),
443
        IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
443
        IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
444
}
444
}
445
 
445
 
446
/** Find handle for device instance identified by name.
446
/** Find handle for device instance identified by name.
447
 * In answer will be send EOK and device handle in arg1 or a error
447
 * In answer will be send EOK and device handle in arg1 or a error
448
 * code from errno.h.
448
 * code from errno.h.
449
 */
449
 */
450
static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall)
450
static void devmap_get_handle(ipc_callid_t iid, ipc_call_t *icall)
451
{
451
{
452
    char *name = NULL;
452
    char *name = NULL;
453
    size_t name_size;
453
    size_t name_size;
454
    const devmap_device_t *dev;
454
    const devmap_device_t *dev;
455
    ipc_callid_t callid;
455
    ipc_callid_t callid;
456
    ipcarg_t retval;
456
    ipcarg_t retval;
457
   
457
   
458
    /*
458
    /*
459
     * Wait for incoming message with device name (but do not
459
     * Wait for incoming message with device name (but do not
460
     * read the name itself until the buffer is allocated).
460
     * read the name itself until the buffer is allocated).
461
     */
461
     */
462
    if (!ipc_data_write_receive(&callid, &name_size)) {
462
    if (!ipc_data_write_receive(&callid, &name_size)) {
463
        ipc_answer_0(callid, EREFUSED);
463
        ipc_answer_0(callid, EREFUSED);
464
        ipc_answer_0(iid, EREFUSED);
464
        ipc_answer_0(iid, EREFUSED);
465
        return;
465
        return;
466
    }
466
    }
467
 
467
 
468
    if (name_size > DEVMAP_NAME_MAXLEN) {
468
    if (name_size > DEVMAP_NAME_MAXLEN) {
469
        ipc_answer_0(callid, EINVAL);
469
        ipc_answer_0(callid, EINVAL);
470
        ipc_answer_0(iid, EREFUSED);
470
        ipc_answer_0(iid, EREFUSED);
471
        return;
471
        return;
472
    }
472
    }
473
 
473
 
474
    /*
474
    /*
475
     * Allocate buffer for device name.
475
     * Allocate buffer for device name.
476
     */
476
     */
477
    if (NULL == (name = (char *)malloc(name_size))) {
477
    if (NULL == (name = (char *)malloc(name_size))) {
478
        ipc_answer_0(callid, ENOMEM);
478
        ipc_answer_0(callid, ENOMEM);
479
        ipc_answer_0(iid, EREFUSED);
479
        ipc_answer_0(iid, EREFUSED);
480
        return;
480
        return;
481
    }  
481
    }  
482
 
482
 
483
    /*
483
    /*
484
     * Send confirmation to sender and get data into buffer.
484
     * Send confirmation to sender and get data into buffer.
485
     */
485
     */
486
    if (EOK != (retval = ipc_data_write_finalize(callid, name,
486
    if (EOK != (retval = ipc_data_write_finalize(callid, name,
487
        name_size))) {
487
        name_size))) {
488
        ipc_answer_0(iid, EREFUSED);
488
        ipc_answer_0(iid, EREFUSED);
489
        return;
489
        return;
490
    }
490
    }
491
 
491
 
492
    /*
492
    /*
493
     * Find device name in linked list of known devices.
493
     * Find device name in linked list of known devices.
494
     */
494
     */
495
    dev = devmap_device_find_name(name);
495
    dev = devmap_device_find_name(name);
496
 
496
 
497
    /*
497
    /*
498
     * Device was not found.
498
     * Device was not found.
499
     */
499
     */
500
    if (NULL == dev) {
500
    if (NULL == dev) {
501
        ipc_answer_0(iid, ENOENT);
501
        ipc_answer_0(iid, ENOENT);
502
        return;
502
        return;
503
    }
503
    }
504
 
504
 
505
    ipc_answer_1(iid, EOK, dev->handle);
505
    ipc_answer_1(iid, EOK, dev->handle);
506
}
506
}
507
 
507
 
508
/** Find name of device identified by id and send it to caller.
508
/** Find name of device identified by id and send it to caller.
509
 *
509
 *
510
 */
510
 */
511
static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall)
511
static void devmap_get_name(ipc_callid_t iid, ipc_call_t *icall)
512
{
512
{
513
    const devmap_device_t *device;
513
    const devmap_device_t *device;
514
    size_t name_size;
514
    size_t name_size;
515
 
515
 
516
    device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
516
    device = devmap_device_find_handle(IPC_GET_ARG1(*icall));
517
 
517
 
518
    /*
518
    /*
519
     * Device not found.
519
     * Device not found.
520
     */
520
     */
521
    if (NULL == device) {
521
    if (NULL == device) {
522
        ipc_answer_0(iid, ENOENT);
522
        ipc_answer_0(iid, ENOENT);
523
        return;
523
        return;
524
    }  
524
    }  
525
 
525
 
526
    ipc_answer_0(iid, EOK);
526
    ipc_answer_0(iid, EOK);
527
 
527
 
528
    name_size = strlen(device->name);
528
    name_size = strlen(device->name);
529
 
529
 
530
 
530
 
531
/*  FIXME:
531
/*  FIXME:
532
    we have no channel from DEVMAP to client ->
532
    we have no channel from DEVMAP to client ->
533
    sending must be initiated by client
533
    sending must be initiated by client
534
 
534
 
535
    int rc = ipc_data_write_send(phone, device->name, name_size);
535
    int rc = ipc_data_write_send(phone, device->name, name_size);
536
    if (rc != EOK) {
536
    if (rc != EOK) {
537
        async_wait_for(req, NULL);
537
        async_wait_for(req, NULL);
538
        return rc;
538
        return rc;
539
    }
539
    }
540
*/ 
540
*/ 
541
    /* TODO: send name in response */
541
    /* TODO: send name in response */
542
}
542
}
543
 
543
 
544
/** Handle connection with device driver.
544
/** Handle connection with device driver.
545
 *
545
 *
546
 */
546
 */
547
static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
547
static void devmap_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
548
{
548
{
549
    ipc_callid_t callid;
549
    ipc_callid_t callid;
550
    ipc_call_t call;
550
    ipc_call_t call;
551
    bool cont = true;
551
    bool cont = true;
552
    devmap_driver_t *driver = NULL;
552
    devmap_driver_t *driver = NULL;
553
 
553
 
554
    ipc_answer_0(iid, EOK);
554
    ipc_answer_0(iid, EOK);
555
 
555
 
556
    devmap_driver_register(&driver);
556
    devmap_driver_register(&driver);
557
 
557
 
558
    if (NULL == driver)
558
    if (NULL == driver)
559
        return;
559
        return;
560
   
560
   
561
    while (cont) {
561
    while (cont) {
562
        callid = async_get_call(&call);
562
        callid = async_get_call(&call);
563
 
563
 
564
        switch (IPC_GET_METHOD(call)) {
564
        switch (IPC_GET_METHOD(call)) {
565
        case IPC_M_PHONE_HUNGUP:
565
        case IPC_M_PHONE_HUNGUP:
566
            cont = false;
566
            cont = false;
567
            continue; /* Exit thread */
567
            continue; /* Exit thread */
568
        case DEVMAP_DRIVER_UNREGISTER:
568
        case DEVMAP_DRIVER_UNREGISTER:
569
            if (NULL == driver) {
569
            if (NULL == driver) {
570
                ipc_answer_0(callid, ENOENT);
570
                ipc_answer_0(callid, ENOENT);
571
            } else {
571
            } else {
572
                ipc_answer_0(callid, EOK);
572
                ipc_answer_0(callid, EOK);
573
            }
573
            }
574
            break;
574
            break;
575
        case DEVMAP_DEVICE_REGISTER:
575
        case DEVMAP_DEVICE_REGISTER:
576
            /* Register one instance of device */
576
            /* Register one instance of device */
577
            devmap_device_register(callid, &call, driver);
577
            devmap_device_register(callid, &call, driver);
578
            break;
578
            break;
579
        case DEVMAP_DEVICE_UNREGISTER:
579
        case DEVMAP_DEVICE_UNREGISTER:
580
            /* Remove instance of device identified by handler */
580
            /* Remove instance of device identified by handler */
581
            devmap_device_unregister(callid, &call, driver);
581
            devmap_device_unregister(callid, &call, driver);
582
            break;
582
            break;
583
        case DEVMAP_DEVICE_GET_HANDLE:
583
        case DEVMAP_DEVICE_GET_HANDLE:
584
            devmap_get_handle(callid, &call);
584
            devmap_get_handle(callid, &call);
585
            break;
585
            break;
586
        case DEVMAP_DEVICE_GET_NAME:
586
        case DEVMAP_DEVICE_GET_NAME:
587
            devmap_get_handle(callid, &call);
587
            devmap_get_handle(callid, &call);
588
            break;
588
            break;
589
        default:
589
        default:
590
            if (!(callid & IPC_CALLID_NOTIFICATION)) {
590
            if (!(callid & IPC_CALLID_NOTIFICATION)) {
591
                ipc_answer_0(callid, ENOENT);
591
                ipc_answer_0(callid, ENOENT);
592
            }
592
            }
593
        }
593
        }
594
    }
594
    }
595
   
595
   
596
    if (NULL != driver) {
596
    if (NULL != driver) {
597
        /*
597
        /*
598
         * Unregister the device driver and all its devices.
598
         * Unregister the device driver and all its devices.
599
         */
599
         */
600
        devmap_driver_unregister(driver);
600
        devmap_driver_unregister(driver);
601
        driver = NULL;
601
        driver = NULL;
602
    }
602
    }
603
   
603
   
604
}
604
}
605
 
605
 
606
/** Handle connection with device client.
606
/** Handle connection with device client.
607
 *
607
 *
608
 */
608
 */
609
static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
609
static void devmap_connection_client(ipc_callid_t iid, ipc_call_t *icall)
610
{
610
{
611
    ipc_callid_t callid;
611
    ipc_callid_t callid;
612
    ipc_call_t call;
612
    ipc_call_t call;
613
    bool cont = true;
613
    bool cont = true;
614
 
614
 
615
    ipc_answer_0(iid, EOK); /* Accept connection */
615
    ipc_answer_0(iid, EOK); /* Accept connection */
616
 
616
 
617
    while (cont) {
617
    while (cont) {
618
        callid = async_get_call(&call);
618
        callid = async_get_call(&call);
619
 
619
 
620
        switch (IPC_GET_METHOD(call)) {
620
        switch (IPC_GET_METHOD(call)) {
621
        case IPC_M_PHONE_HUNGUP:
621
        case IPC_M_PHONE_HUNGUP:
622
            cont = false;
622
            cont = false;
623
            continue; /* Exit thread */
623
            continue; /* Exit thread */
624
 
624
 
625
        case DEVMAP_DEVICE_GET_HANDLE:
625
        case DEVMAP_DEVICE_GET_HANDLE:
626
            devmap_get_handle(callid, &call);
626
            devmap_get_handle(callid, &call);
627
 
627
 
628
            break;
628
            break;
629
        case DEVMAP_DEVICE_GET_NAME:
629
        case DEVMAP_DEVICE_GET_NAME:
630
            /* TODO */
630
            /* TODO */
631
            devmap_get_name(callid, &call);
631
            devmap_get_name(callid, &call);
632
            break;
632
            break;
633
        default:
633
        default:
634
            if (!(callid & IPC_CALLID_NOTIFICATION)) {
634
            if (!(callid & IPC_CALLID_NOTIFICATION)) {
635
                ipc_answer_0(callid, ENOENT);
635
                ipc_answer_0(callid, ENOENT);
636
            }
636
            }
637
        }
637
        }
638
    }
638
    }
639
}
639
}
640
 
640
 
641
/** Function for handling connections to devmap
641
/** Function for handling connections to devmap
642
 *
642
 *
643
 */
643
 */
644
static void devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
644
static void devmap_connection(ipc_callid_t iid, ipc_call_t *icall)
645
{
645
{
646
    /* Select interface */
646
    /* Select interface */
647
    switch ((ipcarg_t) (IPC_GET_ARG1(*icall))) {
647
    switch ((ipcarg_t) (IPC_GET_ARG1(*icall))) {
648
    case DEVMAP_DRIVER:
648
    case DEVMAP_DRIVER:
649
        devmap_connection_driver(iid, icall);
649
        devmap_connection_driver(iid, icall);
650
        break;
650
        break;
651
    case DEVMAP_CLIENT:
651
    case DEVMAP_CLIENT:
652
        devmap_connection_client(iid, icall);
652
        devmap_connection_client(iid, icall);
653
        break;
653
        break;
654
    case DEVMAP_CONNECT_TO_DEVICE:
654
    case DEVMAP_CONNECT_TO_DEVICE:
655
        /* Connect client to selected device */
655
        /* Connect client to selected device */
656
        devmap_forward(iid, icall);
656
        devmap_forward(iid, icall);
657
        break;
657
        break;
658
    default:
658
    default:
659
        ipc_answer_0(iid, ENOENT); /* No such interface */
659
        ipc_answer_0(iid, ENOENT); /* No such interface */
660
    }
660
    }
661
 
661
 
662
    /* Cleanup */
662
    /* Cleanup */
663
}
663
}
664
 
664
 
665
/**
665
/**
666
 *
666
 *
667
 */
667
 */
668
int main(int argc, char *argv[])
668
int main(int argc, char *argv[])
669
{
669
{
670
    printf(NAME ": HelenOS Device Mapper\n");
670
    printf(NAME ": HelenOS Device Mapper\n");
671
   
671
   
672
    ipcarg_t phonead;
672
    ipcarg_t phonead;
673
 
673
 
674
    if (devmap_init() != 0) {
674
    if (devmap_init() != 0) {
675
        printf(NAME ": Error while initializing service\n");
675
        printf(NAME ": Error while initializing service\n");
676
        return -1;
676
        return -1;
677
    }
677
    }
678
   
678
   
679
    /* Set a handler of incomming connections */
679
    /* Set a handler of incomming connections */
680
    async_set_client_connection(devmap_connection);
680
    async_set_client_connection(devmap_connection);
681
 
681
 
682
    /* Register device mapper at naming service */
682
    /* Register device mapper at naming service */
683
    if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0)
683
    if (ipc_connect_to_me(PHONE_NS, SERVICE_DEVMAP, 0, 0, &phonead) != 0)
684
        return -1;
684
        return -1;
685
   
685
   
686
    printf(NAME ": Accepting connections\n");
686
    printf(NAME ": Accepting connections\n");
687
    async_manager();
687
    async_manager();
688
    /* Never reached */
688
    /* Never reached */
689
    return 0;
689
    return 0;
690
}
690
}
691
 
691
 
692
/**
692
/**
693
 * @}
693
 * @}
694
 */
694
 */
695
 
695