File:  [Apple Darwin 0.x] / driverkit / Examples / IOStub / IOStub.m
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:37:50 2018 UTC (8 years, 3 months ago) by root
Branches: MAIN, Apple
CVS tags: HEAD, Darwin03, Darwin02
Darwin 0.2 Driver Kit

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.1 (the "License").  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/*	IOStub.m	1.0	01/29/91	(c) 1991 NeXT   
 *
 * IOStub.m - Implementation for trivial I/O device subclass.
 *
 * HISTORY
 * 29-Jan-91    Doug Mitchell at NeXT
 *      Created. 
 */
 
#import <bsd/sys/types.h>
#import <mach/mach.h>
#import <mach/vm_param.h>
#import <mach/mach_error.h>
#import <bsd/libc.h>
#import <driverkit/return.h>
#import <driverkit/IODevice.h>
#import "IOStub.h"
#import "IOStubThread.h"
#import "IOStubDevice.h"
#import "IOStubUxpr.h"
#import <machkit/NXLock.h>

@implementation IOStub

/*
 * Initialize current instance. Returns non-zero on error.
 */
- initStub : (int)unitNum
{
	int data_size;
	int i;
	char *cp;
	kern_return_t krtn;
	u_int block_size, dev_size;
	
	xpr_stub("IOStub : init: unitNum %d\n", unitNum, 2,3,4,5);
	

	[self setUnit:unitNum];
	if(unitNum == 0) {
		/*
		 * read/write.
		 */
		block_size = 0x20;
		dev_size = 0x1000;
		[self setName : "IOStub0"];
		[self setWriteProtected:NO];
	}
	else {
		/*
		 * Make this one read-only, non-queuing.
		 */
		block_size = 0x40;
		dev_size = 0x800;
		[self setName : "IOStub1"];
		[self setWriteProtected:YES];
	}
	[self setDeviceKind:"Stub Device"];
	[self setLocation:NULL];
	[self setDiskSize:dev_size];
	[self setBlockSize:block_size];
	[self setFormattedInternal:1];
	
	/* 
	 * allocate and initialize data for writing and reading.
	 */
	data_size = block_size * dev_size;
	krtn = vm_allocate(task_self(),
		(vm_address_t *)&stub_data,
		(vm_size_t)round_page(data_size), 
		YES);
	if(krtn != KERN_SUCCESS) {
		mach_error("***IOStub init: vm_allocate", krtn);
		return(self);
	}
	
	/*
	 * initial data: incrementing bytes for unit 0, decrementing
	 * bytes for others.
	 */
	cp = (char *)stub_data;
	for(i=0; i<data_size; i++) {
		if(unitNum)
			*cp++ = 0 - (char)i;
		else
			*cp++ = i;
	}
	 
	/*
	 * Set up our instance's IOQueue.
	 */
	ioQLock = [NXConditionLock alloc];
	[ioQLock initWith:NO_WORK_AVAILABLE];
	queue_init(&ioQueue);

	/*
	 * Start up an I/O thread to perform the actual work of this device.
	 */
	IOForkThread((IOThreadFunc)IOStub_thread, self);
			
	[self registerDevice];
	
	/*
	 * Let superclass take care of initializing inherited instance
	 * variables.
	 */
	[super init];
	return self;
}

/*
 * Free resources consumed by this instance. 
 */
- free
{
	int data_size;
	kern_return_t krtn;
	u_int block_size, dev_size;
	IOBuf_t *IOBuf;
		
	/*
	 * Kill the I/O thread.
	 */
	IOBuf            = IOMalloc(sizeof(*IOBuf));
	IOBuf->cmd       = STUB_ABORT;
	IOBuf->pending   = 0;
	IOBuf->waitLock  = [NXConditionLock alloc];
	[IOBuf->waitLock initWith:NO];
	[self enqueueIoBuf:IOBuf];
	
	/*
	 * Wait for I/O complete.
	 */
	[IOBuf->waitLock lockWhen:YES];
	[IOBuf->waitLock unlock];
	[IOBuf->waitLock free];
	IOFree(IOBuf, sizeof(IOBuf_t));
	
	/*
	 *  Free up our VM.
	 */
	block_size = [self blockSize];
	dev_size = [self diskSize];
	data_size = block_size * dev_size;
	krtn = vm_deallocate(task_self(),
		(vm_address_t)stub_data,
		(vm_size_t)round_page(data_size));
	if(krtn != KERN_SUCCESS) {
		mach_error("***IOStub free: vm_deallocate", krtn);
	}
	return([super free]);
}

/*
 * These override the superclass's methods which are no-op stubs.
 */
 
- (int)deviceOpen:(u_int)intentions
{
	xpr_stub("IOStub deviceOpen: unit %d\n", [self unit], 2,3,4,5);
	return(IO_R_SUCCESS);
}

- (void)deviceClose
{
	xpr_stub("IOStub deviceClose: unit %d\n", [self unit], 2,3,4,5);
}

/* 
 * These are the exported I/O methods, from the 
 * IODiskDeviceReadingAndWriting category. Their main task is:
 * 
 * -- verify valid input parameters.
 * -- set up and enqueue an IOBuf for servicing by the I/O thread.
 * -- Wait for I/O complete if synchronous request.
 */

- (IOReturn) readAt		: (unsigned)offset 
				  length : (unsigned)length 
				  buffer : (unsigned char *)buffer
				  actualLength : (unsigned *)actualLength
{
	IOReturn mrtn;
	char *source;
	IOBuf_t *IOBuf;
	u_int block_size;
	u_int dev_size;
	
	xpr_stub("IOStub read: unit %d  offset 0x%x  length 0x%x\n",
		[self unit], offset, length, 4,5);
		
	block_size = [self blockSize];
	dev_size = [self diskSize];

	/*
	 * Verify legal parameters.
	 */
	source = stub_data + offset * block_size;
	if((source + length) > (stub_data + (block_size * dev_size))) {
	   
	    	xpr_stub("IOStub read: invalid offset/byte count\n", 
			1,2,3,4,5);
		return(IO_R_INVALID_ARG);
	}

	/*
	 * OK, queue up an IOBuf.
	 */
	IOBuf            = IOMalloc(sizeof(*IOBuf));
	IOBuf->cmd       = STUB_READ;
	IOBuf->offset    = offset;
	IOBuf->bytesReq	 = length;
	IOBuf->buf       = buffer;
	IOBuf->bytesXfr  = actualLength;
	IOBuf->status 	 = IO_R_INVALID;
	IOBuf->pending   = 0;
	IOBuf->waitLock  = [NXConditionLock alloc];
	[IOBuf->waitLock initWith:NO];
	IOBuf->dirRead	 = 1;
	[self enqueueIoBuf:IOBuf];
	
	/*
	 * Wait for I/O complete.
	 */
	[IOBuf->waitLock lockWhen:YES];
	[IOBuf->waitLock unlock];
	xpr_stub("stub read: DONE\n", 1,2,3,4,5);
	mrtn = IOBuf->status;
	[IOBuf->waitLock free];
	IOFree(IOBuf, sizeof(*IOBuf));
	return(mrtn);
}

- (IOReturn) readAsyncAt	: (unsigned)offset 
				  length : (unsigned)length 
				  buffer : (unsigned char *)buffer
				  pending : (void *)pending
{
	char *source;
	IOBuf_t *IOBuf;
	unsigned block_size;
	unsigned dev_size;
	
	xpr_stub("IOStub readAsync: unit %d  offset 0x%x  length 0x%x\n",
		[self unit], offset, length, 4,5);
		
	block_size = [self blockSize];
	dev_size = [self diskSize];

	/*
	 * Verify legal parameters.
	 */
	source = stub_data + offset * block_size;
	if((source + length) > (stub_data + (block_size * dev_size))) {
	   
	    	xpr_stub("IOStub read: invalid offset/byte count\n",
			1,2,3,4,5);
		return(IO_R_INVALID_ARG);
	}

	/*
	 * Just queue up an IOBuf.
	 */
	IOBuf            = IOMalloc(sizeof(*IOBuf));
	IOBuf->cmd       = STUB_READ;
	IOBuf->offset    = offset;
	IOBuf->bytesReq	 = length;
	IOBuf->buf       = buffer;
	IOBuf->status 	 = IO_R_INVALID;	/* must be filled in by
						 * I/O thread */
	IOBuf->pending   = pending;
	IOBuf->dirRead	 = 1;
	[self enqueueIoBuf:IOBuf];
	
	xpr_stub("stub readAsync: DONE\n", 1,2,3,4,5);
	return(IO_R_SUCCESS);
}

- (IOReturn) writeAt		: (unsigned)offset 
				  length : (unsigned)length 
				  buffer : (unsigned char *)buffer
				  actualLength : (unsigned *)actualLength
{
	IOReturn mrtn;
	char *dest;
	IOBuf_t *IOBuf;
	unsigned block_size;
	unsigned dev_size;
	
	xpr_stub("IOStub write: unit %d  offset 0x%x  length 0x%x\n",
		[self unit], offset, length, 4,5);
		
	block_size = [self blockSize];
	dev_size = [self diskSize];

	/*
	 * Verify legal parameters.
	 */
	if([self isWriteProtected]) {
		return IO_R_NOT_WRITABLE;
	}
	dest = stub_data + offset * block_size;
	if((dest + length) > (stub_data + (block_size * dev_size))) {
	   
	    	xpr_stub("IOStub dest: invalid offset/byte count\n",
			1,2,3,4,5);
		return(IO_R_INVALID_ARG);
	}

	/*
	 * OK, queue up an IOBuf.
	 */
	IOBuf            = IOMalloc(sizeof(*IOBuf));
	IOBuf->cmd       = STUB_WRITE;
	IOBuf->offset    = offset;
	IOBuf->bytesReq	 = length;
	IOBuf->buf       = buffer;
	IOBuf->bytesXfr  = actualLength;
	IOBuf->status 	 = IO_R_INVALID;
	IOBuf->pending   = 0;
	IOBuf->waitLock  = [NXConditionLock alloc];
	[IOBuf->waitLock initWith:NO];
	IOBuf->dirRead	 = 0;
	[self enqueueIoBuf:IOBuf];
	
	/*
	 * Wait for I/O complete.
	 */
	[IOBuf->waitLock lockWhen:YES];
	[IOBuf->waitLock unlock];
	xpr_stub("stub write: DONE\n", 1,2,3,4,5);
	mrtn = IOBuf->status;
	[IOBuf->waitLock free];
	IOFree(IOBuf, sizeof(*IOBuf));
	return(mrtn);
}

- (IOReturn) writeAsyncAt	: (unsigned)offset 
				  length : (unsigned)length 
				  buffer : (unsigned char *)buffer
				  pending : (void *)pending;
{
	char *source;
	IOBuf_t *IOBuf;
	unsigned block_size;
	unsigned dev_size;
	
	xpr_stub("IOStub writeAsync: unit %d  offset 0x%x  length 0x%x\n",
		[self unit], offset, length, 4,5);
		
	block_size = [self blockSize];
	dev_size = [self diskSize];

	/*
	 * Verify legal parameters.
	 */
	if([self isWriteProtected]) {
		return IO_R_NOT_WRITABLE;
	}
	source = stub_data + offset * block_size;
	if((source + length) > (stub_data + (block_size * dev_size))) {
	   
	    	xpr_stub("IOStub write: invalid offset/byte count\n",
			1,2,3,4,5);
		return(IO_R_INVALID_ARG);
	}

	/*
	 * Just queue up an IOBuf.
	 */
	IOBuf            = IOMalloc(sizeof(*IOBuf));
	IOBuf->cmd       = STUB_WRITE;
	IOBuf->offset    = offset;
	IOBuf->bytesReq	 = length;
	IOBuf->buf       = buffer;
	IOBuf->status 	 = IO_R_INVALID;	/* must be filled in by
						 * I/O thread */
	IOBuf->pending   = pending;
	IOBuf->dirRead	 = 0;
	[self enqueueIoBuf:IOBuf];
	
	xpr_stub("stub writeAsync: DONE\n", 1,2,3,4,5);
	return(IO_R_SUCCESS);
}

/*
 * Distributed Objects R/W protocol.
 */
- (IOReturn) readAt		: (unsigned)offset 		// in blocks
				  length : (unsigned)length 	// in bytes
				  data : (out IOData **)data
				  actualLength : (out unsigned *)actualLength
{
	IOReturn rtn;
	IOData *ldata = [[IOData alloc] initWithSize:length];
	
	/*
	 * FIXME - when freeFlag is set to YES (which is what we really 
	 * want), this method crashes with the following error messages
	 * when run with the DiskTest app:
	 *
	 *   finishEncoding: send error -101:invalid memory
	 *   uncaught exception : 11001
	 *   objc: FREED(id): message free sent to freed object=0x9c01c
	 * 
	 * When run with the test programs in ../tests, everything works 
	 * OK...
	 *
	 * When we set freeFlag to NO, everything works, but the IOStub
	 * server leaks memory.
	 *
	 * Update 15-Oct-92 - this error only happens when moving at least
	 * one entire page of data. Moving less than a page is OK.
	 */
	[ldata setFreeFlag:YES];
	rtn = [self readAt:offset
		length:length
		buffer:[ldata data]
		actualLength:actualLength];
	if(*actualLength) {
		*data = ldata;
	}
	
	/*
	 * FIXME - when does the IOData get deallocated??
	 */
	return rtn;
}

/*
 * DiskRwDistributed protocol.
 */
- (IOData *)rreadAt		: (unsigned)offset
				  length : (unsigned)length
				  rtn : (out IOReturn *)rtn
				  actualLength : (out unsigned *)actualLength
{
	IOReturn lrtn;
	IOData *ldata = [[IOData alloc] initWithSize:length];
	
	[ldata setFreeFlag:YES];
	lrtn = [self readAt:offset
		length:length
		buffer:[ldata data]
		actualLength:actualLength];
	*rtn = lrtn;
	return ldata;
}
	
- (IOReturn) readAsyncAt	: (unsigned)offset
				  length : (unsigned)length
				  ioKey : (unsigned)ioKey
				  caller : (id)caller
{
	/* TBD */
	return IO_R_UNSUPPORTED;
}
				  
			  
- (IOReturn) writeAt		: (unsigned)offset 		// in blocks
				  length : (unsigned)length 	// in bytes
				  data : (in IOData *)data
				  actualLength : (out unsigned *)actualLength
{
	IOReturn rtn;
	
	if([data size] < length) {
		IOLog("%s writeAt: insufficient memory in IOData\n",
			[self name]);
	}
	rtn = [self writeAt:offset
			length:length
			buffer:[data data]
			actualLength:actualLength];
	[data free]; 
	return rtn;
}

- (IOReturn)writeAsyncAt	: (unsigned)offset 		// in blocks
				  length : (unsigned)length 	// in bytes
				  data : (in IOData *)data
				  ioKey : (unsigned)ioKey
				  caller : (id)caller
{
	return IO_R_UNSUPPORTED;
}
@end


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.