File:
[DragonFly] /
src /
sys /
kern /
kern_device.c
Revision
1.10:
download - view:
text,
annotated -
select for diffs
Thu May 13 23:49:23 2004 UTC (9 years ago) by
dillon
Branches:
MAIN
CVS tags:
HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).
d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device. It was never
used for that purpose.
d_clone will be more fully implemented as work continues. We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads. This is something we will be needing later
on.
1: /*
2: * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com> All rights reserved.
3: * cdevsw from kern/kern_conf.c Copyright (c) 1995 Terrence R. Lambert
4: * cdevsw from kern/kern_conf.c Copyright (c) 1995 Julian R. Elishcer,
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26: * SUCH DAMAGE.
27: *
28: * $DragonFly: src/sys/kern/kern_device.c,v 1.10 2004/05/13 23:49:23 dillon Exp $
29: */
30: #include <sys/param.h>
31: #include <sys/kernel.h>
32: #include <sys/sysctl.h>
33: #include <sys/systm.h>
34: #include <sys/module.h>
35: #include <sys/malloc.h>
36: #include <sys/conf.h>
37: #include <sys/vnode.h>
38: #include <sys/queue.h>
39: #include <sys/msgport.h>
40: #include <sys/device.h>
41: #include <machine/stdarg.h>
42: #include <sys/proc.h>
43: #include <sys/thread2.h>
44: #include <sys/msgport2.h>
45:
46: static struct cdevsw *cdevsw[NUMCDEVSW];
47: static struct lwkt_port *cdevport[NUMCDEVSW];
48:
49: static int cdevsw_putport(lwkt_port_t port, lwkt_msg_t msg);
50:
51: /*
52: * Initialize a message port to serve as the default message-handling port
53: * for device operations. This message port provides compatibility with
54: * traditional cdevsw dispatch functions by running them synchronously.
55: *
56: * YYY NOTE: ms_cmd can now hold a function pointer, should this code be
57: * converted from an integer op to a function pointer with a flag to
58: * indicate legacy operation?
59: */
60: static void
61: init_default_cdevsw_port(lwkt_port_t port)
62: {
63: lwkt_initport(port, NULL);
64: port->mp_putport = cdevsw_putport;
65: }
66:
67: static
68: int
69: cdevsw_putport(lwkt_port_t port, lwkt_msg_t lmsg)
70: {
71: cdevallmsg_t msg = (cdevallmsg_t)lmsg;
72: struct cdevsw *csw = msg->am_msg.csw;
73: int error;
74:
75: /*
76: * Run the device switch function synchronously in the context of the
77: * caller and return a synchronous error code (anything not EASYNC).
78: */
79: switch(msg->am_lmsg.ms_cmd.cm_op) {
80: case CDEV_CMD_OPEN:
81: error = csw->old_open(
82: msg->am_open.msg.dev,
83: msg->am_open.oflags,
84: msg->am_open.devtype,
85: msg->am_open.td);
86: break;
87: case CDEV_CMD_CLOSE:
88: error = csw->old_close(
89: msg->am_close.msg.dev,
90: msg->am_close.fflag,
91: msg->am_close.devtype,
92: msg->am_close.td);
93: break;
94: case CDEV_CMD_STRATEGY:
95: csw->old_strategy(msg->am_strategy.bp);
96: error = 0;
97: break;
98: case CDEV_CMD_IOCTL:
99: error = csw->old_ioctl(
100: msg->am_ioctl.msg.dev,
101: msg->am_ioctl.cmd,
102: msg->am_ioctl.data,
103: msg->am_ioctl.fflag,
104: msg->am_ioctl.td);
105: break;
106: case CDEV_CMD_DUMP:
107: error = csw->old_dump(msg->am_ioctl.msg.dev);
108: break;
109: case CDEV_CMD_PSIZE:
110: msg->am_psize.result = csw->old_psize(msg->am_psize.msg.dev);
111: error = 0; /* XXX */
112: break;
113: case CDEV_CMD_READ:
114: error = csw->old_read(
115: msg->am_read.msg.dev,
116: msg->am_read.uio,
117: msg->am_read.ioflag);
118: break;
119: case CDEV_CMD_WRITE:
120: error = csw->old_write(
121: msg->am_read.msg.dev,
122: msg->am_read.uio,
123: msg->am_read.ioflag);
124: break;
125: case CDEV_CMD_POLL:
126: msg->am_poll.events = csw->old_poll(
127: msg->am_poll.msg.dev,
128: msg->am_poll.events,
129: msg->am_poll.td);
130: error = 0;
131: break;
132: case CDEV_CMD_KQFILTER:
133: msg->am_kqfilter.result = csw->old_kqfilter(
134: msg->am_kqfilter.msg.dev,
135: msg->am_kqfilter.kn);
136: error = 0;
137: break;
138: case CDEV_CMD_MMAP:
139: msg->am_mmap.result = csw->old_mmap(
140: msg->am_mmap.msg.dev,
141: msg->am_mmap.offset,
142: msg->am_mmap.nprot);
143: error = 0; /* XXX */
144: break;
145: default:
146: error = ENOSYS;
147: break;
148: }
149: KKASSERT(error != EASYNC);
150: return(error);
151: }
152:
153: /*
154: * These device dispatch functions provide convenient entry points for
155: * any code wishing to make a dev call.
156: *
157: * YYY we ought to be able to optimize the port lookup by caching it in
158: * the dev_t structure itself.
159: */
160: static __inline
161: struct cdevsw *
162: _devsw(dev_t dev)
163: {
164: if (dev == NULL)
165: return(NULL);
166: if (dev->si_devsw)
167: return (dev->si_devsw);
168: return(cdevsw[major(dev)]);
169: }
170:
171: static __inline
172: lwkt_port_t
173: _init_cdevmsg(dev_t dev, cdevmsg_t msg, int cmd)
174: {
175: struct cdevsw *csw;
176:
177: lwkt_initmsg_simple(&msg->msg, cmd);
178: msg->dev = dev;
179: msg->csw = csw = _devsw(dev);
180: if (csw != NULL) { /* YYY too hackish */
181: KKASSERT(csw->d_port); /* YYY too hackish */
182: if (cdevport[major(dev)]) /* YYY too hackish */
183: return(cdevport[major(dev)]);
184: return(csw->d_port);
185: }
186: return(NULL);
187: }
188:
189: int
190: dev_dopen(dev_t dev, int oflags, int devtype, thread_t td)
191: {
192: struct cdevmsg_open msg;
193: lwkt_port_t port;
194:
195: port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_OPEN);
196: if (port == NULL)
197: return(ENXIO);
198: msg.oflags = oflags;
199: msg.devtype = devtype;
200: msg.td = td;
201: return(lwkt_domsg(port, &msg.msg.msg));
202: }
203:
204: int
205: dev_dclose(dev_t dev, int fflag, int devtype, thread_t td)
206: {
207: struct cdevmsg_close msg;
208: lwkt_port_t port;
209:
210: port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_CLOSE);
211: if (port == NULL)
212: return(ENXIO);
213: msg.fflag = fflag;
214: msg.devtype = devtype;
215: msg.td = td;
216: return(lwkt_domsg(port, &msg.msg.msg));
217: }
218:
219: void
220: dev_dstrategy(dev_t dev, struct buf *bp)
221: {
222: struct cdevmsg_strategy msg;
223: lwkt_port_t port;
224:
225: port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_STRATEGY);
226: KKASSERT(port); /* 'nostrategy' function is NULL YYY */
227: msg.bp = bp;
228: lwkt_domsg(port, &msg.msg.msg);
229: }
230:
231: int
232: dev_dioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, thread_t td)
233: {
234: struct cdevmsg_ioctl msg;
235: lwkt_port_t port;
236:
237: port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_IOCTL);
238: if (port == NULL)
239: return(ENXIO);
240: msg.cmd = cmd;
241: msg.data = data;
242: msg.fflag = fflag;
243: msg.td = td;
244: return(lwkt_domsg(port, &msg.msg.msg));
245: }
246:
247: int
248: dev_ddump(dev_t dev)
249: {
250: struct cdevmsg_dump msg;
251: lwkt_port_t port;
252:
253: port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_DUMP);
254: if (port == NULL)
255: return(ENXIO);
256: return(lwkt_domsg(port, &msg.msg.msg));
257: }
258:
259: int
260: dev_dpsize(dev_t dev)
261: {
262: struct cdevmsg_psize msg;
263: lwkt_port_t port;
264: int error;
265:
266: port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_PSIZE);
267: if (port == NULL)
268: return(-1);
269: error = lwkt_domsg(port, &msg.msg.msg);
270: if (error == 0)
271: return(msg.result);
272: return(-1);
273: }
274:
275: int
276: dev_dread(dev_t dev, struct uio *uio, int ioflag)
277: {
278: struct cdevmsg_read msg;
279: lwkt_port_t port;
280:
281: port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_READ);
282: if (port == NULL)
283: return(ENXIO);
284: msg.uio = uio;
285: msg.ioflag = ioflag;
286: return(lwkt_domsg(port, &msg.msg.msg));
287: }
288:
289: int
290: dev_dwrite(dev_t dev, struct uio *uio, int ioflag)
291: {
292: struct cdevmsg_write msg;
293: lwkt_port_t port;
294:
295: port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_WRITE);
296: if (port == NULL)
297: return(ENXIO);
298: msg.uio = uio;
299: msg.ioflag = ioflag;
300: return(lwkt_domsg(port, &msg.msg.msg));
301: }
302:
303: int
304: dev_dpoll(dev_t dev, int events, thread_t td)
305: {
306: struct cdevmsg_poll msg;
307: lwkt_port_t port;
308: int error;
309:
310: port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_POLL);
311: if (port == NULL)
312: return(ENXIO);
313: msg.events = events;
314: msg.td = td;
315: error = lwkt_domsg(port, &msg.msg.msg);
316: if (error == 0)
317: return(msg.events);
318: return(seltrue(dev, msg.events, td));
319: }
320:
321: int
322: dev_dkqfilter(dev_t dev, struct knote *kn)
323: {
324: struct cdevmsg_kqfilter msg;
325: lwkt_port_t port;
326: int error;
327:
328: port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_KQFILTER);
329: if (port == NULL)
330: return(ENXIO);
331: msg.kn = kn;
332: error = lwkt_domsg(port, &msg.msg.msg);
333: if (error == 0)
334: return(msg.result);
335: return(ENODEV);
336: }
337:
338: int
339: dev_dmmap(dev_t dev, vm_offset_t offset, int nprot)
340: {
341: struct cdevmsg_mmap msg;
342: lwkt_port_t port;
343: int error;
344:
345: port = _init_cdevmsg(dev, &msg.msg, CDEV_CMD_MMAP);
346: if (port == NULL)
347: return(-1);
348: msg.offset = offset;
349: msg.nprot = nprot;
350: error = lwkt_domsg(port, &msg.msg.msg);
351: if (error == 0)
352: return(msg.result);
353: return(-1);
354: }
355:
356: int
357: dev_port_dopen(lwkt_port_t port, dev_t dev, int oflags, int devtype, thread_t td)
358: {
359: struct cdevmsg_open msg;
360:
361: _init_cdevmsg(dev, &msg.msg, CDEV_CMD_OPEN);
362: if (port == NULL)
363: return(ENXIO);
364: msg.oflags = oflags;
365: msg.devtype = devtype;
366: msg.td = td;
367: return(lwkt_domsg(port, &msg.msg.msg));
368: }
369:
370: int
371: dev_port_dclose(lwkt_port_t port, dev_t dev, int fflag, int devtype, thread_t td)
372: {
373: struct cdevmsg_close msg;
374:
375: _init_cdevmsg(dev, &msg.msg, CDEV_CMD_CLOSE);
376: if (port == NULL)
377: return(ENXIO);
378: msg.fflag = fflag;
379: msg.devtype = devtype;
380: msg.td = td;
381: return(lwkt_domsg(port, &msg.msg.msg));
382: }
383:
384: void
385: dev_port_dstrategy(lwkt_port_t port, dev_t dev, struct buf *bp)
386: {
387: struct cdevmsg_strategy msg;
388:
389: _init_cdevmsg(dev, &msg.msg, CDEV_CMD_STRATEGY);
390: KKASSERT(port); /* 'nostrategy' function is NULL YYY */
391: msg.bp = bp;
392: lwkt_domsg(port, &msg.msg.msg);
393: }
394:
395: int
396: dev_port_dioctl(lwkt_port_t port, dev_t dev, u_long cmd, caddr_t data, int fflag, thread_t td)
397: {
398: struct cdevmsg_ioctl msg;
399:
400: _init_cdevmsg(dev, &msg.msg, CDEV_CMD_IOCTL);
401: if (port == NULL)
402: return(ENXIO);
403: msg.cmd = cmd;
404: msg.data = data;
405: msg.fflag = fflag;
406: msg.td = td;
407: return(lwkt_domsg(port, &msg.msg.msg));
408: }
409:
410: int
411: dev_port_ddump(lwkt_port_t port, dev_t dev)
412: {
413: struct cdevmsg_dump msg;
414:
415: _init_cdevmsg(dev, &msg.msg, CDEV_CMD_DUMP);
416: if (port == NULL)
417: return(ENXIO);
418: return(lwkt_domsg(port, &msg.msg.msg));
419: }
420:
421: int
422: dev_port_dpsize(lwkt_port_t port, dev_t dev)
423: {
424: struct cdevmsg_psize msg;
425: int error;
426:
427: _init_cdevmsg(dev, &msg.msg, CDEV_CMD_PSIZE);
428: if (port == NULL)
429: return(-1);
430: error = lwkt_domsg(port, &msg.msg.msg);
431: if (error == 0)
432: return(msg.result);
433: return(-1);
434: }
435:
436: int
437: dev_port_dread(lwkt_port_t port, dev_t dev, struct uio *uio, int ioflag)
438: {
439: struct cdevmsg_read msg;
440:
441: _init_cdevmsg(dev, &msg.msg, CDEV_CMD_READ);
442: if (port == NULL)
443: return(ENXIO);
444: msg.uio = uio;
445: msg.ioflag = ioflag;
446: return(lwkt_domsg(port, &msg.msg.msg));
447: }
448:
449: int
450: dev_port_dwrite(lwkt_port_t port, dev_t dev, struct uio *uio, int ioflag)
451: {
452: struct cdevmsg_write msg;
453:
454: _init_cdevmsg(dev, &msg.msg, CDEV_CMD_WRITE);
455: if (port == NULL)
456: return(ENXIO);
457: msg.uio = uio;
458: msg.ioflag = ioflag;
459: return(lwkt_domsg(port, &msg.msg.msg));
460: }
461:
462: int
463: dev_port_dpoll(lwkt_port_t port, dev_t dev, int events, thread_t td)
464: {
465: struct cdevmsg_poll msg;
466: int error;
467:
468: _init_cdevmsg(dev, &msg.msg, CDEV_CMD_POLL);
469: if (port == NULL)
470: return(ENXIO);
471: msg.events = events;
472: msg.td = td;
473: error = lwkt_domsg(port, &msg.msg.msg);
474: if (error == 0)
475: return(msg.events);
476: return(seltrue(dev, msg.events, td));
477: }
478:
479: int
480: dev_port_dkqfilter(lwkt_port_t port, dev_t dev, struct knote *kn)
481: {
482: struct cdevmsg_kqfilter msg;
483: int error;
484:
485: _init_cdevmsg(dev, &msg.msg, CDEV_CMD_KQFILTER);
486: if (port == NULL)
487: return(ENXIO);
488: msg.kn = kn;
489: error = lwkt_domsg(port, &msg.msg.msg);
490: if (error == 0)
491: return(msg.result);
492: return(ENODEV);
493: }
494:
495: int
496: dev_port_dmmap(lwkt_port_t port, dev_t dev, vm_offset_t offset, int nprot)
497: {
498: struct cdevmsg_mmap msg;
499: int error;
500:
501: _init_cdevmsg(dev, &msg.msg, CDEV_CMD_MMAP);
502: if (port == NULL)
503: return(-1);
504: msg.offset = offset;
505: msg.nprot = nprot;
506: error = lwkt_domsg(port, &msg.msg.msg);
507: if (error == 0)
508: return(msg.result);
509: return(-1);
510: }
511:
512: const char *
513: dev_dname(dev_t dev)
514: {
515: struct cdevsw *csw;
516:
517: if ((csw = _devsw(dev)) != NULL)
518: return(csw->d_name);
519: return(NULL);
520: }
521:
522: int
523: dev_dflags(dev_t dev)
524: {
525: struct cdevsw *csw;
526:
527: if ((csw = _devsw(dev)) != NULL)
528: return(csw->d_flags);
529: return(0);
530: }
531:
532: int
533: dev_dmaj(dev_t dev)
534: {
535: struct cdevsw *csw;
536:
537: if ((csw = _devsw(dev)) != NULL)
538: return(csw->d_maj);
539: return(0);
540: }
541:
542: lwkt_port_t
543: dev_dport(dev_t dev)
544: {
545: struct cdevsw *csw;
546:
547: if ((csw = _devsw(dev)) != NULL) {
548: if (cdevport[major(dev)]) /* YYY too hackish */
549: return(cdevport[major(dev)]);
550: return(csw->d_port);
551: }
552: return(NULL);
553: }
554:
555: #if 0
556: /*
557: * cdevsw[] array functions, moved from kern/kern_conf.c
558: */
559: struct cdevsw *
560: devsw(dev_t dev)
561: {
562: return(_devsw(dev));
563: }
564: #endif
565:
566: /*
567: * Convert a cdevsw template into the real thing, filling in fields the
568: * device left empty with appropriate defaults.
569: */
570: void
571: compile_devsw(struct cdevsw *devsw)
572: {
573: static lwkt_port devsw_compat_port;
574:
575: if (devsw_compat_port.mp_putport == NULL)
576: init_default_cdevsw_port(&devsw_compat_port);
577:
578: if (devsw->old_open == NULL)
579: devsw->old_open = noopen;
580: if (devsw->old_close == NULL)
581: devsw->old_close = noclose;
582: if (devsw->old_read == NULL)
583: devsw->old_read = noread;
584: if (devsw->old_write == NULL)
585: devsw->old_write = nowrite;
586: if (devsw->old_ioctl == NULL)
587: devsw->old_ioctl = noioctl;
588: if (devsw->old_poll == NULL)
589: devsw->old_poll = nopoll;
590: if (devsw->old_mmap == NULL)
591: devsw->old_mmap = nommap;
592: if (devsw->old_strategy == NULL)
593: devsw->old_strategy = nostrategy;
594: if (devsw->old_dump == NULL)
595: devsw->old_dump = nodump;
596: if (devsw->old_psize == NULL)
597: devsw->old_psize = nopsize;
598: if (devsw->old_kqfilter == NULL)
599: devsw->old_kqfilter = nokqfilter;
600:
601: if (devsw->d_port == NULL)
602: devsw->d_port = &devsw_compat_port;
603: }
604:
605: /*
606: * Add a cdevsw entry
607: */
608: int
609: cdevsw_add(struct cdevsw *newentry)
610: {
611: compile_devsw(newentry);
612: if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) {
613: printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
614: newentry->d_name, newentry->d_maj);
615: return (EINVAL);
616: }
617: if (cdevsw[newentry->d_maj]) {
618: printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n",
619: newentry->d_name, cdevsw[newentry->d_maj]->d_name);
620: }
621: cdevsw[newentry->d_maj] = newentry;
622: return (0);
623: }
624:
625: /*
626: * Add a cdevsw entry and override the port.
627: */
628: lwkt_port_t
629: cdevsw_add_override(struct cdevsw *newentry, lwkt_port_t port)
630: {
631: int error;
632:
633: if ((error = cdevsw_add(newentry)) == 0)
634: cdevport[newentry->d_maj] = port;
635: return(newentry->d_port);
636: }
637:
638: lwkt_port_t
639: cdevsw_dev_override(dev_t dev, lwkt_port_t port)
640: {
641: struct cdevsw *csw;
642:
643: KKASSERT(major(dev) >= 0 && major(dev) < NUMCDEVSW);
644: if ((csw = _devsw(dev)) != NULL) {
645: cdevport[major(dev)] = port;
646: return(csw->d_port);
647: }
648: return(NULL);
649: }
650:
651: /*
652: * Remove a cdevsw entry
653: */
654: int
655: cdevsw_remove(struct cdevsw *oldentry)
656: {
657: if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) {
658: printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
659: oldentry->d_name, oldentry->d_maj);
660: return EINVAL;
661: }
662: cdevsw[oldentry->d_maj] = NULL;
663: cdevport[oldentry->d_maj] = NULL;
664: return 0;
665: }
666: