source: mainline/uspace/lib/libdrv/include/driver.h@ 08d9525a

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

add default handler for client requests which do not use any of the standard interfaces

  • Property mode set to 100644
File size: 7.9 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/** @addtogroup libdrv
30 * @{
31 */
32/** @file
33 */
34#ifndef LIBDRV_DRIVER_H_
35#define LIBDRV_DRIVER_H_
36
37
38#include <adt/list.h>
39#include <ipc/ipc.h>
40#include <ipc/devman.h>
41#include <ipc/dev_iface.h>
42#include <device/hw_res.h>
43#include <device/char.h>
44#include <assert.h>
45#include <ddi.h>
46#include <libarch/ddi.h>
47#include <fibril_synch.h>
48#include <malloc.h>
49
50struct device;
51typedef struct device device_t;
52
53// device interface
54
55// first two parameters: device and interface structure registered by the devices driver
56typedef void remote_iface_func_t(device_t*, void *, ipc_callid_t, ipc_call_t *);
57typedef remote_iface_func_t *remote_iface_func_ptr_t;
58typedef void remote_handler_t(device_t*, ipc_callid_t, ipc_call_t *);
59
60typedef struct {
61 size_t method_count;
62 remote_iface_func_ptr_t *methods;
63} remote_iface_t;
64
65typedef struct {
66 remote_iface_t * ifaces[DEV_IFACE_COUNT];
67} iface_dipatch_table_t;
68
69
70static inline bool is_valid_iface_idx(int idx)
71{
72 return 0 <= idx && idx < DEV_IFACE_MAX;
73}
74
75remote_iface_t* get_remote_iface(int idx);
76remote_iface_func_ptr_t get_remote_method(remote_iface_t *rem_iface, ipcarg_t iface_method_idx);
77
78
79// device class
80
81/** Devices belonging to the same class should implement the same set of interfaces.*/
82typedef struct device_class {
83 /** Unique identification of the class. */
84 int id;
85 /** Optional callback function called when a client is connecting to the device. */
86 int (*open)(device_t *dev);
87 /** Optional callback function called when a client is disconnecting from the device. */
88 void (*close)(device_t *dev);
89 /** The table of standard interfaces implemented by the device. */
90 void *interfaces[DEV_IFACE_COUNT];
91 /** The default handler of remote client requests. If the client's remote request cannot be handled
92 * by any of the standard interfaces, the default handler is used.*/
93 remote_handler_t *default_handler;
94} device_class_t;
95
96
97// device
98
99/** The device. */
100struct device {
101 /** Globally unique device identifier (assigned to the device by the device manager). */
102 device_handle_t handle;
103 /** The phone to the parent device driver (if it is different from this driver).*/
104 int parent_phone;
105 /** Parent device if handled by this driver, NULL otherwise. */
106 device_t *parent;
107 /** The device's name.*/
108 const char *name;
109 /** The list of device ids for device-to-driver matching.*/
110 match_id_list_t match_ids;
111 /** The device driver's data associated with this device.*/
112 void *driver_data;
113 /** Device class consist of class id and table of interfaces supported by the device.*/
114 device_class_t *class;
115 /** Pointer to the previous and next device in the list of devices handled by the driver */
116 link_t link;
117};
118
119
120// driver
121
122/** Generic device driver operations. */
123typedef struct driver_ops {
124 /** Callback method for passing a new device to the device driver.*/
125 int (*add_device)(device_t *dev);
126 // TODO add other generic driver operations
127} driver_ops_t;
128
129/** The driver structure.*/
130typedef struct driver {
131 /** The name of the device driver. */
132 const char *name;
133 /** Generic device driver operations. */
134 driver_ops_t *driver_ops;
135} driver_t;
136
137int driver_main(driver_t *drv);
138
139/** Create new device structure.
140 *
141 * @return the device structure.
142 */
143static inline device_t * create_device()
144{
145 device_t *dev = malloc(sizeof(device_t));
146 if (NULL != dev) {
147 memset(dev, 0, sizeof(device_t));
148 init_match_ids(&dev->match_ids);
149 }
150 return dev;
151}
152
153/** Delete device structure.
154 *
155 * @param dev the device structure.
156 */
157static inline void delete_device(device_t *dev)
158{
159 clean_match_ids(&dev->match_ids);
160 if (NULL != dev->name) {
161 free(dev->name);
162 }
163 free(dev);
164}
165
166static inline void * device_get_iface(device_t *dev, dev_inferface_idx_t idx)
167{
168 assert(is_valid_iface_idx(idx));
169 if (NULL == dev->class) {
170 return NULL;
171 }
172 return dev->class->interfaces[idx];
173}
174
175int child_device_register(device_t *child, device_t *parent);
176
177// interrupts
178
179typedef void interrupt_handler_t(device_t *dev, ipc_callid_t iid, ipc_call_t *icall);
180
181typedef struct interrupt_context {
182 int id;
183 device_t *dev;
184 int irq;
185 interrupt_handler_t *handler;
186 link_t link;
187} interrupt_context_t;
188
189typedef struct interrupt_context_list {
190 int curr_id;
191 link_t contexts;
192 fibril_mutex_t mutex;
193} interrupt_context_list_t;
194
195static inline interrupt_context_t * create_interrupt_context()
196{
197 interrupt_context_t *ctx = (interrupt_context_t *)malloc(sizeof(interrupt_context_t));
198 if (NULL != ctx) {
199 memset(ctx, 0, sizeof(interrupt_context_t));
200 }
201 return ctx;
202}
203
204static inline void delete_interrupt_context(interrupt_context_t *ctx)
205{
206 if (NULL != ctx) {
207 free(ctx);
208 }
209}
210
211static inline void init_interrupt_context_list(interrupt_context_list_t *list)
212{
213 memset(list, 0, sizeof(interrupt_context_list_t));
214 fibril_mutex_initialize(&list->mutex);
215 list_initialize(&list->contexts);
216}
217
218static inline void add_interrupt_context(interrupt_context_list_t *list, interrupt_context_t *ctx)
219{
220 fibril_mutex_lock(&list->mutex);
221
222 ctx->id = list->curr_id++;
223 list_append(&ctx->link, &list->contexts);
224
225 fibril_mutex_unlock(&list->mutex);
226}
227
228static inline void remove_interrupt_context(interrupt_context_list_t *list, interrupt_context_t *ctx)
229{
230 fibril_mutex_lock(&list->mutex);
231
232 list_remove(&ctx->link);
233
234 fibril_mutex_unlock(&list->mutex);
235}
236
237static inline interrupt_context_t *find_interrupt_context_by_id(interrupt_context_list_t *list, int id)
238{
239 fibril_mutex_lock(&list->mutex);
240 link_t *link = list->contexts.next;
241 interrupt_context_t *ctx;
242
243 while (link != &list->contexts) {
244 ctx = list_get_instance(link, interrupt_context_t, link);
245 if (id == ctx->id) {
246 fibril_mutex_unlock(&list->mutex);
247 return ctx;
248 }
249 link = link->next;
250 }
251 fibril_mutex_unlock(&list->mutex);
252 return NULL;
253}
254
255static inline interrupt_context_t *find_interrupt_context(interrupt_context_list_t *list, device_t *dev, int irq)
256{
257 fibril_mutex_lock(&list->mutex);
258 link_t *link = list->contexts.next;
259 interrupt_context_t *ctx;
260
261 while (link != &list->contexts) {
262 ctx = list_get_instance(link, interrupt_context_t, link);
263 if (irq == ctx->irq && dev == ctx->dev) {
264 fibril_mutex_unlock(&list->mutex);
265 return ctx;
266 }
267 link = link->next;
268 }
269 fibril_mutex_unlock(&list->mutex);
270 return NULL;
271}
272
273int register_interrupt_handler(device_t *dev, int irq, interrupt_handler_t *handler, irq_code_t *pseudocode);
274int unregister_interrupt_handler(device_t *dev, int irq);
275
276
277// default handler for client requests
278
279static inline remote_handler_t * device_get_default_handler(device_t *dev)
280{
281 if (NULL == dev->class) {
282 return NULL;
283 }
284
285 return dev->class->default_handler;
286}
287
288#endif
289
290/**
291 * @}
292 */
Note: See TracBrowser for help on using the repository browser.