~jakub/helenos/ia64-revival

« back to all changes in this revision

Viewing changes to uspace/lib/c/generic/devman.c

  • Committer: Jakub Jermar
  • Date: 2011-04-13 14:45:41 UTC
  • mfrom: (527.1.397 main-clone)
  • Revision ID: jakub@jermar.eu-20110413144541-x0j3r1zxqhsljx1o
MergeĀ mainlineĀ changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2007 Josef Cejka
 
3
 * Copyright (c) 2009 Jiri Svoboda
 
4
 * Copyright (c) 2010 Lenka Trochtova
 
5
 * All rights reserved.
 
6
 *
 
7
 * Redistribution and use in source and binary forms, with or without
 
8
 * modification, are permitted provided that the following conditions
 
9
 * are met:
 
10
 *
 
11
 * - Redistributions of source code must retain the above copyright
 
12
 *   notice, this list of conditions and the following disclaimer.
 
13
 * - Redistributions in binary form must reproduce the above copyright
 
14
 *   notice, this list of conditions and the following disclaimer in the
 
15
 *   documentation and/or other materials provided with the distribution.
 
16
 * - The name of the author may not be used to endorse or promote products
 
17
 *   derived from this software without specific prior written permission.
 
18
 *
 
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 
20
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
21
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
22
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 
23
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
24
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
25
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
26
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
27
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
28
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
29
 */
 
30
 
 
31
/** @addtogroup libc
 
32
 * @{
 
33
 */
 
34
/** @file
 
35
 */
 
36
 
 
37
#include <str.h>
 
38
#include <stdio.h>
 
39
#include <ipc/services.h>
 
40
#include <ipc/devman.h>
 
41
#include <devman.h>
 
42
#include <async.h>
 
43
#include <fibril_synch.h>
 
44
#include <errno.h>
 
45
#include <malloc.h>
 
46
#include <bool.h>
 
47
#include <adt/list.h>
 
48
 
 
49
static int devman_phone_driver = -1;
 
50
static int devman_phone_client = -1;
 
51
 
 
52
static FIBRIL_MUTEX_INITIALIZE(devman_phone_mutex);
 
53
 
 
54
int devman_get_phone(devman_interface_t iface, unsigned int flags)
 
55
{
 
56
        switch (iface) {
 
57
        case DEVMAN_DRIVER:
 
58
                fibril_mutex_lock(&devman_phone_mutex);
 
59
                if (devman_phone_driver >= 0) {
 
60
                        fibril_mutex_unlock(&devman_phone_mutex);
 
61
                        return devman_phone_driver;
 
62
                }
 
63
                
 
64
                if (flags & IPC_FLAG_BLOCKING)
 
65
                        devman_phone_driver = async_connect_me_to_blocking(
 
66
                            PHONE_NS, SERVICE_DEVMAN, DEVMAN_DRIVER, 0);
 
67
                else
 
68
                        devman_phone_driver = async_connect_me_to(PHONE_NS,
 
69
                            SERVICE_DEVMAN, DEVMAN_DRIVER, 0);
 
70
                
 
71
                fibril_mutex_unlock(&devman_phone_mutex);
 
72
                return devman_phone_driver;
 
73
        case DEVMAN_CLIENT:
 
74
                fibril_mutex_lock(&devman_phone_mutex);
 
75
                if (devman_phone_client >= 0) {
 
76
                        fibril_mutex_unlock(&devman_phone_mutex);
 
77
                        return devman_phone_client;
 
78
                }
 
79
                
 
80
                if (flags & IPC_FLAG_BLOCKING) {
 
81
                        devman_phone_client = async_connect_me_to_blocking(
 
82
                            PHONE_NS, SERVICE_DEVMAN, DEVMAN_CLIENT, 0);
 
83
                } else {
 
84
                        devman_phone_client = async_connect_me_to(PHONE_NS,
 
85
                            SERVICE_DEVMAN, DEVMAN_CLIENT, 0);
 
86
                }
 
87
                
 
88
                fibril_mutex_unlock(&devman_phone_mutex);
 
89
                return devman_phone_client;
 
90
        default:
 
91
                return -1;
 
92
        }
 
93
}
 
94
 
 
95
/** Register running driver with device manager. */
 
96
int devman_driver_register(const char *name, async_client_conn_t conn)
 
97
{
 
98
        int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING);
 
99
        
 
100
        if (phone < 0)
 
101
                return phone;
 
102
        
 
103
        async_serialize_start();
 
104
        
 
105
        ipc_call_t answer;
 
106
        aid_t req = async_send_2(phone, DEVMAN_DRIVER_REGISTER, 0, 0, &answer);
 
107
        
 
108
        sysarg_t retval = async_data_write_start(phone, name, str_size(name));
 
109
        if (retval != EOK) {
 
110
                async_wait_for(req, NULL);
 
111
                async_serialize_end();
 
112
                return -1;
 
113
        }
 
114
        
 
115
        async_set_client_connection(conn);
 
116
        
 
117
        async_connect_to_me(phone, 0, 0, 0, NULL);
 
118
        async_wait_for(req, &retval);
 
119
        
 
120
        async_serialize_end();
 
121
        
 
122
        return retval;
 
123
}
 
124
 
 
125
static int devman_send_match_id(int phone, match_id_t *match_id)
 
126
{
 
127
        ipc_call_t answer;
 
128
 
 
129
        aid_t req = async_send_1(phone, DEVMAN_ADD_MATCH_ID, match_id->score,
 
130
            &answer);
 
131
        int retval = async_data_write_start(phone, match_id->id,
 
132
            str_size(match_id->id));
 
133
 
 
134
        async_wait_for(req, NULL);
 
135
        return retval;
 
136
}
 
137
 
 
138
 
 
139
static int devman_send_match_ids(int phone, match_id_list_t *match_ids)
 
140
{
 
141
        link_t *link = match_ids->ids.next;
 
142
        match_id_t *match_id = NULL;
 
143
        int ret = EOK;
 
144
 
 
145
        while (link != &match_ids->ids) {
 
146
                match_id = list_get_instance(link, match_id_t, link); 
 
147
                ret = devman_send_match_id(phone, match_id);
 
148
                if (ret != EOK) {
 
149
                        return ret;
 
150
                }
 
151
 
 
152
                link = link->next;
 
153
        }
 
154
 
 
155
        return ret;
 
156
}
 
157
 
 
158
/** Add function to a device.
 
159
 *
 
160
 * Request devman to add a new function to the specified device owned by
 
161
 * this driver task.
 
162
 *
 
163
 * @param name          Name of the new function
 
164
 * @param ftype         Function type, fun_inner or fun_exposed
 
165
 * @param match_ids     Match IDs (should be empty for fun_exposed)
 
166
 * @param devh          Devman handle of the device
 
167
 * @param funh          Place to store handle of the new function
 
168
 *
 
169
 * @return              EOK on success or negative error code.
 
170
 */
 
171
int devman_add_function(const char *name, fun_type_t ftype,
 
172
    match_id_list_t *match_ids, devman_handle_t devh, devman_handle_t *funh)
 
173
{
 
174
        int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING);
 
175
        int fun_handle;
 
176
        
 
177
        if (phone < 0)
 
178
                return phone;
 
179
        
 
180
        async_serialize_start();
 
181
        
 
182
        int match_count = list_count(&match_ids->ids);
 
183
        ipc_call_t answer;
 
184
 
 
185
        aid_t req = async_send_3(phone, DEVMAN_ADD_FUNCTION, (sysarg_t) ftype,
 
186
            devh, match_count, &answer);
 
187
 
 
188
        sysarg_t retval = async_data_write_start(phone, name, str_size(name));
 
189
        if (retval != EOK) {
 
190
                async_wait_for(req, NULL);
 
191
                async_serialize_end();
 
192
                return retval;
 
193
        }
 
194
        
 
195
        int match_ids_rc = devman_send_match_ids(phone, match_ids);
 
196
        
 
197
        async_wait_for(req, &retval);
 
198
        
 
199
        async_serialize_end();
 
200
        
 
201
        /* Prefer the answer to DEVMAN_ADD_FUNCTION in case of errors. */
 
202
        if ((match_ids_rc != EOK) && (retval == EOK)) {
 
203
                retval = match_ids_rc;
 
204
        }
 
205
 
 
206
        if (retval == EOK)
 
207
                fun_handle = (int) IPC_GET_ARG1(answer);
 
208
        else
 
209
                fun_handle = -1;
 
210
        
 
211
        *funh = fun_handle;
 
212
 
 
213
        return retval;
 
214
}
 
215
 
 
216
int devman_add_device_to_class(devman_handle_t devman_handle,
 
217
    const char *class_name)
 
218
{
 
219
        int phone = devman_get_phone(DEVMAN_DRIVER, IPC_FLAG_BLOCKING);
 
220
        
 
221
        if (phone < 0)
 
222
                return phone;
 
223
        
 
224
        async_serialize_start();
 
225
        ipc_call_t answer;
 
226
        aid_t req = async_send_1(phone, DEVMAN_ADD_DEVICE_TO_CLASS,
 
227
            devman_handle, &answer);
 
228
        
 
229
        sysarg_t retval = async_data_write_start(phone, class_name,
 
230
            str_size(class_name));
 
231
        if (retval != EOK) {
 
232
                async_wait_for(req, NULL);
 
233
                async_serialize_end();
 
234
                return retval;
 
235
        }
 
236
        
 
237
        async_wait_for(req, &retval);
 
238
        async_serialize_end();
 
239
        
 
240
        return retval;
 
241
}
 
242
 
 
243
void devman_hangup_phone(devman_interface_t iface)
 
244
{
 
245
        switch (iface) {
 
246
        case DEVMAN_DRIVER:
 
247
                if (devman_phone_driver >= 0) {
 
248
                        async_hangup(devman_phone_driver);
 
249
                        devman_phone_driver = -1;
 
250
                }
 
251
                break;
 
252
        case DEVMAN_CLIENT:
 
253
                if (devman_phone_client >= 0) {
 
254
                        async_hangup(devman_phone_client);
 
255
                        devman_phone_client = -1;
 
256
                }
 
257
                break;
 
258
        default:
 
259
                break;
 
260
        }
 
261
}
 
262
 
 
263
int devman_device_connect(devman_handle_t handle, unsigned int flags)
 
264
{
 
265
        int phone;
 
266
        
 
267
        if (flags & IPC_FLAG_BLOCKING) {
 
268
                phone = async_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAN,
 
269
                    DEVMAN_CONNECT_TO_DEVICE, handle);
 
270
        } else {
 
271
                phone = async_connect_me_to(PHONE_NS, SERVICE_DEVMAN,
 
272
                    DEVMAN_CONNECT_TO_DEVICE, handle);
 
273
        }
 
274
        
 
275
        return phone;
 
276
}
 
277
 
 
278
int devman_parent_device_connect(devman_handle_t handle, unsigned int flags)
 
279
{
 
280
        int phone;
 
281
        
 
282
        if (flags & IPC_FLAG_BLOCKING) {
 
283
                phone = async_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAN,
 
284
                    DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
 
285
        } else {
 
286
                phone = async_connect_me_to(PHONE_NS, SERVICE_DEVMAN,
 
287
                    DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
 
288
        }
 
289
        
 
290
        return phone;
 
291
}
 
292
 
 
293
int devman_device_get_handle(const char *pathname, devman_handle_t *handle,
 
294
    unsigned int flags)
 
295
{
 
296
        int phone = devman_get_phone(DEVMAN_CLIENT, flags);
 
297
        
 
298
        if (phone < 0)
 
299
                return phone;
 
300
        
 
301
        async_serialize_start();
 
302
        
 
303
        ipc_call_t answer;
 
304
        aid_t req = async_send_2(phone, DEVMAN_DEVICE_GET_HANDLE, flags, 0,
 
305
            &answer);
 
306
        
 
307
        sysarg_t retval = async_data_write_start(phone, pathname,
 
308
            str_size(pathname));
 
309
        if (retval != EOK) {
 
310
                async_wait_for(req, NULL);
 
311
                async_serialize_end();
 
312
                return retval;
 
313
        }
 
314
        
 
315
        async_wait_for(req, &retval);
 
316
        
 
317
        async_serialize_end();
 
318
        
 
319
        if (retval != EOK) {
 
320
                if (handle != NULL)
 
321
                        *handle = (devman_handle_t) -1;
 
322
                return retval;
 
323
        }
 
324
        
 
325
        if (handle != NULL)
 
326
                *handle = (devman_handle_t) IPC_GET_ARG1(answer);
 
327
        
 
328
        return retval;
 
329
}
 
330
 
 
331
int devman_device_get_handle_by_class(const char *classname,
 
332
    const char *devname, devman_handle_t *handle, unsigned int flags)
 
333
{
 
334
        int phone = devman_get_phone(DEVMAN_CLIENT, flags);
 
335
 
 
336
        if (phone < 0)
 
337
                return phone;
 
338
 
 
339
        async_serialize_start();
 
340
 
 
341
        ipc_call_t answer;
 
342
        aid_t req = async_send_1(phone, DEVMAN_DEVICE_GET_HANDLE_BY_CLASS,
 
343
            flags, &answer);
 
344
 
 
345
        sysarg_t retval = async_data_write_start(phone, classname,
 
346
            str_size(classname));
 
347
        if (retval != EOK) {
 
348
                async_wait_for(req, NULL);
 
349
                async_serialize_end();
 
350
                return retval;
 
351
        }
 
352
        retval = async_data_write_start(phone, devname,
 
353
            str_size(devname));
 
354
        if (retval != EOK) {
 
355
                async_wait_for(req, NULL);
 
356
                async_serialize_end();
 
357
                return retval;
 
358
        }
 
359
 
 
360
        async_wait_for(req, &retval);
 
361
 
 
362
        async_serialize_end();
 
363
 
 
364
        if (retval != EOK) {
 
365
                if (handle != NULL)
 
366
                        *handle = (devman_handle_t) -1;
 
367
                return retval;
 
368
        }
 
369
 
 
370
        if (handle != NULL)
 
371
                *handle = (devman_handle_t) IPC_GET_ARG1(answer);
 
372
 
 
373
        return retval;
 
374
}
 
375
 
 
376
 
 
377
/** @}
 
378
 */