|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24: /* Copyright (c) 1991 NeXT Computer, Inc. All rights reserved.
25: *
26: * dma.m - kern_dev stub for IODevice testing.
27: *
28: * HISTORY
29: * 08-Apr-91 Doug Mitchell at NeXT
30: * Created.
31: */
32:
33: #import <objc/objc.h>
34: #import <driverkit/driverServer.h>
35: #import <driverkit/return.h>
36: #import <driverkit/Device_ddm.h>
37: #import <architecture/nrw/io.h>
38: #import <driverkit/generalFuncs.h>
39: #import <driverkit/interruptMsg.h>
40: #import <machkit/NXLock.h>
41: #import <bsd/sys/printf.h>
42: #import <driverkit/IODeviceParams.h>
43: #import <libc.h>
44:
45: #ifndef KERNEL
46: #define vm_map_t vm_task_t
47: #endif KERNEL
48:
49: /*
50: * Struct for "enqueueing" dma requests.
51: */
52: typedef struct {
53: unsigned dma_id;
54: vm_offset_t address;
55: unsigned byte_count;
56: unsigned completed:1;
57: queue_chain_t link;
58: } dma_frame_t;
59:
60: /*
61: * Info for one mapped dma channel.
62: */
63: typedef struct {
64: queue_head_t frame_list; // queue of dma frames
65: id channel_lock;
66: unsigned mapped:1, // true if channel is mapped
67: running:1;
68: IODmaDirection dir;
69: } dma_chan_t;
70:
71: /*
72: * Static variables for "registering" one (and only one) device.
73: * If we want to get fancy, we can make these one-per-dev_port.
74: */
75: BOOL dev_port_exists = NO; // dev_port_create() called
76: BOOL dev_is_mapped = NO; // dev_reg_mapped() called
77: port_t interrupt_port = PORT_NULL;
78: BOOL streamMode;
79: dma_chan_t channel[CHAN_PER_DEV];
80: IODevicePage *dev_page = NULL;
81: BOOL int_enabled;
82: BOOL int_pending;
83:
84: static dma_frame_t *dma_frame_alloc();
85: static void dma_frame_free(dma_frame_t *frame);
86: static void set_eor(int channel);
87: static void set_error_int(int channel);
88:
89: IOReturn _IOLookupByObjectNumber(
90: port_t device_master,
91: IODeviceNumber dev_number,
92: IOSlotId *slot_id, // returned
93: IODeviceType *dev_type,
94: BOOL *in_use)
95: {
96: xpr_dma("dev_get_type\n", 1,2,3,4,5);
97: return(IO_R_SUCCESS);
98: }
99:
100: IOReturn _IOLookupByObjectNumberFromPort(
101: port_t dev_port,
102: IOSlotId *slot_id, // returned
103: IODeviceType *dev_type) // returned
104: {
105: xpr_dma("dev_port_to_type\n", 1,2,3,4,5);
106: return(IO_R_SUCCESS);
107: }
108:
109: IOReturn _IOCreateDevicePort(
110: port_t device_master,
111: task_t target_task,
112: IODeviceNumber dev_num,
113: port_name_t *dev_port)
114: {
115: xpr_dma("dev_port_create\n", 1,2,3,4,5);
116: dev_port_exists = YES;
117: return(IO_R_SUCCESS);
118: }
119:
120: IOReturn _IODestroyDevicePort(
121: port_t device_master,
122: port_t dev_port)
123: {
124: xpr_dma("dev_port_destroy\n", 1,2,3,4,5);
125: dev_port_exists = NO;
126: return(IO_R_SUCCESS);
127: }
128:
129: IOReturn _IOAttachInterrupt(
130: port_t dev_port,
131: port_t intr_port)
132: {
133: xpr_dma("dev_intr_attach\n", 1,2,3,4,5);
134: if(!dev_port_exists) {
135: IOLog("dev_intr_attach: no dev_port\n");
136: return IO_R_PRIVILEGE;
137: }
138: interrupt_port = intr_port;
139: int_enabled = NO;
140: return(IO_R_SUCCESS);
141: }
142:
143: IOReturn _IODetachInterrupt(
144: port_t dev_port,
145: port_t intr_port)
146: {
147: xpr_dma("dev_intr_detach\n", 1,2,3,4,5);
148: if(!dev_port_exists) {
149: IOLog("dev_intr_detach: no dev_port\n");
150: return IO_R_PRIVILEGE;
151: }
152: if(interrupt_port == PORT_NULL) {
153: IOLog("dev_intr_detach: no interrupt port\n");
154: return IO_R_NOT_ATTACHED;
155: }
156: interrupt_port = PORT_NULL;
157: return(IO_R_SUCCESS);
158: }
159: IOReturn _IOAttachChannel(
160: port_t dev_port,
161: int chan_num,
162: BOOL stream_mode,
163: int buffer_size)
164: {
165: dma_chan_t *chan;
166:
167: xpr_dma("dev_chan_attach\n", 1,2,3,4,5);
168: if(!dev_port_exists) {
169: IOLog("dev_chan_attach: no dev_port\n");
170: return IO_R_PRIVILEGE;
171: }
172: if(channel[chan_num].mapped) {
173: IOLog("dev_chan_attach: chan already mapped\n");
174: return IO_R_BUSY;
175: }
176: if(chan_num > CHAN_PER_DEV) {
177: IOLog("dev_chan_attach: bogus channel number (%d)\n",
178: chan_num);
179: return(IO_R_INVALID_ARG);
180: }
181: chan = &channel[chan_num];
182: chan->mapped = 1;
183: int_pending = 0;
184: queue_init(&chan->frame_list);
185: streamMode = stream_mode;
186: chan->channel_lock = [NXSpinLock new];
187: return(IO_R_SUCCESS);
188: }
189:
190: IOReturn _IODetachChannel(
191: port_t dev_port,
192: int chan_num)
193: {
194: dma_chan_t *chan = &channel[chan_num];
195: IOReturn rtn = IO_R_SUCCESS;
196:
197: xpr_dma("dev_chan_detach\n", 1,2,3,4,5);
198: if(!dev_port_exists) {
199: IOLog("dev_chan_detach: no dev_port\n");
200: return IO_R_PRIVILEGE;
201: }
202: [chan->channel_lock lock];
203: if(!channel[chan_num].mapped) {
204: IOLog("dev_chan_detach: chan not mapped\n");
205: rtn = IO_R_NOT_ATTACHED;
206: goto done;
207: }
208: channel[chan_num].mapped = 0;
209: done:
210: [chan->channel_lock unlock];
211: return rtn;
212: }
213:
214: IOReturn _IOMapDevicePage(
215: IODevicePort dev_port,
216: task_t target_task,
217: vm_offset_t *addr, /* in/out */
218: BOOL anywhere,
219: IOCache cache)
220: {
221: xpr_dma("dev_reg_map\n", 1,2,3,4,5);
222: if(!dev_port_exists) {
223: IOLog("dev_reg_map: no dev_port\n");
224: return IO_R_PRIVILEGE;
225: }
226: dev_page = IOMalloc(sizeof(IODevicePage));
227: bzero(dev_page, sizeof(*dev_page));
228: *addr = (vm_offset_t)dev_page;
229: dev_is_mapped = YES;
230: return(IO_R_SUCCESS);
231: }
232:
233: IOReturn _IOUnmapDevicePage(
234: port_t dev_port,
235: task_t target_task,
236: vm_offset_t addr)
237: {
238: xpr_dma("dev_reg_unmap\n", 1,2,3,4,5);
239: if(!dev_port_exists) {
240: IOLog("dev_reg_unmap: no dev_port\n");
241: return IO_R_PRIVILEGE;
242: }
243: if(!dev_is_mapped) {
244: IOLog("dev_reg_unmap: dev not mapped\n");
245: return(IO_R_NOT_ATTACHED);
246: }
247: if(addr != (vm_offset_t)dev_page) {
248: IOLog("dev_reg_unmap: bad address\n");
249: return IO_R_PRIVILEGE;
250: }
251: IOFree(dev_page, sizeof(IODevicePage));
252: dev_is_mapped = NO;
253: return(IO_R_SUCCESS);
254: }
255:
256: IOReturn _IOMapSlotSpace(
257: port_t dev_port,
258: task_t target_task,
259: vm_offset_t slot_offset,
260: vm_size_t length,
261: vm_offset_t *addr, // in/out
262: BOOL anywhere,
263: IOCache cache)
264: {
265: xpr_dma("dev_slot_map\n", 1,2,3,4,5);
266: if(!dev_port_exists)
267: return IO_R_PRIVILEGE;
268: return(IO_R_SUCCESS);
269: }
270:
271: IOReturn _IOUnmapSlotSpace(port_t dev_port,
272: task_t target_task,
273: vm_offset_t addr,
274: vm_size_t len)
275: {
276: xpr_dma("dev_slot_unmap\n", 1,2,3,4,5);
277: if(!dev_port_exists)
278: return IO_R_PRIVILEGE;
279: return(IO_R_SUCCESS);
280: }
281:
282: IOReturn _IOSendChannelCommand(port_t dev_port,
283: int chan_num,
284: IOChannelCommand command)
285: {
286: xpr_dma("chan_command cmd = 0x%x\n", command,2,3,4,5);
287: if(!dev_port_exists) {
288: IOLog("chan_command: no dev_port\n");
289: return IO_R_PRIVILEGE;
290: }
291: if(command & IO_CC_ENABLE_INTERRUPTS)
292: int_enabled = 1;
293: else if(command & IO_CC_ENABLE_INTERRUPTS)
294: int_enabled = 0;
295: else {
296: IOLog("chan_command: BOGUS COMMAND (0x%x)\n", command);
297: return IO_R_INVALID_ARG;
298: }
299: return(IO_R_SUCCESS);
300: }
301:
302: IOReturn _IOEnqueueDMA(port_t dev_port,
303: int chan_num,
304: vm_task_t task_id,
305: vm_offset_t addr,
306: vm_size_t len,
307: IODmaDirection rw,
308: IODescriptorCommand cmd,
309: u_char index,
310: IOChannelEnqueueOption opts,
311: unsigned dma_id,
312: BOOL *running)
313: {
314: IOReturn rtn = IO_R_SUCCESS;
315: dma_chan_t *chan;
316: dma_frame_t *frame;
317:
318: xpr_dma("chan_dma_enqueue dma_id 0x%x len %d chan %d\n",
319: dma_id, len, chan_num, 4,5);
320: if(!dev_port_exists) {
321: IOLog("chan_dma_enqueue: no dev_port\n");
322: return IO_R_PRIVILEGE;
323: }
324: if(!dev_is_mapped) {
325: IOLog("chan_dma_enqueue: no dev_page\n");
326: return IO_R_PRIVILEGE;
327: }
328: chan = &channel[chan_num];
329: [chan->channel_lock lock];
330: if(!chan->mapped) {
331: IOLog("chan_dma_enqueue: channel not mapped\n");
332: rtn = IO_R_NOT_ATTACHED;
333: goto done;
334: }
335:
336: /*
337: * Take care of enabling interrupts now to simpify notification...
338: */
339: if(opts & IO_CEO_ENABLE_INTERRUPTS)
340: int_enabled = YES;
341:
342: /*
343: * Enqueue this on the end of this channel's pending DMAs.
344: */
345: frame = dma_frame_alloc();
346: frame->dma_id = dma_id;
347: frame->address = addr;
348: frame->byte_count = len;
349: frame->completed = 0;
350: if(!queue_empty(&chan->frame_list)) {
351:
352: /*
353: * Make sure we're not changing direction.
354: */
355: if(chan->dir != rw) {
356: IOLog("chan_dma_enqueue: DMA DIRECTION CHANGE\n");
357: rtn = IO_R_INVALID_ARG;
358: goto done;
359: }
360: }
361: else {
362: chan->dir = rw;
363: }
364: queue_enter(&chan->frame_list,
365: frame,
366: dma_frame_t *,
367: link);
368:
369: /*
370: * Block devices:
371: * Mark this frame as done. Block devices do their own interrupt
372: * simulation for testing.
373: *
374: * Stream devices:
375: * Mark this frame as done for outbound frames only.
376: * If this is a IO_DMAWrite and there exists a IO_DMARead
377: * channel on this device, mark the first non-complete frame
378: * on the read channel's queue as done, copy the data we just enqueued
379: * to that (DMA read) frame, and send an interrupt message to the
380: * driver. (Intended for ethernet debug).
381: */
382: if(!streamMode) {
383: frame->completed = 1;
384: set_eor(chan_num);
385: }
386: else if(rw == IO_DMAWrite) {
387:
388: int read_chan_num;
389: dma_chan_t *read_chan = &channel[0];
390: dma_frame_t *read_frame;
391: BOOL found = NO;
392: IOInterruptMsg int_msg;
393: kern_return_t krtn;
394:
395: frame->completed = 1;
396: set_eor(chan_num);
397: for(read_chan_num=0;
398: read_chan_num<CHAN_PER_DEV;
399: read_chan_num++) {
400: if(read_chan->dir == IO_DMARead)
401: break;
402: chan++;
403: }
404: if(read_chan_num == CHAN_PER_DEV) {
405: xpr_dma("chan_dma_enqueue: NO READ CHANNEL\n",
406: 1,2,3,4,5);
407:
408: /*
409: * for int_pending....
410: */
411: read_chan = chan;
412: goto send_intr;
413: }
414:
415: /*
416: * OK, look for an uncompleted DMA frame on the Read channel
417: * queue.
418: */
419: read_frame = (dma_frame_t *)
420: queue_first(&read_chan->frame_list);
421: while(!queue_end(&read_chan->frame_list,
422: (queue_t)read_frame)) {
423: if(!read_frame->completed) {
424: found = YES;
425: break;
426: }
427: read_frame = (dma_frame_t *)read_frame->link.next;
428: }
429: if(!found) {
430: /*
431: * DMA overrun! Let's call this a "channel error"
432: * interrupt.
433: */
434: xpr_dma("chan_dma_enqueue: DMA Overrun on Read\n ",
435: 1,2,3,4,5);
436: if(queue_empty(&read_chan->frame_list)) {
437: xpr_dma(" (no frames)\n", 1,2,3,4,5);
438: }
439: else {
440: xpr_dma(" (no incompl frames)\n", 1,2,3,4,5);
441: }
442: set_error_int(read_chan_num);
443: goto send_intr;
444: }
445:
446: /*
447: * Found an incomplete Read frame. Copy data over to it
448: * and make it complete.
449: */
450: bcopy((void *)frame->address, (void *)read_frame->address,
451: frame->byte_count);
452: read_frame->completed = 1;
453: read_frame->byte_count = frame->byte_count;
454: set_eor(read_chan_num);
455:
456: /*
457: * Finally, send an interrupt message to the device if
458: * we haven't already done so since the last "enable
459: * interrupts".
460: */
461: send_intr:
462: if(int_enabled && !int_pending) {
463: bzero(&int_msg, sizeof(int_msg));
464: int_msg.header.msg_size = sizeof(int_msg);
465: int_msg.header.msg_id = IO_DMA_INTERRUPT_MSG;
466: int_msg.header.msg_remote_port = interrupt_port;
467: int_msg.header.msg_local_port = PORT_NULL;
468:
469: /*
470: * Timeout is to handle port queue full. If that
471: * happens, it's a bug in this weird test simulation,
472: * not the driver. That can never happen on the
473: * NRW.
474: */
475: krtn = msg_send(&int_msg.header, SEND_TIMEOUT, 1);
476: if(krtn) {
477: IOLog("chan_dma_enqueue: msg_send returned "
478: "%d\n", krtn);
479: }
480: int_pending = 1;
481: int_enabled = 0;
482: }
483: }
484: *running = NO; // right???
485: done:
486: [chan->channel_lock unlock];
487: return rtn;
488: }
489:
490: IOReturn _IOEnqueueDMAInt(
491: IODevicePort dev_port,
492: int chan_num,
493: vm_map_t task_id,
494: vm_offset_t addr,
495: vm_size_t len,
496: IODmaDirection rw,
497: IODescriptorCommand cmd, // descriptor command - m88k only
498: u_char index,
499: IOChannelEnqueueOption opts,
500: unsigned dma_id, // must be non-zero
501: BOOL *running) // returned - m88k only
502: {
503: return _IOEnqueueDMA(dev_port,
504: chan_num,
505: task_id,
506: addr,
507: len,
508: rw,
509: cmd,
510: index,
511: opts,
512: dma_id,
513: running);
514: }
515:
516: IOReturn _IODequeueDMA(port_t dev_port,
517: int chan_num,
518: IOChannelDequeueOption opts,
519: vm_size_t *bcount, // RETURNED
520: IOUserStatus *userStatus, // RETURNED, m88k only
521: IODmaStatus *dmaStatus, // RETURNED
522: BOOL *eor, // RETURNED
523: unsigned *dma_id) // RETURNED
524: {
525: dma_frame_t *frame = NULL;
526: dma_chan_t *chan;
527: IOReturn rtn = IO_R_SUCCESS;
528: BOOL found = NO;
529: unsigned summary_bit = 1 << chan_num;
530:
531: if(!dev_port_exists)
532: return IO_R_PRIVILEGE;
533: chan = &channel[chan_num];
534: [chan->channel_lock lock];
535: if(!chan->mapped) {
536: IOLog("chan_dma_dequeue: channel not mapped\n");
537: rtn = IO_R_NOT_ATTACHED;
538: goto done;
539: }
540:
541: /*
542: * See if we have a frame to dequeue. We can't tell if a channel
543: * is running; this'll be crude.
544: */
545: if(!queue_empty(&chan->frame_list)) {
546: frame = (dma_frame_t *)queue_first(&chan->frame_list);
547: if(frame->completed || (opts & IO_CDO_ALL))
548: found = YES;
549: }
550: if(found) {
551: queue_remove(&chan->frame_list,
552: frame,
553: dma_frame_t *,
554: link);
555: *dma_id = frame->dma_id;
556: *bcount = frame->byte_count;
557: *dma_status = IO_Complete;
558: *user_status = 0;
559: *eor = frame->completed ? YES : NO;
560: dma_frame_free(frame);
561: }
562: else
563: *dma_id = IO_NULL_DMA_ID;
564:
565: /*
566: * Clear this channel's interrupt bit in the summary register.
567: */
568: dev_page->int_dev.intr_summ.is_u.is_int &= ~summary_bit;
569: int_pending = 0;
570:
571: /*
572: * Re-enable interrupts if appropriate.
573: */
574: if((opts & IO_CDO_ENABLE_INTERRUPTS) ||
575: ((opts & IO_CDO_ENABLE_INTERRUPTS_IF_EMPTY) && (*dma_id == IO_NULL_DMA_ID))) {
576: int_enabled = 1;
577: }
578:
579: done:
580: xpr_dma("chan_dma_dequeue dma_id 0x%x bcount %d chan %d\n",
581: *dma_id, *bcount ,chan_num, 4,5);
582: [chan->channel_lock unlock];
583: return rtn;
584: }
585:
586: /*
587: * Determine deviceType and name of specified unit.
588: */
589: IOReturn _IOLookupByObjectNumber(
590: port_t deviceMaster,
591: IOObjectNumber unit,
592: IOString *deviceType, // returned
593: IOString *name) // returned
594: {
595: return IODoInquire(unit,
596: deviceType,
597: name);
598: }
599:
600: /*
601: * Get/set parameter RPCs.
602: */
603:
604: IOReturn _IOGetParameterInIntArray(
605: port_t device_master,
606: IOObjectNumber unit,
607: IOParameterName parameterName,
608: unsigned int maxCount, // 0 means "as much as
609: // possible"
610: unsigned int *parameterArray, // data returned here
611: unsigned int *returnedCount) // size returned here
612: {
613: return IODoGetParameterInt(unit,
614: parameterName,
615: maxCount,
616: parameterArray,
617: returnedCount);
618: }
619:
620: IOReturn _IOGetParameterInCharArray(
621: port_t device_master,
622: IOObjectNumber unit,
623: IOParameterName parameterName,
624: unsigned int maxCount, // 0 means "as much as
625: // possible"
626: unsigned char *parameterArray, // data returned here
627: unsigned int *returnedCount) // size returned here
628: {
629: return IODoGetParameterChar(unit,
630: parameterName,
631: maxCount,
632: parameterArray,
633: returnedCount);
634: }
635:
636: IOReturn _IOSetParameterFromIntArray(
637: port_t device_master,
638: IOObjectNumber unit,
639: IOParameterName parameterName,
640: unsigned int count, // size of parameterArray
641: unsigned int *parameterArray)
642: {
643: return IODoSetParameterInt(unit,
644: parameterName,
645: count,
646: parameterArray);
647: }
648:
649: IOReturn _IOSetParameterFromCharArray(
650: port_t device_master,
651: IOObjectNumber unit,
652: IOParameterName parameterName,
653: unsigned int count, // size of parameterArray
654: unsigned char *parameterArray)
655: {
656: return IODoSetParameterChar(unit,
657: parameterName,
658: count,
659: parameterArray);
660: }
661:
662:
663: static dma_frame_t *dma_frame_alloc()
664: {
665: return(IOMalloc(sizeof(dma_frame_t)));
666: }
667:
668: static void dma_frame_free(dma_frame_t *frame)
669: {
670: IOFree(frame, sizeof(dma_frame_t));
671: }
672:
673: /*
674: * Set channel's EOR and descriptor interrupt bits in channel interrupt cause.
675: * Also set the channel interrupt bit in the device interrupt summary
676: * register.
677: */
678: static void set_eor(int channel)
679: {
680: chan_t *io_chan = &dev_page->chan_regs[channel];
681: unsigned summary_bit = 1 << channel;
682:
683: io_chan->chan_intr_cause.ci_u.ci_int |= (CI_DESC | CI_EIO);
684: dev_page->int_dev.intr_summ.is_u.is_int |= summary_bit;
685: }
686:
687: /*
688: * Set channel's error interrupt.
689: */
690: static void set_error_int(int channel)
691: {
692: chan_t *io_chan = &dev_page->chan_regs[channel];
693: unsigned summary_bit = 1 << channel;
694:
695: io_chan->chan_intr_cause.ci_u.ci_int |= CI_ERROR;
696: dev_page->int_dev.intr_summ.is_u.is_int |= summary_bit;
697: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.