Mon 14 Oct 23:06:38 CEST 2024
This commit is contained in:
		
							parent
							
								
									7ab1ce5fad
								
							
						
					
					
						commit
						3609d2db7d
					
				
							
								
								
									
										176
									
								
								kernel/device.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								kernel/device.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,176 @@ | ||||||
|  | /*
 | ||||||
|  | Copyright (C) 2016-2019 The University of Notre Dame | ||||||
|  | This software is distributed under the GNU General Public License. | ||||||
|  | See the file LICENSE for details. | ||||||
|  | */ | ||||||
|  | #include "device.h" | ||||||
|  | #include "string.h" | ||||||
|  | #include "page.h" | ||||||
|  | #include "kmalloc.h" | ||||||
|  | 
 | ||||||
|  | #include "kernel/stats.h" | ||||||
|  | #include "kernel/types.h" | ||||||
|  | #include "kernel/error.h" | ||||||
|  | 
 | ||||||
|  | static struct device_driver *driver_list = 0; | ||||||
|  | 
 | ||||||
|  | struct device { | ||||||
|  | 	struct device_driver *driver; | ||||||
|  | 	int refcount; | ||||||
|  | 	int unit; | ||||||
|  | 	int block_size; | ||||||
|  | 	int nblocks; | ||||||
|  | 	int multiplier; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void device_driver_register( struct device_driver *d ) | ||||||
|  | { | ||||||
|  | 	d->next = driver_list; | ||||||
|  | 	d->stats = (struct device_driver_stats){0}; | ||||||
|  | 	driver_list = d; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct device *device_create( struct device_driver *dd, int unit, int nblocks, int block_size ) | ||||||
|  | { | ||||||
|  | 	struct device *d = kmalloc(sizeof(*d)); | ||||||
|  | 	d->refcount = 1; | ||||||
|  | 	d->driver = dd; | ||||||
|  | 	d->unit = unit; | ||||||
|  | 	d->block_size = block_size; | ||||||
|  | 	d->nblocks = nblocks; | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | If the device driver specifies a non-zero default multiplier, | ||||||
|  | then save it in this device instance.  It gives the effect of | ||||||
|  | multiplying the block size, typically from the 512 ATA sector | ||||||
|  | size, up to the usual 4KB page size.  See the effect below | ||||||
|  | in read/write. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | 	if(dd->multiplier>0) { | ||||||
|  | 		d->multiplier = dd->multiplier; | ||||||
|  | 	} else { | ||||||
|  | 		d->multiplier = 1; | ||||||
|  | 	} | ||||||
|  | 	return d; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct device *device_open( const char *name, int unit ) | ||||||
|  | { | ||||||
|  | 	int nblocks, block_size; | ||||||
|  | 	char info[64]; | ||||||
|  | 
 | ||||||
|  | 	struct device_driver *dd = device_driver_lookup(name); | ||||||
|  | 	if (dd && dd->probe(unit,&nblocks,&block_size,info)) { | ||||||
|  | 		return device_create(dd,unit,nblocks,block_size); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct device *device_addref( struct device *d ) | ||||||
|  | { | ||||||
|  | 	d->refcount++; | ||||||
|  | 	return d; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int device_set_multiplier( struct device *d, int multiplier ) | ||||||
|  | { | ||||||
|  | 	if(multiplier<1 || multiplier*d->block_size>PAGE_SIZE ) { | ||||||
|  | 		return KERROR_INVALID_REQUEST; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	d->multiplier = multiplier; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void device_close( struct device *d ) | ||||||
|  | { | ||||||
|  | 	d->refcount--; | ||||||
|  | 	if(d->refcount<1) kfree(d); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int device_read(struct device *d, void *data, int size, int offset) | ||||||
|  | { | ||||||
|  | 	int status; | ||||||
|  | 	if(d->driver->read) { | ||||||
|  | 		status = d->driver->read(d->unit,data,size*d->multiplier,offset*d->multiplier); | ||||||
|  | 		if (status) { | ||||||
|  | 			d->driver->stats.blocks_read += size*d->multiplier; // number of blocks
 | ||||||
|  | 		} | ||||||
|  | 		return status; | ||||||
|  | 	} else { | ||||||
|  | 		return KERROR_NOT_IMPLEMENTED; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int device_read_nonblock(struct device *d, void *data, int size, int offset) | ||||||
|  | { | ||||||
|  | 	int status; | ||||||
|  | 	if(d->driver->read_nonblock) { | ||||||
|  | 		status = d->driver->read_nonblock(d->unit,data,size*d->multiplier,offset*d->multiplier); | ||||||
|  | 		if (status) { | ||||||
|  | 			d->driver->stats.blocks_read += size*d->multiplier; // number of blocks
 | ||||||
|  | 		} | ||||||
|  | 		return status; | ||||||
|  | 	} else { | ||||||
|  | 		return KERROR_NOT_IMPLEMENTED; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int device_write(struct device *d, const void *data, int size, int offset) | ||||||
|  | { | ||||||
|  | 	int status; | ||||||
|  | 	if(d->driver->write) { | ||||||
|  | 		status = d->driver->write(d->unit,data,size*d->multiplier,offset*d->multiplier); | ||||||
|  | 		if (!status) { | ||||||
|  | 			d->driver->stats.blocks_written += size*d->multiplier; | ||||||
|  | 		} | ||||||
|  | 		return status; | ||||||
|  | 	} else { | ||||||
|  | 		return KERROR_NOT_IMPLEMENTED; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int device_block_size( struct device *d ) | ||||||
|  | { | ||||||
|  | 	return d->block_size*d->multiplier; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int device_nblocks( struct device *d ) | ||||||
|  | { | ||||||
|  | 	return d->nblocks/d->multiplier; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int device_unit( struct device *d ) | ||||||
|  | { | ||||||
|  | 	return d->unit; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char * device_name( struct device *d ) | ||||||
|  | { | ||||||
|  | 	return d->driver->name; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct device_driver * device_driver_lookup(const char *name) | ||||||
|  | { | ||||||
|  | 	struct device_driver *dd = driver_list; | ||||||
|  | 	for(dd=driver_list; dd; dd=dd->next) { | ||||||
|  | 		if(!strcmp(dd->name, name)) { | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return dd; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void device_driver_get_stats(const char * name, struct device_driver_stats * s) | ||||||
|  | { | ||||||
|  | 	/* Get the device driver */ | ||||||
|  | 	struct device_driver *dd = device_driver_lookup(name); | ||||||
|  | 
 | ||||||
|  | 	/* Copy stats into struct */ | ||||||
|  | 	if (dd) { | ||||||
|  | 		memcpy(s, &(dd->stats), sizeof(*s)); | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user