Subversion Repositories HelenOS

Rev

Rev 3150 | Rev 4348 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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