|
|
1.1 root 1: /*
2: * Mach device server routines (oskit version).
3: *
4: * Mach Operating System
5: * Copyright (c) 1993,1991,1990,1989 Carnegie Mellon University
6: * All Rights Reserved.
7: *
8: * Permission to use, copy, modify and distribute this software and its
9: * documentation is hereby granted, provided that both the copyright
10: * notice and this permission notice appear in all copies of the
11: * software, derivative works or modified versions, and any portions
12: * thereof, and that both notices appear in supporting documentation.
13: *
14: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17: *
18: * Carnegie Mellon requests users of this software to return to
19: *
20: * Software Distribution Coordinator or [email protected]
21: * School of Computer Science
22: * Carnegie Mellon University
23: * Pittsburgh PA 15213-3890
24: *
25: * any improvements or extensions that they make and grant Carnegie Mellon
26: * the rights to redistribute these changes.
27: */
28:
29: #include "ds_oskit.h"
30: #include "device_error_reply.h"
31:
32: #include <mach/boolean.h>
33: #include <mach/kern_return.h>
34: #include <mach/mig_errors.h>
35: #include <mach/port.h>
36: #include <mach/notify.h>
37: #include <mach/time_value.h>
38:
39: #include <vm/vm_map.h>
40: #include <vm/vm_kern.h>
41: #include <vm/vm_page.h>
42: #include "pmap.h"
43:
44: #include <ipc/ipc_port.h>
45: #include <ipc/ipc_space.h>
46:
47: #include <oskit/dev/dev.h>
48: #include <oskit/error.h>
49: #include <oskit/unsupp/bus_walk.h>
50: #include <oskit/dev/bus.h>
51: #include <oskit/dev/blk.h>
52: #ifdef HAVE_OSKIT_DEV_STREAM_H
53: # include <oskit/dev/stream.h>
54: #endif
55: #include <oskit/dev/net.h>
56: #include <oskit/dev/linux.h>
57: #include <oskit/com/stream.h>
58: #include <oskit/c/stdlib.h>
59:
60: #include <oskit/machine/pc/direct_cons.h> /* XXX direct_cons_set_flags */
61:
62: #include <device/device_port.h>
63:
64: #include <string.h>
65:
66:
67: #define NDEVICES 256
68: #define DEVICE_IO_MAP_SIZE (4 * 1024 * 1024)
69:
70: zone_t dev_hdr_zone;
71: zone_t io_inband_zone; /* for inband reads */
72:
73: queue_head_t io_done_list;
74: decl_simple_lock_data(, io_done_list_lock)
75:
76: /* We maintain a hash table mapping COM oskit_device_t pointers to
77: open device ports (device_t). */
78:
79: #define NDEVHASH 7
80: #define DEV_PTR_HASH(com) ((natural_t) (com) % NDEVHASH)
81: queue_head_t dev_hash_table[NDEVHASH];
82:
83: /*
84: * Lock for device-number to device lookup.
85: * Must be held before device-ref_count lock.
86: */
87: decl_simple_lock_data(,dev_hash_lock)
88:
89: static void
90: dev_hash_enter (device_t device)
91: {
92: queue_enter (&dev_hash_table[DEV_PTR_HASH(device->com_device)],
93: device, device_t, hash_chain);
94: }
95:
96: static void
97: dev_hash_remove (device_t device)
98: {
99: queue_remove (&dev_hash_table[DEV_PTR_HASH(device->com_device)],
100: device, device_t, hash_chain);
101: }
102:
103:
104: static device_t
105: dev_hash_lookup (oskit_device_t *com_device, dev_mode_t mode)
106: {
107: queue_t q;
108: device_t device;
109:
110: q = &dev_hash_table[DEV_PTR_HASH (com_device)];
111: queue_iterate (q, device, device_t, hash_chain)
112: if (device->com_device == com_device && (mode &~ device->mode) == 0)
113: return device;
114:
115: return DEVICE_NULL;
116: }
117:
118: /*
119: * Add a reference to the device.
120: */
121: void
122: device_reference(device_t device)
123: {
124: simple_lock(&device->ref_lock);
125: device->ref_count++;
126: simple_unlock(&device->ref_lock);
127: }
128:
129: /*
130: * Remove a reference to the device, and deallocate the
131: * structure if no references are left.
132: */
133: void
134: device_deallocate (device_t device)
135: {
136: if (device == DEVICE_NULL)
137: return;
138:
139: simple_lock (&device->ref_lock);
140: if (device->ref_count > 1)
141: {
142: --device->ref_count;
143: simple_unlock (&device->ref_lock);
144: return;
145: }
146: simple_unlock (&device->ref_lock);
147:
148: if (device->com_device)
149: {
150: simple_lock(&dev_hash_lock);
151: simple_lock(&device->ref_lock);
152: if (--device->ref_count > 0)
153: {
154: simple_unlock (&device->ref_lock);
155: simple_unlock (&dev_hash_lock);
156: return;
157: }
158:
159: dev_hash_remove (device);
160: simple_unlock(&device->ref_lock);
161: simple_unlock(&dev_hash_lock);
162: }
163:
164: /* Destroy the port. */
165: ipc_kobject_set (device->port, IKO_NULL, IKOT_NONE);
166: ipc_port_dealloc_kernel (device->port);
167: device->port = IP_NULL;
168:
169: DEV_LOCK (device);
170: if (device->ops && device->ops->close)
171: (*device->ops->close) (device);
172: if (device->com_device) /* close hook might have cleared it */
173: oskit_device_release (device->com_device);
174: DEV_UNLOCK (device);
175:
176: zfree(dev_hdr_zone, (vm_offset_t)device);
177: }
178:
179: const struct device_ops no_device_ops;
180:
181: void ds_init()
182: {
183: vm_offset_t device_io_min, device_io_max;
184: unsigned int i;
185:
186: queue_init(&io_done_list);
187: simple_lock_init(&io_done_list_lock);
188:
189: device_io_map = kmem_suballoc(kernel_map,
190: &device_io_min,
191: &device_io_max,
192: DEVICE_IO_MAP_SIZE,
193: FALSE);
194: /*
195: * If the kernel receives many device_write requests, the
196: * device_io_map might run out of space. To prevent
197: * device_write_get from failing in this case, we enable
198: * wait_for_space on the map. This causes kmem_io_map_copyout
199: * to block until there is sufficient space.
200: * (XXX Large writes may be starved by small writes.)
201: *
202: * There is a potential deadlock problem with this solution,
203: * if a device_write from the default pager has to wait
204: * for the completion of a device_write which needs to wait
205: * for memory allocation. Hence, once device_write_get
206: * allocates space in device_io_map, no blocking memory
207: * allocations should happen until device_write_dealloc
208: * frees the space. (XXX A large write might starve
209: * a small write from the default pager.)
210: */
211: device_io_map->wait_for_space = TRUE;
212:
213: dev_hdr_zone = zinit(sizeof(struct device),
214: sizeof(struct device) * NDEVICES,
215: PAGE_SIZE,
216: FALSE,
217: "open device entry");
218:
219: io_inband_zone = zinit(sizeof(io_buf_ptr_inband_t),
220: 1000 * sizeof(io_buf_ptr_inband_t),
221: 10 * sizeof(io_buf_ptr_inband_t),
222: FALSE,
223: "io inband read buffers");
224:
225: simple_lock_init(&dev_hash_lock);
226: for (i = 0; i < NDEVHASH; i++)
227: queue_init(&dev_hash_table[i]);
228:
229: ds_osenv_init();
230: ds_request_init();
231:
232: DEV_LOCK_INIT;
233: }
234:
235:
236: boolean_t
237: ds_notify (mach_msg_header_t *msg)
238: {
239: if (msg->msgh_id == MACH_NOTIFY_NO_SENDERS)
240: {
241: device_t dev;
242: mach_no_senders_notification_t *ns;
243:
244: ns = (mach_no_senders_notification_t *) msg;
245: dev = dev_port_lookup ((ipc_port_t) ns->not_header.msgh_remote_port);
246: assert (dev);
247:
248: /* Extant send rights held one ref on the device object,
249: and we just got another one from dev_port_lookup. */
250: device_deallocate (dev);
251: device_deallocate (dev);
252:
253: return TRUE;
254: }
255:
256: printf ("ds_notify: strange notification %d\n", msg->msgh_id);
257: return FALSE;
258: }
259:
260:
261: ipc_port_t
262: convert_device_to_port (device_t device)
263: {
264: ipc_port_t port;
265:
266: if (! device)
267: return IP_NULL;
268: device_lock(device);
269: port = ipc_port_make_send(device->port);
270: device_unlock(device);
271: device_deallocate(device);
272: return port;
273: }
274:
275:
276: /*
277: * Lookup a device by its port.
278: * Doesn't consume the naked send right; produces a device reference.
279: */
280: device_t
281: dev_port_lookup(port)
282: ipc_port_t port;
283: {
284: register device_t device;
285:
286: if (!IP_VALID(port))
287: return (DEVICE_NULL);
288:
289: ip_lock(port);
290: if (ip_active(port) && (ip_kotype(port) == IKOT_DEVICE)) {
291: device = (device_t) port->ip_kobject;
292: device_reference(device);
293: }
294: else
295: device = DEVICE_NULL;
296:
297: ip_unlock(port);
298: return (device);
299: }
300:
301:
302: /*** Opening devices. ***/
303:
304:
305: device_t
306: dev_open_alloc (void)
307: {
308: device_t dev = (device_t) zalloc (dev_hdr_zone);
309: simple_lock_init(&dev->ref_lock);
310: dev->ref_count = 1;
311: simple_lock_init(&dev->lock);
312:
313: /*
314: * Allocate port, keeping a reference for it.
315: */
316: dev->port = ipc_port_alloc_kernel ();
317: if (dev->port == IP_NULL)
318: {
319: zfree (dev_hdr_zone, (vm_offset_t) dev);
320: return DEVICE_NULL;
321: }
322:
323: /* Associate the port with the device. */
324: ipc_kobject_set (dev->port, (ipc_kobject_t) dev, IKOT_DEVICE);
325:
326: return dev;
327: }
328:
329:
330: void
331: setup_no_senders (device_t dev)
332: {
333: ipc_port_t notify;
334:
335: /*
336: * Request no-senders notifications on device port.
337: * One ref in DEV->ref_count is held by the existence of send rights;
338: * the no-senders notification will release that ref.
339: */
340: notify = ipc_port_make_sonce(dev->port);
341: ip_lock(dev->port);
342: ipc_port_nsrequest(dev->port, 1, notify, ¬ify);
343: assert(notify == IP_NULL);
344:
345: device_reference (dev);
346: }
347:
348:
349: /* Given a COM device object and an i/o mode, produce an open device.
350: Always consumes a ref on COM_DEVICE. */
351: static io_return_t
352: dev_open_com (oskit_device_t *com_device, dev_mode_t mode, device_t *devp,
353: const char *diskpart)
354: {
355: device_t dev;
356: const struct device_ops *ops;
357:
358: /* First we look for an existing device port already open. */
359: lookup:
360: simple_lock (&dev_hash_lock);
361: dev = dev_hash_lookup (com_device, mode);
362: if (dev != DEVICE_NULL)
363: {
364: /* Acquire a reference on the device, as by device_reference.
365: We don't just call that because of the locking here. */
366: device_lock (dev);
367: ++dev->ref_count;
368: simple_unlock (&dev_hash_lock);
369:
370: DEV_LOCK (dev);
371: oskit_device_release (com_device); /* consume ref passed in */
372: DEV_UNLOCK (dev);
373: if (dev->ops == 0)
374: {
375: /* Somebody else is blocked in the oskit getting this device open.
376: We will block until they wake us up. */
377: dev->mode |= D_NODELAY; /* mark for opener */
378: thread_sleep ((event_t) dev, simple_lock_addr (dev->lock), TRUE);
379: /* Repeat the lookup in case DEV got killed in a failed open. */
380: goto lookup;
381: }
382: else
383: device_unlock (dev);
384:
385: goto got_device;
386: }
387: simple_unlock (&dev_hash_lock);
388:
389: /* Nope! We will need a new device port. */
390:
391: dev = dev_open_alloc ();
392: if (!dev)
393: return KERN_RESOURCE_SHORTAGE;
394:
395: dev->com_device = com_device;
396: dev->mode = mode;
397: dev->ops = 0;
398:
399: /* Put the device in the hash table under its COM device. We hold the
400: only reference to the device, and releasing that reference will remove
401: it from the hash table. While it's live, someone else might come
402: along and find it in the hash table and get their own reference to
403: keep it there. After this point we need to use device_lock. */
404: simple_lock (&dev_hash_lock);
405: dev_hash_enter (dev);
406: simple_unlock (&dev_hash_lock);
407:
408: /* Now we must open the oskit device, first determining which flavor it is.
409: */
410: {
411: oskit_bus_t *bus;
412: oskit_blkdev_t *blkdev;
413: oskit_netdev_t *netdev;
414: #ifdef oskit_streamdev_open
415: oskit_streamdev_t *streamdev;
416: #endif
417: oskit_error_t rc;
418: inline void asyncio_init (device_t dev)
419: {
420: dev->com.stream.listening = 0;
421: queue_init (&dev->com.stream.read_queue);
422: queue_init (&dev->com.stream.write_queue);
423: dev->com.stream.ready_queue.next = 0;
424: }
425:
426: if (oskit_device_query (com_device, &oskit_stream_iid,
427: (void **) &dev->com.stream.io) == 0)
428: {
429: /* Special case for minimal console stream, not really a device. */
430: if (oskit_stream_query (dev->com.stream.io, &oskit_asyncio_iid,
431: (void **) &dev->com.stream.aio) == 0)
432: {
433: asyncio_init (dev);
434: ops = &asyncio_device_ops;
435: }
436: else
437: ops = &stream_device_ops;
438: rc = 0;
439:
440: /* Kludge for kmsg. */
441: if ((void *) com_device == kmsg_stream && (mode & D_READ))
442: ++kmsg_readers;
443: }
444: else if (oskit_device_query (com_device, &oskit_bus_iid,
445: (void **) &bus) == 0)
446: {
447: if (mode & D_WRITE)
448: {
449: device_lock (dev);
450: mode = dev->mode & D_NODELAY;
451: device_unlock (dev);
452: if (mode & D_NODELAY)
453: /* Someone was waiting for us to finish opening. */
454: thread_wakeup ((event_t)dev);
455: device_deallocate (dev);
456: return D_READ_ONLY;
457: }
458: ops = &bus_device_ops;
459: rc = populate_bus (dev, bus);
460: oskit_bus_release (bus);
461: }
462: else if (oskit_device_query (com_device, &oskit_blkdev_iid,
463: (void **) &blkdev) == 0)
464: {
465: ops = &block_device_ops;
466: rc = oskit_blkdev_open (blkdev,
467: ((mode & D_READ) ? OSKIT_DEV_OPEN_READ : 0) |
468: ((mode & D_WRITE) ? OSKIT_DEV_OPEN_WRITE : 0),
469: &dev->com.blk.io);
470: oskit_blkdev_release (blkdev);
471: if (OSKIT_SUCCEEDED (rc))
472: dev->com.blk.size = oskit_blkio_getblocksize (dev->com.blk.io);
473: dev->com.blk.parts = 0;
474: }
475: else if (oskit_device_query (com_device, &oskit_netdev_iid,
476: (void **) &netdev) == 0)
477: {
478: ops = &net_device_ops;
479: rc = ds_netdev_open (dev, netdev);
480: }
481: #ifdef oskit_streamdev_open
482: else if (oskit_device_query (com_device, &oskit_streamdev_iid,
483: (void **) &streamdev) == 0)
484: {
485: rc = oskit_streamdev_open (streamdev,
486: ((mode & D_READ) ? OSKIT_DEV_OPEN_READ : 0)
487: | ((mode & D_WRITE)
488: ? OSKIT_DEV_OPEN_WRITE : 0),
489: &dev->com.stream.io);
490: oskit_streamdev_release (streamdev);
491: if (OSKIT_SUCCEEDED (rc))
492: {
493: if (oskit_stream_query (dev->com.stream.io, &oskit_asyncio_iid,
494: (void **) &dev->com.stream.aio) == 0)
495: {
496: asyncio_init (dev);
497: ops = &asyncio_device_ops;
498: }
499: else
500: ops = &stream_device_ops;
501: }
502: }
503: #endif
504:
505: if (OSKIT_FAILED (rc))
506: {
507: if (dev->mode & D_NODELAY)
508: /* Someone was waiting for us to finish opening. */
509: thread_wakeup ((event_t)dev);
510: device_deallocate (dev);
511: return oskit_to_mach_error (rc);
512: }
513: }
514:
515: device_lock (dev);
516: dev->ops = ops;
517: mode = dev->mode & D_NODELAY;
518: dev->mode &= ~D_NODELAY;
519: device_unlock (dev);
520: if (mode)
521: /* Someone was waiting for us to finish opening. */
522: thread_wakeup ((event_t)dev);
523:
524: setup_no_senders (dev);
525:
526: /* Return the open device. */
527:
528: got_device:
529:
530: if (diskpart)
531: {
532: diskpart_t *part;
533: device_t subdev;
534:
535: /* Kludge for partitioning. */
536: if (dev->ops != &block_device_ops)
537: {
538: device_deallocate (dev);
539: return D_NO_SUCH_DEVICE;
540: }
541:
542: device_lock (dev);
543: if (dev->com.blk.parts == 0)
544: {
545: diskpart_t *parts = (void *) kalloc (MAX_PARTS * sizeof *parts);
546: int n = diskpart_blkio_get_partition (dev->com.blk.io,
547: parts, MAX_PARTS);
548: if (n <= 0)
549: {
550: device_unlock (dev);
551: kfree ((vm_offset_t) parts, MAX_PARTS * sizeof *parts);
552: device_deallocate (dev);
553: return D_NO_SUCH_DEVICE;
554: }
555: dev->com.blk.parts = parts;
556: }
557: device_unlock (dev);
558:
559: part = diskpart_lookup_bsd_string (dev->com.blk.parts, diskpart);
560: if (part == 0)
561: {
562: device_deallocate (dev);
563: return D_NO_SUCH_DEVICE;
564: }
565:
566: /* Now we have the pointer to the partition we want. For partition
567: pseudo-devices, we use this pointer in lieu of the COM object
568: pointer as the key in the device hash table. */
569: simple_lock (&dev_hash_lock);
570: subdev = dev_hash_lookup ((void *) part, mode);
571: if (subdev != DEVICE_NULL)
572: {
573: device_lock (subdev);
574: ++subdev->ref_count;
575: simple_unlock (&dev_hash_lock);
576:
577: device_deallocate (dev);
578: dev = subdev;
579: }
580: else
581: {
582: simple_unlock (&dev_hash_lock);
583:
584: subdev = dev_open_alloc ();
585: if (!subdev)
586: {
587: device_deallocate (dev);
588: return KERN_RESOURCE_SHORTAGE;
589: }
590:
591: mode = dev->mode;
592: subdev->com.blkpart.blk = dev; /* consumes our ref */
593: subdev->com.blkpart.part = part;
594: dev = subdev;
595:
596: dev->com_device = (void *) part;
597: dev->mode = mode;
598: dev->ops = &block_partition_device_ops;
599:
600: simple_lock (&dev_hash_lock);
601: dev_hash_enter (dev);
602: simple_unlock (&dev_hash_lock);
603:
604: setup_no_senders (dev);
605: }
606: }
607:
608: *devp = dev; /* Caller consumes the reference. */
609: return D_SUCCESS;
610: }
611:
612: /* Create a special pseudo-device that maps contiguous physical memory
613: starting with the physical memory backing the wired kernel virtual
614: address KVA. See ds_mem.c for the device ops. */
615: static io_return_t
616: special_mem_device (device_t *loc,
617: dev_mode_t mode,
618: vm_offset_t kva, vm_size_t size, vm_size_t recsize,
619: device_t *out_dev)
620: {
621: if (*loc == DEVICE_NULL)
622: {
623: device_t dev = dev_open_alloc ();
624: if (dev == DEVICE_NULL)
625: return KERN_RESOURCE_SHORTAGE;
626: dev->mode = mode & (D_READ|D_WRITE);
627: dev->com_device = 0;
628: dev->com.mem.pa = pmap_extract (kernel_pmap, kva);
629: dev->com.mem.size = size;
630: dev->com.mem.recsize = recsize;
631: dev->ops = &mem_device_ops;
632: *loc = dev;
633:
634: /* The *LOC value (in a global variable) holds a reference that
635: is never released. */
636: }
637:
638: device_reference (*loc); /* This reference is consumed by the caller. */
639: *out_dev = *loc;
640: return D_SUCCESS;
641: }
642:
643:
644: io_return_t
645: ds_device_open (ipc_port_t open_port, ipc_port_t reply_port,
646: mach_msg_type_name_t reply_port_type, dev_mode_t mode,
647: char *name, device_t *devp)
648: {
649: char constructed[200];
650: oskit_error_t rc;
651: oskit_device_t *com_device;
652: const char *subpart = 0;
653:
654: /* Open must be called on the master device port. */
655: if (open_port != master_device_port)
656: INVALOP;
657:
658: /* There must be a reply port. */
659: if (! IP_VALID (reply_port))
660: return MIG_NO_REPLY;
661:
662: if (name[0] == '@') /* Bus tree location. */
663: {
664: rc = oskit_bus_walk_lookup (name, &com_device, &subpart);
665: if (OSKIT_FAILED (rc))
666: return oskit_to_mach_error (rc);
667: }
668: else if (!strcmp (name, "console")) /* Special case. */
669: {
670: com_device = (oskit_device_t *) ds_console_stream; /* not a device */
671: oskit_device_addref (com_device);
672:
673: /* Kludge. We don't do this at bootup so that the printing of any
674: kernel lossage or panics will be easier to read. But we need it
675: set for real use of the console device. It's harmless to call
676: this more than once, since it just sets a variable. */
677: direct_cons_set_flags (DC_NO_ONLCR);
678: }
679: else if (!strcmp (name, "kmsg")) /* Special case. */
680: {
681: com_device = (oskit_device_t *) kmsg_stream; /* not a device */
682: oskit_device_addref (com_device);
683: }
684: else if (!strcmp (name, "time")) /* Special case. */
685: {
686: extern time_value_t *mtime;
687: static device_t mapped_time_device;
688: if (mode & D_WRITE) /* No writing of "time" device allowed; */
689: return D_READ_ONLY; /* users must do host_set_time instead. */
690: return special_mem_device (&mapped_time_device, D_READ,
691: (vm_offset_t) mtime,
692: sizeof *mtime, sizeof mtime->seconds,
693: devp);
694: }
695: else if (!strcmp (name, "mem")) /* Special case. */
696: {
697: static device_t phys_mem_device;
698: return special_mem_device (&phys_mem_device, mode,
699: phystokv (0), ~(vm_offset_t)0, 1,
700: devp);
701: }
702: else if (bus_walk_from_compat_string (name, constructed)) /* compat hack */
703: {
704: /* The name was recognized as a compatibility syntax, and CONSTRUCTED
705: now contains a name in bus walk syntax (starting with an '@'). */
706: rc = oskit_bus_walk_lookup (constructed, &com_device, &subpart);
707: if (OSKIT_FAILED (rc))
708: return oskit_to_mach_error (rc);
709: }
710: else /* I got no clue. */
711: return D_NO_SUCH_DEVICE;
712:
713: return dev_open_com (com_device, mode & (D_READ | D_WRITE), devp, subpart);
714: }
715:
716: io_return_t
717: ds_device_close (device_t dev)
718: {
719: if (dev == DEVICE_NULL)
720: return D_NO_SUCH_DEVICE;
721:
722: /* The device_close RPC never does anything.
723: The device gets closed when the last send right to its port dies. */
724:
725: return D_SUCCESS;
726: }
727:
728:
729:
730: /* Server functions for RPCs to open devices.
731:
732: Note: These functions expect a migworthy return value from the dev->ops
733: functions, i.e. MIG_NO_REPLY and not D_IO_QUEUED.
734: */
735:
736: io_return_t
737: ds_device_write (device_t dev, ipc_port_t reply_port,
738: mach_msg_type_name_t reply_port_type, dev_mode_t mode,
739: recnum_t recnum, io_buf_ptr_t data,
740: mach_msg_type_number_t count,
741: int *bytes_written)
742: {
743: if (dev == DEVICE_NULL)
744: return D_NO_SUCH_DEVICE;
745: if (!(dev->mode & D_WRITE))
746: INVALOP;
747: if (! data)
748: INVALSZ;
749: if (! dev->ops->write)
750: {
751: if (!dev->ops->write_inband)
752: return D_READ_ONLY;
753: else
754: {
755: /*
756: * Copy out-of-line data into kernel address space.
757: * Since data is copied as page list, it will be
758: * accessible.
759: */
760: vm_offset_t addr;
761: kern_return_t kr = vm_map_copyout (device_io_map, &addr,
762: (vm_map_copy_t) data);
763: if (kr != KERN_SUCCESS)
764: return kr;
765:
766: /* Note: we assume that write_inband can take a large count. */
767: kr = (*dev->ops->write_inband) (dev, reply_port,
768: reply_port_type, mode, recnum,
769: (char *) addr, count,
770: bytes_written);
771: (void) vm_deallocate (device_io_map, addr, count);
772: if (kr == KERN_SUCCESS || kr == MIG_NO_REPLY)
773: return kr;
774: /* We don't want to return an error to our caller, because it
775: will respond to that by destroying the message body--but we
776: have already consumed DATA, and destroying it would be bad. */
777: if (IP_VALID (reply_port))
778: ds_device_write_error_reply (reply_port, reply_port_type, kr);
779: return MIG_NO_REPLY;
780: }
781: }
782: return (*dev->ops->write) (dev, reply_port,
783: reply_port_type, mode, recnum,
784: data, count, bytes_written);
785: }
786:
787: io_return_t
788: ds_device_write_inband (device_t dev, ipc_port_t reply_port,
789: mach_msg_type_name_t reply_port_type,
790: dev_mode_t mode, recnum_t recnum,
791: io_buf_ptr_inband_t data, unsigned count,
792: int *bytes_written)
793: {
794: if (dev == DEVICE_NULL)
795: return D_NO_SUCH_DEVICE;
796: if (!(dev->mode & D_WRITE))
797: INVALOP;
798: if (! data)
799: INVALSZ;
800: assert (count <= IO_INBAND_MAX);
801: if (! dev->ops->write_inband)
802: {
803: if (! dev->ops->write)
804: INVALOP;
805: else
806: {
807: vm_offset_t addr;
808: kern_return_t kr;
809: vm_map_copy_t copy;
810:
811: assert (IO_INBAND_MAX <= PAGE_SIZE);
812: kr = kmem_alloc (kernel_map, &addr, PAGE_SIZE);
813: if (kr != KERN_SUCCESS)
814: return kr;
815:
816: memcpy ((char *) addr, data, count);
817: kr = vm_map_copyin_page_list (kernel_map, addr, PAGE_SIZE,
818: TRUE, TRUE, ©, FALSE);
819: assert (kr == KERN_SUCCESS);
820:
821: kr = (*dev->ops->write) (dev, reply_port,
822: reply_port_type, mode, recnum,
823: (char *) copy, count, bytes_written);
824: if (kr != D_SUCCESS)
825: vm_map_copy_discard (copy);
826: return kr;
827: }
828: }
829: return (*dev->ops->write_inband) (dev, reply_port,
830: reply_port_type, mode, recnum,
831: data, count, bytes_written);
832: }
833:
834: io_return_t
835: ds_device_read (device_t dev, ipc_port_t reply_port,
836: mach_msg_type_name_t reply_port_type, dev_mode_t mode,
837: recnum_t recnum, int count, io_buf_ptr_t *data,
838: unsigned *bytes_read)
839: {
840: io_return_t err;
841:
842: /* There must be a reply port. */
843: if (! IP_VALID (reply_port))
844: return MIG_NO_REPLY;
845: if (dev == DEVICE_NULL)
846: return D_NO_SUCH_DEVICE;
847: if (!(dev->mode & D_READ))
848: INVALOP;
849:
850: err = (dev->ops->read ? (*dev->ops->read) (dev, reply_port,
851: reply_port_type, mode, recnum,
852: count, data, bytes_read)
853: : D_INVALID_OPERATION);
854:
855: /* The ops->read function can return D_INVALID_OPERATION to tell us that
856: it doesn't want to deal with making a copy object for this read. We
857: fall back to the generic code below using the inband read function. */
858: if (err != D_INVALID_OPERATION)
859: return err;
860:
861: if (! dev->ops->read_inband)
862: INVALOP;
863: else
864: {
865: vm_offset_t addr;
866: vm_size_t size;
867: kern_return_t kr;
868:
869: size = round_page (count);
870: kr = kmem_alloc (kernel_map, &addr, size);
871: if (kr != KERN_SUCCESS)
872: return kr;
873: kr = (*dev->ops->read_inband) (dev, reply_port,
874: reply_port_type, mode, recnum,
875: count, (char *) addr, bytes_read);
876: if (kr == D_SUCCESS)
877: {
878: vm_size_t result_size = round_page (*bytes_read);
879:
880: /* Free any excess pages we allocated beyond what was used. */
881: size -= result_size;
882: if (size > 0)
883: vm_deallocate (kernel_map, addr + result_size, size);
884:
885: /* Zero memory that the device did not fill. */
886: memset ((char *) addr + *bytes_read, 0,
887: result_size - *bytes_read);
888:
889: kr = vm_map_copyin_page_list (kernel_map, addr, result_size,
890: TRUE, TRUE, (vm_map_copy_t *) data,
891: FALSE);
892: if (kr != KERN_SUCCESS)
893: panic ("vm_map_copyin_page_list failed");
894: }
895: else
896: {
897: /* Deallocate the pages since the read failed completely. */
898: vm_deallocate (kernel_map, addr, size);
899: }
900: return kr;
901: }
902: }
903:
904: io_return_t
905: ds_device_read_inband (device_t dev, ipc_port_t reply_port,
906: mach_msg_type_name_t reply_port_type, dev_mode_t mode,
907: recnum_t recnum, int count, char *data,
908: unsigned *bytes_read)
909: {
910: /* There must be a reply port. */
911: if (! IP_VALID (reply_port))
912: return MIG_NO_REPLY;
913: if (dev == DEVICE_NULL)
914: return D_NO_SUCH_DEVICE;
915: if (!(dev->mode & D_READ))
916: INVALOP;
917: if (count > IO_INBAND_MAX)
918: count = IO_INBAND_MAX;
919:
920: if (dev->ops->read_inband)
921: return (*dev->ops->read_inband) (dev, reply_port,
922: reply_port_type, mode, recnum,
923: count, data, bytes_read);
924: if (dev->ops->read)
925: {
926: vm_map_copy_t copy;
927: io_return_t err = (*dev->ops->read) (dev, reply_port,
928: reply_port_type, mode, recnum,
929: count,
930: (io_buf_ptr_t *) ©,
931: bytes_read);
932: if (!err)
933: {
934: vm_offset_t addr;
935: err = vm_map_copyout (kernel_map, &addr, copy);
936: assert (!err);
937: memcpy (data, (char *) addr, *bytes_read);
938: vm_deallocate (kernel_map, addr, round_page (*bytes_read));
939: }
940: return err;
941: }
942:
943: INVALOP;
944: }
945:
946: io_return_t
947: ds_device_set_status (device_t dev, dev_flavor_t flavor,
948: dev_status_t status, mach_msg_type_number_t status_count)
949: {
950: if (dev == DEVICE_NULL)
951: return D_NO_SUCH_DEVICE;
952: if (! dev->ops->set_status)
953: INVALOP;
954:
955: return (*dev->ops->set_status) (dev, flavor, status,
956: status_count);
957: }
958:
959: io_return_t
960: ds_device_get_status (device_t dev, dev_flavor_t flavor, dev_status_t status,
961: mach_msg_type_number_t *status_count)
962: {
963: if (dev == DEVICE_NULL)
964: return D_NO_SUCH_DEVICE;
965: if (! dev->ops->get_status)
966: INVALOP;
967:
968: return (*dev->ops->get_status) (dev, flavor, status,
969: status_count);
970: }
971:
972: io_return_t
973: ds_device_set_filter (device_t dev, ipc_port_t receive_port, int priority,
974: filter_t *filter, unsigned filter_count)
975: {
976: if (dev == DEVICE_NULL)
977: return D_NO_SUCH_DEVICE;
978: if (! dev->ops->set_filter)
979: INVALOP;
980: return (*dev->ops->set_filter) (dev, receive_port,
981: priority, filter, filter_count);
982: }
983:
984: io_return_t
985: ds_device_map (device_t dev, vm_prot_t prot, vm_offset_t offset,
986: vm_size_t size, ipc_port_t *pager, boolean_t unmap)
987: {
988: kern_return_t kr;
989:
990: if (dev == DEVICE_NULL)
991: return D_NO_SUCH_DEVICE;
992: if (! dev->ops->map)
993: INVALOP;
994:
995: if (dev->mode != (D_READ | ((prot & VM_PROT_WRITE) ? D_WRITE : 0)))
996: INVALOP;
997:
998: /* This call serves only to verify that this offset and size are valid.
999: It does not do any mapping! All the real work with the VM system
1000: is done by the device pager code (found in device/dev_pager.c). */
1001: kr = (*dev->ops->map) (dev, prot, offset, size, 0);
1002: if (!kr)
1003: kr = device_pager_setup (dev, prot, offset, size, pager);
1004: return kr;
1005: }
1006:
1007:
1008: io_return_t
1009: ds_device_write_trap (device_t dev, dev_mode_t mode,
1010: recnum_t recnum, vm_offset_t data, vm_size_t count)
1011: {
1012: if (dev == DEVICE_NULL)
1013: return D_NO_SUCH_DEVICE;
1014: if (!(dev->mode & D_WRITE))
1015: return D_INVALID_OPERATION;
1016: if (! dev->ops->write_trap)
1017: return D_INVALID_OPERATION;
1018: return (*dev->ops->write_trap) (dev, mode, recnum, data, count);
1019: }
1020:
1021: io_return_t
1022: ds_device_writev_trap (device_t dev, dev_mode_t mode,
1023: recnum_t recnum, io_buf_vec_t *iovec, vm_size_t count)
1024: {
1025: if (dev == DEVICE_NULL)
1026: return D_NO_SUCH_DEVICE;
1027: if (!(dev->mode & D_WRITE))
1028: return D_INVALID_OPERATION;
1029: if (! dev->ops->writev_trap)
1030: return D_INVALID_OPERATION;
1031: return (*dev->ops->writev_trap) (dev, mode, recnum, iovec, count);
1032: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.