1 /* This file contains the table with device <-> driver mappings. It also
2 * contains some routines to dynamically add and/ or remove device drivers
12 #include <minix/com.h>
18 /* The order of the entries in the table determines the mapping between major
19 * device numbers and device drivers. Character and block devices
20 * can be intermixed at random. The ordering determines the device numbers in
21 * /dev. Note that the major device numbers used in /dev are NOT the same as
22 * the process numbers of the device drivers. See <minix/dmap.h> for mappings.
25 struct dmap dmap
[NR_DEVICES
];
27 #define DT_EMPTY { no_dev, no_dev_io, NONE, "", 0, STYLE_NDEV, NULL, NONE, \
30 /*===========================================================================*
32 *===========================================================================*/
33 void lock_dmap(struct dmap
*dp
)
36 struct worker_thread
*org_self
;
41 assert(dp
->dmap_driver
!= NONE
);
46 if ((r
= mutex_lock(dp
->dmap_lock_ref
)) != 0)
47 panic("unable to get a lock on dmap: %d\n", r
);
53 /*===========================================================================*
55 *===========================================================================*/
56 void unlock_dmap(struct dmap
*dp
)
63 if ((r
= mutex_unlock(dp
->dmap_lock_ref
)) != 0)
64 panic("unable to unlock dmap lock: %d\n", r
);
67 /*===========================================================================*
69 *===========================================================================*/
72 /* Create a device->driver mapping. RS will tell us which major is driven by
73 * this driver, what type of device it is (regular, TTY, asynchronous, clone,
74 * etc), and its label. This label is registered with DS, and allows us to
75 * retrieve the driver's endpoint.
77 int r
, flags
, major
, style
, slot
;
81 char label
[LABEL_MAX
];
84 /* Only RS can map drivers. */
85 if (who_e
!= RS_PROC_NR
) return(EPERM
);
87 label_vir
= (vir_bytes
) job_m_in
.md_label
;
88 label_len
= (size_t) job_m_in
.md_label_len
;
89 major
= job_m_in
.md_major
;
90 flags
= job_m_in
.md_flags
;
91 style
= job_m_in
.md_style
;
94 if (label_len
+1 > sizeof(label
)) { /* Can we store this label? */
95 printf("VFS: do_mapdriver: label too long\n");
98 r
= sys_vircopy(who_e
, label_vir
, SELF
, (vir_bytes
) label
, label_len
);
100 printf("VFS: do_mapdriver: sys_vircopy failed: %d\n", r
);
103 label
[label_len
] = '\0'; /* Terminate label */
105 /* Now we know how the driver is called, fetch its endpoint */
106 r
= ds_retrieve_label_endpt(label
, &endpoint
);
108 printf("VFS: do_mapdriver: label '%s' unknown\n", label
);
112 /* Process is a service */
113 if (isokendpt(endpoint
, &slot
) != OK
) {
114 printf("VFS: can't map driver to unknown endpoint %d\n", endpoint
);
118 rfp
->fp_flags
|= FP_SRV_PROC
;
120 /* Try to update device mapping. */
121 return map_driver(label
, major
, endpoint
, style
, flags
);
124 /*===========================================================================*
126 *===========================================================================*/
127 int map_driver(label
, major
, proc_nr_e
, style
, flags
)
128 const char label
[LABEL_MAX
]; /* name of the driver */
129 int major
; /* major number of the device */
130 endpoint_t proc_nr_e
; /* process number of the driver */
131 int style
; /* style of the device */
132 int flags
; /* device flags */
134 /* Add a new device driver mapping in the dmap table. If the proc_nr is set to
135 * NONE, we're supposed to unmap it.
142 /* Get pointer to device entry in the dmap table. */
143 if (major
< 0 || major
>= NR_DEVICES
) return(ENODEV
);
146 /* Check if we're supposed to unmap it. */
147 if (proc_nr_e
== NONE
) {
148 /* Even when a driver is now unmapped and is shortly to be mapped in
149 * due to recovery, invalidate associated filps if they're character
150 * special files. More sophisticated recovery mechanisms which would
151 * reduce the need to invalidate files are possible, but would require
152 * cooperation of the driver and more recovery framework between RS,
155 invalidate_filp_by_char_major(major
);
156 dp
->dmap_opcl
= no_dev
;
157 dp
->dmap_io
= no_dev_io
;
158 dp
->dmap_driver
= NONE
;
159 dp
->dmap_flags
= flags
;
160 dp
->dmap_lock_ref
= &dp
->dmap_lock
;
164 /* Check process number of new driver if it was alive before mapping */
165 s
= isokendpt(proc_nr_e
, &slot
);
167 /* This is not a problem only when we force this driver mapping */
168 if (! (flags
& DRV_FORCED
))
174 if (len
+1 > sizeof(dp
->dmap_label
))
175 panic("VFS: map_driver: label too long: %d", len
);
176 strlcpy(dp
->dmap_label
, label
, LABEL_MAX
);
179 /* Store driver I/O routines based on type of device */
182 dp
->dmap_opcl
= gen_opcl
;
183 dp
->dmap_io
= gen_io
;
186 dp
->dmap_opcl
= gen_opcl
;
187 dp
->dmap_io
= asyn_io
;
190 dp
->dmap_opcl
= tty_opcl
;
191 dp
->dmap_io
= gen_io
;
194 dp
->dmap_opcl
= ctty_opcl
;
195 dp
->dmap_io
= ctty_io
;
198 dp
->dmap_opcl
= clone_opcl
;
199 dp
->dmap_io
= gen_io
;
202 dp
->dmap_opcl
= clone_opcl
;
203 dp
->dmap_io
= asyn_io
;
209 dp
->dmap_driver
= proc_nr_e
;
210 dp
->dmap_flags
= flags
;
211 dp
->dmap_style
= style
;
216 /*===========================================================================*
217 * dmap_unmap_by_endpt *
218 *===========================================================================*/
219 void dmap_unmap_by_endpt(endpoint_t proc_e
)
221 /* Lookup driver in dmap table by endpoint and unmap it */
224 for (major
= 0; major
< NR_DEVICES
; major
++) {
225 if (dmap_driver_match(proc_e
, major
)) {
226 /* Found driver; overwrite it with a NULL entry */
227 if ((r
= map_driver(NULL
, major
, NONE
, 0, 0)) != OK
) {
228 printf("VFS: unmapping driver %d for major %d failed:"
229 " %d\n", proc_e
, major
, r
);
235 /*===========================================================================*
237 *===========================================================================*/
238 int map_service(struct rprocpub
*rpub
)
240 /* Map a new service by storing its device driver properties. */
242 struct dmap
*fdp
, *sdp
;
245 /* Process is a service */
246 if (isokendpt(rpub
->endpoint
, &slot
) != OK
) {
247 printf("VFS: can't map service with unknown endpoint %d\n",
252 rfp
->fp_flags
|= FP_SRV_PROC
;
254 /* Not a driver, nothing more to do. */
255 if (rpub
->dev_nr
== NO_DEV
) return(OK
);
258 r
= map_driver(rpub
->label
, rpub
->dev_nr
, rpub
->endpoint
, rpub
->dev_style
,
260 if(r
!= OK
) return(r
);
262 /* If driver has two major numbers associated, also map the other one. */
263 if(rpub
->dev_style2
!= STYLE_NDEV
) {
264 r
= map_driver(rpub
->label
, rpub
->dev_nr
+1, rpub
->endpoint
,
265 rpub
->dev_style2
, rpub
->dev_flags
);
266 if(r
!= OK
) return(r
);
268 /* To ensure that future dmap lock attempts always lock the same driver
269 * regardless of major number, refer the second dmap lock reference
270 * to the first dmap entry.
272 fdp
= get_dmap_by_major(rpub
->dev_nr
);
273 sdp
= get_dmap_by_major(rpub
->dev_nr
+1);
277 sdp
->dmap_lock_ref
= &fdp
->dmap_lock
;
283 /*===========================================================================*
285 *===========================================================================*/
288 /* Initialize the table with empty device <-> driver mappings. */
290 struct dmap dmap_default
= DT_EMPTY
;
292 for (i
= 0; i
< NR_DEVICES
; i
++)
293 dmap
[i
] = dmap_default
;
296 /*===========================================================================*
298 *===========================================================================*/
299 void init_dmap_locks()
303 for (i
= 0; i
< NR_DEVICES
; i
++) {
304 if (mutex_init(&dmap
[i
].dmap_lock
, NULL
) != 0)
305 panic("unable to initialize dmap lock");
306 dmap
[i
].dmap_lock_ref
= &dmap
[i
].dmap_lock
;
310 /*===========================================================================*
311 * dmap_driver_match *
312 *===========================================================================*/
313 int dmap_driver_match(endpoint_t proc
, int major
)
315 if (major
< 0 || major
>= NR_DEVICES
) return(0);
316 if (dmap
[major
].dmap_driver
!= NONE
&& dmap
[major
].dmap_driver
== proc
)
322 /*===========================================================================*
324 *===========================================================================*/
326 get_dmap_by_major(int major
)
328 if (major
< 0 || major
>= NR_DEVICES
) return(NULL
);
329 if (dmap
[major
].dmap_driver
== NONE
) return(NULL
);
330 return(&dmap
[major
]);
333 /*===========================================================================*
335 *===========================================================================*/
336 void dmap_endpt_up(endpoint_t proc_e
, int is_blk
)
338 /* A device driver with endpoint proc_e has been restarted. Go tell everyone
339 * that might be blocking on it that this device is 'up'.
344 struct worker_thread
*worker
;
346 if (proc_e
== NONE
) return;
348 for (major
= 0; major
< NR_DEVICES
; major
++) {
349 if ((dp
= get_dmap_by_major(major
)) == NULL
) continue;
350 if (dp
->dmap_driver
== proc_e
) {
352 if (dp
->dmap_recovering
) {
353 printf("VFS: driver recovery failure for"
354 " major %d\n", major
);
355 if (dp
->dmap_servicing
!= NONE
) {
356 worker
= worker_get(dp
->dmap_servicing
);
359 dp
->dmap_recovering
= 0;
362 dp
->dmap_recovering
= 1;
364 dp
->dmap_recovering
= 0;
366 if (dp
->dmap_servicing
!= NONE
) {
367 worker
= worker_get(dp
->dmap_servicing
);
376 /*===========================================================================*
378 *===========================================================================*/
379 struct dmap
*get_dmap(endpoint_t proc_e
)
381 /* See if 'proc_e' endpoint belongs to a valid dmap entry. If so, return a
385 for (major
= 0; major
< NR_DEVICES
; major
++)
386 if (dmap_driver_match(proc_e
, major
))
387 return(&dmap
[major
]);