1 /* libbdev - driver endpoint management */
2
3 #include <minix/drivers.h>
4 #include <minix/bdev.h>
5 #include <minix/ds.h>
6 #include <assert.h>
7
8 #include "const.h"
9 #include "type.h"
10 #include "proto.h"
11
12 static struct {
13 endpoint_t endpt;
14 char label[DS_MAX_KEYLEN];
15 } driver_tab[NR_DEVICES];
16
bdev_driver_init(void)17 void bdev_driver_init(void)
18 {
19 /* Initialize the driver table.
20 */
21 int i;
22
23 for (i = 0; i < NR_DEVICES; i++) {
24 driver_tab[i].endpt = NONE;
25 driver_tab[i].label[0] = '\0';
26 }
27 }
28
bdev_driver_clear(dev_t dev)29 void bdev_driver_clear(dev_t dev)
30 {
31 /* Clear information about a driver.
32 */
33 int major;
34
35 major = major(dev);
36
37 assert(major >= 0 && major < NR_DEVICES);
38
39 driver_tab[major].endpt = NONE;
40 driver_tab[major].label[0] = '\0';
41 }
42
bdev_driver_set(dev_t dev,char * label)43 endpoint_t bdev_driver_set(dev_t dev, char *label)
44 {
45 /* Set the label for a driver, and retrieve the associated endpoint.
46 */
47 int major;
48
49 major = major(dev);
50
51 assert(major >= 0 && major < NR_DEVICES);
52 assert(strlen(label) < sizeof(driver_tab[major].label));
53
54 strlcpy(driver_tab[major].label, label, sizeof(driver_tab[major].label));
55
56 driver_tab[major].endpt = NONE;
57
58 return bdev_driver_update(dev);
59 }
60
bdev_driver_get(dev_t dev)61 endpoint_t bdev_driver_get(dev_t dev)
62 {
63 /* Return the endpoint for a driver, or NONE if we do not know its endpoint.
64 */
65 int major;
66
67 major = major(dev);
68
69 assert(major >= 0 && major < NR_DEVICES);
70
71 return driver_tab[major].endpt;
72 }
73
bdev_driver_update(dev_t dev)74 endpoint_t bdev_driver_update(dev_t dev)
75 {
76 /* Update the endpoint of a driver. The caller of this function already knows
77 * that the current endpoint may no longer be valid, and must be updated.
78 * Return the new endpoint upon success, and NONE otherwise.
79 */
80 endpoint_t endpt;
81 int r, major, nr_tries;
82
83 major = major(dev);
84
85 assert(major >= 0 && major < NR_DEVICES);
86 assert(driver_tab[major].label[0] != '\0');
87
88 /* Repeatedly retrieve the endpoint for the driver label, and see if it is a
89 * different, valid endpoint. If retrieval fails at first, we have to wait.
90 * We use polling, as opposed to a DS subscription, for a number of reasons:
91 * 1) DS supports only one subscription per process, and our main program may
92 * already have a subscription;
93 * 2) if we block on receiving a notification from DS, we cannot impose an
94 * upper bound on the retry time;
95 * 3) temporarily subscribing and then unsubscribing may cause leftover DS
96 * notifications, which the main program would then have to deal with.
97 * As of writing, unsubscribing from DS is not possible at all, anyway.
98 *
99 * In the normal case, the driver's label/endpoint mapping entry disappears
100 * completely for a short moment, before being replaced with the new mapping.
101 * Hence, failure to retrieve the entry at all does not constitute permanent
102 * failure. In fact, there is no way to determine reliably that a driver has
103 * failed permanently in the current approach. For this we simply rely on the
104 * retry limit.
105 */
106 for (nr_tries = 0; nr_tries < DS_NR_TRIES; nr_tries++) {
107 r = ds_retrieve_label_endpt(driver_tab[major].label, &endpt);
108
109 if (r == OK && endpt != NONE && endpt != driver_tab[major].endpt) {
110 driver_tab[major].endpt = endpt;
111
112 return endpt;
113 }
114
115 if (nr_tries < DS_NR_TRIES - 1)
116 micro_delay(DS_DELAY);
117 }
118
119 driver_tab[major].endpt = NONE;
120
121 return NONE;
122 }
123