blob: 4e1318871a8d9f7f6f329800d6394158e42f85dd [file] [log] [blame]
Pavel Herrmann732527c2012-08-08 01:42:18 +00001The U-Boot Driver Model Project
2===============================
3Driver cores API document
4=========================
5
6Pavel Herrmann <morpheus.ibis@gmail.com>
7
81) Overview
9-----------
10 Driver cores will be used as a wrapper for devices of the same type, and as
11 an abstraction for device driver APIs. For each driver API (which roughly
12 correspond to device types), there will be one driver core. Each driver core
13 will implement three APIs - a driver API (which will be the same as API of
14 drivers the core wraps around), a core API (which will be implemented by all
15 cores) and a command API (core-specific API which will be exposed to
16 commands).
17
18 A) Command API
19 The command API will provide access to shared functionality for a specific
20 device, which is currently located mostly in commands. Commands will be
21 rewritten to be more lightweight by using this API. As this API will be
22 different for each core, it is out of scope of this document.
23
24 B) Driver API
25 The driver API will act as a wrapper around actual device drivers,
26 providing a single entrypoint for device access. All functions in this API
27 have an instance* argument (probably called "this" or "i"), which will be
28 examined by the core, and a correct function for the specified driver will
29 get called.
30
31 If the core gets called with a group instance pointer (as discussed in
32 design), it will automatically select the instance that is associated
33 with this core, and use it as target of the call. if the group contains
34 multiple instances of a single type, the caller must explicitly use an
35 accessor to select the correct instance.
36
37 This accessor will look like:
38 struct instance *get_instance_from_group(struct instance *group, int i)
39
40 When called with a non-group instance, it will simply return the instance.
41
42 C) Core API
43 The core API will be implemented by all cores, and will provide
44 functionality for getting driver instances from non-driver code. This API
45 will consist of following functions:
46
47 int get_count(struct instance *core);
48 struct instance* get_instance(struct instance *core, int index);
49 int init(struct instance *core);
50 int bind(struct instance *core, struct instance *dev, void *ops,
51 void *hint);
52 int unbind(struct instance *core, instance *dev);
53 int replace(struct instance *core, struct_instance *new_dev,
54 struct instance *old_dev);
55 int destroy(struct instance *core);
56 int reloc(struct instance *new_core, struct instance *old_core);
57
58 The 'hint' parameter of bind() serves for additional data a driver can
59 pass to the core, to help it create the correct internal state for this
60 instance. the replace() function will get called during instance
61 relocation, and will replace the old instance with the new one, keeping
62 the internal state untouched.
63
64
652) Lifetime of a driver core
66----------------------------
67 Driver cores will be initialized at runtime, to limit memory footprint in
68 early-init stage, when we have to fit into ~1KB of memory. All active cores
69 will be stored in a tree structure (referenced as "Core tree") in global data,
70 which provides good tradeoff between size and access time.
71 Every core will have a number constant associated with it, which will be used
72 to find the instance in Core tree, and to refer to the core in all calls
73 working with the Core tree.
74 The Core Tree should be implemented using B-tree (or a similar structure)
75 to guarantee acceptable time overhead in all cases.
76
77 Code for working with the core (i2c in this example) follows:
78
79 core_init(CORE_I2C);
80 This will check whether we already have a i2c core, and if not it creates
81 a new instance and adds it into the Core tree. This will not be exported,
82 all code should depend on get_core_instance to init the core when
83 necessary.
84
85 get_core_instance(CORE_I2C);
86 This is an accessor into the Core tree, which will return the instance
87 of i2c core, creating it if necessary
88
89 core_bind(CORE_I2C, instance, driver_ops);
90 This will get called in bind() function of a driver, and will add the
91 instance into cores internal list of devices. If the core is not found, it
92 will get created.
93
94 driver_activate(instance *inst);
95 This call will recursively activate all devices necessary for using the
96 specified device. the code could be simplified as:
97 {
98 if (is_activated(inst))
99 return;
100 driver_activate(inst->bus);
101 get_driver(inst)->probe(inst);
102 }
103
104 The case with multiple parents will need to be handled here as well.
105 get_driver is an accessor to available drivers, which will get struct
106 driver based on a name in the instance.
107
108 i2c_write(instance *inst, ...);
109 An actual call to some method of the driver. This code will look like:
110 {
111 driver_activate(inst);
112 struct instance *core = get_core_instance(CORE_I2C);
113 device_ops = get_ops(inst);
114 device_ops->write(...);
115 }
116
117 get_ops will not be an exported function, it will be internal and specific
118 to the core, as it needs to know how are the ops stored, and what type
119 they are.
120
121 Please note that above examples represent the algorithm, not the actual code,
122 as they are missing checks for validity of return values.
123
124 core_init() function will get called the first time the core is requested,
125 either by core_link() or core_get_instance(). This way, the cores will get
126 created only when they are necessary, which will reduce our memory footprint.