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 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 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 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 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 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