123 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* libbdev - driver endpoint management */
 | |
| 
 | |
| #include <minix/drivers.h>
 | |
| #include <minix/bdev.h>
 | |
| #include <minix/ds.h>
 | |
| #include <assert.h>
 | |
| 
 | |
| #include "const.h"
 | |
| #include "type.h"
 | |
| #include "proto.h"
 | |
| 
 | |
| static struct {
 | |
|   endpoint_t endpt;
 | |
|   char label[DS_MAX_KEYLEN];
 | |
| } driver_tab[NR_DEVICES];
 | |
| 
 | |
| void bdev_driver_init(void)
 | |
| {
 | |
| /* Initialize the driver table.
 | |
|  */
 | |
|   int i;
 | |
| 
 | |
|   for (i = 0; i < NR_DEVICES; i++) {
 | |
| 	driver_tab[i].endpt = NONE;
 | |
| 	driver_tab[i].label[0] = '\0';
 | |
|   }
 | |
| }
 | |
| 
 | |
| void bdev_driver_clear(dev_t dev)
 | |
| {
 | |
| /* Clear information about a driver.
 | |
|  */
 | |
|   int major;
 | |
| 
 | |
|   major = major(dev);
 | |
| 
 | |
|   assert(major >= 0 && major < NR_DEVICES);
 | |
| 
 | |
|   driver_tab[major].endpt = NONE;
 | |
|   driver_tab[major].label[0] = '\0';
 | |
| }
 | |
| 
 | |
| endpoint_t bdev_driver_set(dev_t dev, char *label)
 | |
| {
 | |
| /* Set the label for a driver, and retrieve the associated endpoint.
 | |
|  */
 | |
|   int major;
 | |
| 
 | |
|   major = major(dev);
 | |
| 
 | |
|   assert(major >= 0 && major < NR_DEVICES);
 | |
|   assert(strlen(label) < sizeof(driver_tab[major].label));
 | |
| 
 | |
|   strlcpy(driver_tab[major].label, label, sizeof(driver_tab[major].label));
 | |
| 
 | |
|   driver_tab[major].endpt = NONE;
 | |
| 
 | |
|   return bdev_driver_update(dev);
 | |
| }
 | |
| 
 | |
| endpoint_t bdev_driver_get(dev_t dev)
 | |
| {
 | |
| /* Return the endpoint for a driver, or NONE if we do not know its endpoint.
 | |
|  */
 | |
|   int major;
 | |
| 
 | |
|   major = major(dev);
 | |
| 
 | |
|   assert(major >= 0 && major < NR_DEVICES);
 | |
| 
 | |
|   return driver_tab[major].endpt;
 | |
| }
 | |
| 
 | |
| endpoint_t bdev_driver_update(dev_t dev)
 | |
| {
 | |
| /* Update the endpoint of a driver. The caller of this function already knows
 | |
|  * that the current endpoint may no longer be valid, and must be updated.
 | |
|  * Return the new endpoint upon success, and NONE otherwise.
 | |
|  */
 | |
|   endpoint_t endpt;
 | |
|   int r, major, nr_tries;
 | |
| 
 | |
|   major = major(dev);
 | |
| 
 | |
|   assert(major >= 0 && major < NR_DEVICES);
 | |
|   assert(driver_tab[major].label[0] != '\0');
 | |
| 
 | |
|   /* Repeatedly retrieve the endpoint for the driver label, and see if it is a
 | |
|    * different, valid endpoint. If retrieval fails at first, we have to wait.
 | |
|    * We use polling, as opposed to a DS subscription, for a number of reasons:
 | |
|    * 1) DS supports only one subscription per process, and our main program may
 | |
|    *    already have a subscription;
 | |
|    * 2) if we block on receiving a notification from DS, we cannot impose an
 | |
|    *    upper bound on the retry time;
 | |
|    * 3) temporarily subscribing and then unsubscribing may cause leftover DS
 | |
|    *    notifications, which the main program would then have to deal with.
 | |
|    *    As of writing, unsubscribing from DS is not possible at all, anyway.
 | |
|    *
 | |
|    * In the normal case, the driver's label/endpoint mapping entry disappears
 | |
|    * completely for a short moment, before being replaced with the new mapping.
 | |
|    * Hence, failure to retrieve the entry at all does not constitute permanent
 | |
|    * failure. In fact, there is no way to determine reliably that a driver has
 | |
|    * failed permanently in the current approach. For this we simply rely on the
 | |
|    * retry limit.
 | |
|    */
 | |
|   for (nr_tries = 0; nr_tries < DS_NR_TRIES; nr_tries++) {
 | |
| 	r = ds_retrieve_label_endpt(driver_tab[major].label, &endpt);
 | |
| 
 | |
| 	if (r == OK && endpt != NONE && endpt != driver_tab[major].endpt) {
 | |
| 		driver_tab[major].endpt = endpt;
 | |
| 
 | |
| 		return endpt;
 | |
| 	}
 | |
| 
 | |
| 	if (nr_tries < DS_NR_TRIES - 1)
 | |
| 		micro_delay(DS_DELAY);
 | |
|   }
 | |
| 
 | |
|   driver_tab[major].endpt = NONE;
 | |
| 
 | |
|   return NONE;
 | |
| }
 | 
