source: mainline/uspace/lib/libdrv/generic/driver.c@ 9a66bc2e

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

several bugs fixed

  • Property mode set to 100644
File size: 8.6 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 printf("%s: driver_add_device\n", driver->name);
106
107 // TODO device state - the driver may detect the device is not actually present
108 // (old non PnP devices) or is not working properly.
109 // We should send such information to device manager.
110
111 ipcarg_t ret;
112 device_handle_t dev_handle = IPC_GET_ARG1(*icall);
113 device_t *dev = driver_create_device();
114 dev->handle = dev_handle;
115 add_to_devices_list(dev);
116 if (driver->driver_ops->add_device(dev)) {
117 printf("%s: new device with handle = %x was added.\n", driver->name, dev_handle);
118 ret = 1;
119 } else {
120 printf("%s: failed to add a new device with handle = %x.\n", driver->name, dev_handle);
121 remove_from_devices_list(dev);
122 // TODO delete device
123 ret = 0;
124 }
125 ipc_answer_1(iid, EOK, ret);
126}
127
128static void driver_connection_devman(ipc_callid_t iid, ipc_call_t *icall)
129{
130 printf("%s: driver_connection_devman \n", driver->name);
131
132 /* Accept connection */
133 ipc_answer_0(iid, EOK);
134
135 bool cont = true;
136 while (cont) {
137 ipc_call_t call;
138 ipc_callid_t callid = async_get_call(&call);
139
140 switch (IPC_GET_METHOD(call)) {
141 case IPC_M_PHONE_HUNGUP:
142 cont = false;
143 continue;
144 case DRIVER_ADD_DEVICE:
145 driver_add_device(callid, &call);
146 break;
147 default:
148 if (!(callid & IPC_CALLID_NOTIFICATION))
149 ipc_answer_0(callid, ENOENT);
150 }
151 }
152}
153
154/**
155 * Generic client connection handler both for applications and drivers.
156 *
157 * @param drv true for driver client, false for other clients (applications, services etc.).
158 */
159static void driver_connection_gen(ipc_callid_t iid, ipc_call_t *icall, bool drv)
160{
161 // Answer the first IPC_M_CONNECT_ME_TO call and remember the handle of the device to which the client connected.
162 device_handle_t handle = IPC_GET_ARG2(*icall);
163 device_t *dev = driver_get_device(&devices, handle);
164
165 if (dev == NULL) {
166 printf("%s: driver_connection_gen error - no device with handle %x was found.\n", driver->name, handle);
167 ipc_answer_0(iid, ENOENT);
168 return;
169 }
170
171
172 // TODO - if the client is not a driver, check whether it is allowed to use the device
173
174 // TODO open the device (introduce some callbacks for opening and closing devices registered by the driver)
175
176 printf("%s: driver_connection_gen: accepting connection.\n", driver->name);
177 ipc_answer_0(iid, EOK);
178
179 while (1) {
180 ipc_callid_t callid;
181 ipc_call_t call;
182
183 printf("%s: driver_connection_gen: waiting for call.\n", driver->name);
184 callid = async_get_call(&call);
185 ipcarg_t method = IPC_GET_METHOD(call);
186 switch (method) {
187 case IPC_M_PHONE_HUNGUP:
188
189 // TODO close the device
190
191 ipc_answer_0(callid, EOK);
192 return;
193 default:
194
195 if (!is_valid_iface_id(method)) {
196 // this is not device's interface
197 printf("%s: driver_connection_gen error - invalid interface id %x.", driver->name, method);
198 ipc_answer_0(callid, ENOTSUP);
199 break;
200 }
201
202 // calling one of the device's interfaces
203
204 // get the device interface structure
205 void *iface = device_get_iface(dev, method);
206 if (NULL == iface) {
207 printf("%s: driver_connection_gen error - ", driver->name);
208 printf("device with handle %x has no interface with id %x.\n", handle, method);
209 ipc_answer_0(callid, ENOTSUP);
210 break;
211 }
212
213 // get the corresponding interface for remote request handling ("remote interface")
214 remote_iface_t* rem_iface = get_remote_iface(method);
215 assert(NULL != rem_iface);
216
217 // get the method of the remote interface
218 ipcarg_t iface_method_idx = IPC_GET_ARG1(call);
219 remote_iface_func_ptr_t iface_method_ptr = get_remote_method(rem_iface, iface_method_idx);
220 if (NULL == iface_method_ptr) {
221 // the interface has not such method
222 printf("%s: driver_connection_gen error - invalid interface method.", driver->name);
223 ipc_answer_0(callid, ENOTSUP);
224 break;
225 }
226
227 // call the remote interface's method, which will receive parameters from the remote client
228 // and it will pass it to the corresponding local interface method associated with the device
229 // by its driver
230 (*iface_method_ptr)(dev, iface, callid, &call);
231 break;
232 }
233 }
234}
235
236static void driver_connection_driver(ipc_callid_t iid, ipc_call_t *icall)
237{
238 printf("%s: driver_connection_driver\n", driver->name);
239 driver_connection_gen(iid, icall, true);
240}
241
242static void driver_connection_client(ipc_callid_t iid, ipc_call_t *icall)
243{
244 printf("%s: driver_connection_client\n", driver->name);
245 driver_connection_gen(iid, icall, false);
246}
247
248
249/** Function for handling connections to device driver.
250 *
251 */
252static void driver_connection(ipc_callid_t iid, ipc_call_t *icall)
253{
254 /* Select interface */
255 switch ((ipcarg_t) (IPC_GET_ARG1(*icall))) {
256 case DRIVER_DEVMAN:
257 // handle PnP events from device manager
258 driver_connection_devman(iid, icall);
259 break;
260 case DRIVER_DRIVER:
261 // handle request from drivers of child devices
262 driver_connection_driver(iid, icall);
263 break;
264 case DRIVER_CLIENT:
265 // handle requests from client applications
266 driver_connection_client(iid, icall);
267 break;
268
269 default:
270 /* No such interface */
271 ipc_answer_0(iid, ENOENT);
272 }
273}
274
275bool child_device_register(device_t *child, device_t *parent)
276{
277 printf("%s: child_device_register\n", driver->name);
278
279 assert(NULL != child->name);
280
281 add_to_devices_list(child);
282 if (EOK == devman_child_device_register(child->name, &child->match_ids, parent->handle, &child->handle)) {
283 return true;
284 }
285 remove_from_devices_list(child);
286 return false;
287}
288
289int driver_main(driver_t *drv)
290{
291 // remember the driver structure - driver_ops will be called by generic handler for incoming connections
292 driver = drv;
293
294 // register driver by device manager with generic handler for incoming connections
295 devman_driver_register(driver->name, driver_connection);
296
297 async_manager();
298
299 // Never reached
300 return 0;
301}
302
303/**
304 * @}
305 */
Note: See TracBrowser for help on using the repository browser.