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/callnr.h>
15 /* The order of the entries in the table determines the mapping between major
16 * device numbers and device drivers. Character and block devices
17 * can be intermixed at random. The ordering determines the device numbers in
18 * /dev. Note that the major device numbers used in /dev are NOT the same as
19 * the process numbers of the device drivers. See <minix/dmap.h> for mappings.
22 struct dmap dmap
[NR_DEVICES
];
24 /*===========================================================================*
26 *===========================================================================*/
27 void lock_dmap(struct dmap
*dp
)
30 struct worker_thread
*org_self
;
34 assert(dp
->dmap_driver
!= NONE
);
36 org_self
= worker_suspend();
38 if ((r
= mutex_lock(&dp
->dmap_lock
)) != 0)
39 panic("unable to get a lock on dmap: %d\n", r
);
41 worker_resume(org_self
);
44 /*===========================================================================*
46 *===========================================================================*/
47 void unlock_dmap(struct dmap
*dp
)
54 if ((r
= mutex_unlock(&dp
->dmap_lock
)) != 0)
55 panic("unable to unlock dmap lock: %d\n", r
);
58 /*===========================================================================*
60 *===========================================================================*/
61 static int map_driver(const char label
[LABEL_MAX
], devmajor_t major
,
64 /* Add a new device driver mapping in the dmap table. If the proc_nr is set to
65 * NONE, we're supposed to unmap it.
70 /* Get pointer to device entry in the dmap table. */
71 if (major
< 0 || major
>= NR_DEVICES
) return(ENODEV
);
74 /* Check if we're supposed to unmap it. */
75 if (proc_nr_e
== NONE
) {
76 /* Even when a driver is now unmapped and is shortly to be mapped in
77 * due to recovery, invalidate associated filps if they're character
78 * special files. More sophisticated recovery mechanisms which would
79 * reduce the need to invalidate files are possible, but would require
80 * cooperation of the driver and more recovery framework between RS,
83 invalidate_filp_by_char_major(major
);
84 dp
->dmap_driver
= NONE
;
90 if (len
+1 > sizeof(dp
->dmap_label
)) {
91 printf("VFS: map_driver: label too long: %zu\n", len
);
94 strlcpy(dp
->dmap_label
, label
, sizeof(dp
->dmap_label
));
97 /* Store driver I/O routines based on type of device */
98 dp
->dmap_driver
= proc_nr_e
;
103 /*===========================================================================*
105 *===========================================================================*/
106 int do_mapdriver(void)
108 /* Create a device->driver mapping. RS will tell us which major is driven by
109 * this driver, what type of device it is (regular, TTY, asynchronous, clone,
110 * etc), and its label. This label is registered with DS, and allows us to
111 * retrieve the driver's endpoint.
114 int r
, slot
, ndomains
;
119 char label
[LABEL_MAX
];
122 /* Only RS can map drivers. */
123 if (who_e
!= RS_PROC_NR
) return(EPERM
);
125 label_vir
= job_m_in
.m_lsys_vfs_mapdriver
.label
;
126 label_len
= job_m_in
.m_lsys_vfs_mapdriver
.labellen
;
127 major
= job_m_in
.m_lsys_vfs_mapdriver
.major
;
128 ndomains
= job_m_in
.m_lsys_vfs_mapdriver
.ndomains
;
129 domains
= job_m_in
.m_lsys_vfs_mapdriver
.domains
;
132 if (label_len
> sizeof(label
)) { /* Can we store this label? */
133 printf("VFS: do_mapdriver: label too long\n");
136 r
= sys_vircopy(who_e
, label_vir
, SELF
, (vir_bytes
) label
, label_len
,
139 printf("VFS: do_mapdriver: sys_vircopy failed: %d\n", r
);
142 if (label
[label_len
-1] != '\0') {
143 printf("VFS: do_mapdriver: label not null-terminated\n");
147 /* Now we know how the driver is called, fetch its endpoint */
148 r
= ds_retrieve_label_endpt(label
, &endpoint
);
150 printf("VFS: do_mapdriver: label '%s' unknown\n", label
);
154 /* Process is a service */
155 if (isokendpt(endpoint
, &slot
) != OK
) {
156 printf("VFS: can't map driver to unknown endpoint %d\n", endpoint
);
160 rfp
->fp_flags
|= FP_SRV_PROC
;
162 /* Try to update device mapping. */
163 if (major
!= NO_DEV
) {
164 if ((r
= map_driver(label
, major
, endpoint
)) != OK
)
168 if ((r
= smap_map(label
, endpoint
, domains
, ndomains
)) != OK
) {
170 map_driver(NULL
, major
, NONE
); /* undo */
177 /*===========================================================================*
178 * dmap_unmap_by_endpt *
179 *===========================================================================*/
180 void dmap_unmap_by_endpt(endpoint_t proc_e
)
182 /* Lookup driver in dmap table by endpoint and unmap it */
186 for (major
= 0; major
< NR_DEVICES
; major
++) {
187 if (dmap_driver_match(proc_e
, major
)) {
188 /* Found driver; overwrite it with a NULL entry */
189 if ((r
= map_driver(NULL
, major
, NONE
)) != OK
) {
190 printf("VFS: unmapping driver %d for major %d failed:"
191 " %d\n", proc_e
, major
, r
);
197 /*===========================================================================*
199 *===========================================================================*/
200 int map_service(struct rprocpub
*rpub
)
202 /* Map a new service by storing its device driver properties. */
206 if (IS_RPUB_BOOT_USR(rpub
)) return(OK
);
208 /* Process is a service */
209 if (isokendpt(rpub
->endpoint
, &slot
) != OK
) {
210 printf("VFS: can't map service with unknown endpoint %d\n",
215 rfp
->fp_flags
|= FP_SRV_PROC
;
217 /* Not a driver, nothing more to do. */
218 if (rpub
->dev_nr
== NO_DEV
) return(OK
);
221 r
= map_driver(rpub
->label
, rpub
->dev_nr
, rpub
->endpoint
);
222 if(r
!= OK
) return(r
);
227 /*===========================================================================*
229 *===========================================================================*/
232 /* Initialize the device mapping table. */
235 memset(dmap
, 0, sizeof(dmap
));
237 for (i
= 0; i
< NR_DEVICES
; i
++) {
238 dmap
[i
].dmap_driver
= NONE
;
239 dmap
[i
].dmap_servicing
= INVALID_THREAD
;
240 if (mutex_init(&dmap
[i
].dmap_lock
, NULL
) != 0)
241 panic("unable to initialize dmap lock");
244 /* CTTY_MAJOR is a special case, which is handled by VFS itself. */
245 if (map_driver("vfs", CTTY_MAJOR
, CTTY_ENDPT
) != OK
)
246 panic("map_driver(CTTY_MAJOR) failed");
249 /*===========================================================================*
250 * dmap_driver_match *
251 *===========================================================================*/
252 int dmap_driver_match(endpoint_t proc
, devmajor_t major
)
254 if (major
< 0 || major
>= NR_DEVICES
) return(0);
255 if (dmap
[major
].dmap_driver
!= NONE
&& dmap
[major
].dmap_driver
== proc
)
261 /*===========================================================================*
263 *===========================================================================*/
265 get_dmap_by_major(devmajor_t major
)
267 if (major
< 0 || major
>= NR_DEVICES
) return(NULL
);
268 if (dmap
[major
].dmap_driver
== NONE
) return(NULL
);
269 return(&dmap
[major
]);
272 /*===========================================================================*
274 *===========================================================================*/
275 void dmap_endpt_up(endpoint_t proc_e
, int is_blk
)
277 /* A device driver with endpoint proc_e has been restarted. Go tell everyone
278 * that might be blocking on it that this device is 'up'.
282 struct worker_thread
*worker
;
284 if (proc_e
== NONE
) return;
286 for (major
= 0; major
< NR_DEVICES
; major
++) {
287 if ((dp
= get_dmap_by_major(major
)) == NULL
) continue;
288 if (dp
->dmap_driver
== proc_e
) {
290 if (dp
->dmap_recovering
) {
291 printf("VFS: driver recovery failure for"
292 " major %d\n", major
);
293 if (dp
->dmap_servicing
!= INVALID_THREAD
) {
294 worker
= worker_get(dp
->dmap_servicing
);
297 dp
->dmap_recovering
= 0;
300 dp
->dmap_recovering
= 1;
302 dp
->dmap_recovering
= 0;
304 if (dp
->dmap_servicing
!= INVALID_THREAD
) {
305 worker
= worker_get(dp
->dmap_servicing
);
308 invalidate_filp_by_char_major(major
);
314 /*===========================================================================*
316 *===========================================================================*/
317 struct dmap
*get_dmap_by_endpt(endpoint_t proc_e
)
319 /* See if 'proc_e' endpoint belongs to a valid dmap entry. If so, return a
323 for (major
= 0; major
< NR_DEVICES
; major
++)
324 if (dmap_driver_match(proc_e
, major
))
325 return(&dmap
[major
]);