source: mainline/uspace/lib/drv/include/driver.h@ 0ca16307

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0ca16307 was 0ca16307, checked in by Vojtech Horky <vojtechhorky@…>, 15 years ago

Add wrapper for adding child device with single match id

The mentioned wrapper neatly wraps calls for creating new device, new match
id and registering such device at devman.

This call is now used in root driver.

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