source: mainline/uspace/lib/libdrv/generic/driver.c@ 2480e19

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2480e19 was 2480e19, checked in by Lenka Trochtova <trochtova.lenka@…>, 15 years ago

fixed some bugs

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/*
2 * Copyright (c) 2010 Lenka Trochtova
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
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
15 * derived from this software without specific prior written permission.
16 *
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
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
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
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
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/**
30 * @defgroup libdrv generic device driver support.
31 * @brief HelenOS generic device driver support.
32 * @{
33 */
34
35/** @file
36 */
37
38#include <assert.h>
39#include <ipc/services.h>
40#include <ipc/ns.h>
41#include <async.h>
42#include <stdio.h>
43#include <errno.h>
44#include <bool.h>
45#include <fibril_synch.h>
46#include <stdlib.h>
47#include <string.h>
48#include <ctype.h>
49#include <errno.h>
50
51#include <devman.h>
52#include <ipc/devman.h>
53#include <ipc/driver.h>
54
55#include "driver.h"
56
57static driver_t *driver;
58LIST_INITIALIZE(devices);
59FIBRIL_MUTEX_INITIALIZE(devices_mutex);
60
61static device_t * driver_create_device()
62{
63 device_t *dev = (device_t *)malloc(sizeof(device_t));
64 if (NULL != dev) {
65 memset(dev, 0, sizeof(device_t));
66 }
67 return dev;
68}
69
70static void add_to_devices_list(device_t *dev)
71{
72 fibril_mutex_lock(&devices_mutex);
73 list_append(&dev->link, &devices);
74 fibril_mutex_unlock(&devices_mutex);
75}
76
77static void remove_from_devices_list(device_t *dev)
78{
79 fibril_mutex_lock(&devices_mutex);
80 list_append(&dev->link, &devices);
81 fibril_mutex_unlock(&devices_mutex);
82}
83
84static device_t * driver_get_device(link_t *devices, device_handle_t handle)
85{
86 device_t *dev = NULL;
87
88 fibril_mutex_lock(&devices_mutex);
89 link_t *link = devices->next;
90 while (link != devices) {
91 dev = list_get_instance(link, device_t, link);
92 if (handle == dev->handle) {
93 fibril_mutex_unlock(&devices_mutex);
94 return dev;
95 }
96 link = link->next;
97 }
98 fibril_mutex_unlock(&devices_mutex);
99
100 return NULL;
101}
102
103static void driver_add_device(ipc_callid_t iid, ipc_call_t *icall)
104{
105 // TODO device state - the driver may detect the device is not actually present
106 // (old non PnP devices) or is not working properly.
107 // We should send such information to device manager.
108
109 ipcarg_t ret;
110 device_handle_t dev_handle = IPC_GET_ARG1(*icall);
111 device_t *dev = driver_create_device();
112 dev->handle = dev_handle;
113 add_to_devices_list(dev);
114 if (driver->driver_ops->add_device(dev)) {
115 printf("%s: new device with handle = %x was added.\n", driver->name, dev_handle);
116 ret = 1;
117 } else {
118 printf("%s: failed to add a new device with handle = %x.\n", driver->name, dev_handle);
119 remove_from_devices_list(dev);
120 // TODO delete device
121 ret = 0;
122 }
123 ipc_answer_1(iid, EOK, ret);
124}
125
126static void driver_connection_devman(ipc_callid_t iid, ipc_call_t *icall)
127{
128 /* Accept connection */
129 ipc_answer_0(iid, EOK);
130
131 bool cont = true;
132 while (cont) {
133 ipc_call_t call;
134 ipc_callid_t callid = async_get_call(&call);
135
136 switch (IPC_GET_METHOD(call)) {
137 case IPC_M_PHONE_HUNGUP:
138 cont = false;
139 continue;
140 case DRIVER_ADD_DEVICE:
141 driver_add_device(callid, &call);
142 break;
143 default:
144 if (!(callid & IPC_CALLID_NOTIFICATION))
145 ipc_answer_0(callid, ENOENT);
146 }
147 }
148}
149
150/**
151 * Generic client connection handler both for applications and drivers.
152 *
153 * @param drv true for driver client, false for other clients (applications, services etc.).
154 */
155static void driver_connection_gen(ipc_callid_t iid, ipc_call_t *icall, bool drv)
156{
157 // Answer the first IPC_M_CONNECT_ME_TO call and remember the handle of the device to which the client connected.
158 device_handle_t handle = IPC_GET_ARG2(*icall);
159 device_t *dev = driver_get_device(&devices, handle);
160
161 if (dev == NULL) {
162 printf("%s: driver_connection_gen error - no device with handle %x was found.\n", driver->name, handle);
163 ipc_answer_0(iid, ENOENT);
164 return;
165 }
166
167
168 // TODO - if the client is not a driver, check whether it is allowed to use the device
169
170 // TODO open the device (introduce some callbacks for opening and closing devices registered by the driver)
171
172 ipc_answer_0(iid, EOK);
173
174 while (1) {
175 ipc_callid_t callid;
176 ipc_call_t call;
177 callid = async_get_call(&call);
178 ipcarg_t method = IPC_GET_METHOD(call);
179 switch (method) {
180 case IPC_M_PHONE_HUNGUP:
181
182 // TODO close the device
183
184 ipc_answer_0(callid, EOK);
185 return;
186 default:
187
188 if (!is_valid_iface_id(method)) {
189 // this is not device's interface
190 printf("%s: driver_connection_gen error - invalid interface id %x.", driver->name, method);
191 ipc_answer_0(callid, ENOTSUP);
192 break;
193 }
194
195 // calling one of the device's interfaces
196
197 // get the device interface structure
198 void *iface = device_get_iface(dev, method);
199 if (NULL == iface) {
200 printf("%s: driver_connection_gen error - ", driver->name);
201 printf("device with handle %x has no interface with id %x.\n", handle, method);
202 ipc_answer_0(callid, ENOTSUP);
203 break;
204 }
205
206 // get the corresponding interface for remote request handling ("remote interface")
207 remote_iface_t* rem_iface = get_remote_iface(method);
208 assert(NULL != rem_iface);
209
210 // get the method of the remote interface
211 ipcarg_t iface_method_idx = IPC_GET_ARG1(call);
212 remote_iface_func_ptr_t iface_method_ptr = get_remote_method(rem_iface, iface_method_idx);
213 if (NULL == iface_method_ptr) {
214 // the interface has not such method
215 printf("%s: driver_connection_gen error - invalid interface method.", driver->name);
216 ipc_answer_0(callid, ENOTSUP);
217 break;
218 }
219
220 // call the remote interface's method, which will receive parameters from the remote client
221 // and it will pass it to the corresponding local interface method associated with the device
222 // by its driver
223 (*iface_method_ptr)(dev, iface, callid, &call);
224 break;
225 }
226 }
227}
228
229static void driver_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
230{
231 driver_connection_gen(iid, icall, true);
232}
233
234static void driver_connection_client(ipc_callid_t iid, ipc_call_t *icall)
235{
236 driver_connection_gen(iid, icall, false);
237}
238
239
240/** Function for handling connections to device driver.
241 *
242 */
243static void driver_connection(ipc_callid_t iid, ipc_call_t *icall)
244{
245 /* Select interface */
246 switch ((ipcarg_t) (IPC_GET_ARG1(*icall))) {
247 case DRIVER_DEVMAN:
248 // handle PnP events from device manager
249 driver_connection_devman(iid, icall);
250 break;
251 case DRIVER_DRIVER:
252 // handle request from drivers of child devices
253 driver_connection_driver(iid, icall);
254 break;
255 case DRIVER_CLIENT:
256 // handle requests from client applications
257 driver_connection_client(iid, icall);
258 break;
259
260 default:
261 /* No such interface */
262 ipc_answer_0(iid, ENOENT);
263 }
264}
265
266bool child_device_register(device_t *child, device_t *parent)
267{
268 // printf("%s: child_device_register\n", driver->name);
269
270 assert(NULL != child->name);
271
272 add_to_devices_list(child);
273 if (EOK == devman_child_device_register(child->name, &child->match_ids, parent->handle, &child->handle)) {
274 return true;
275 }
276 remove_from_devices_list(child);
277 return false;
278}
279
280int driver_main(driver_t *drv)
281{
282 // remember the driver structure - driver_ops will be called by generic handler for incoming connections
283 driver = drv;
284
285 // register driver by device manager with generic handler for incoming connections
286 devman_driver_register(driver->name, driver_connection);
287
288 async_manager();
289
290 // Never reached
291 return 0;
292}
293
294/**
295 * @}
296 */
Note: See TracBrowser for help on using the repository browser.