Created
October 22, 2009 22:53
-
-
Save mhansen/216427 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "../drivers.h" | |
| #include "../libdriver/driver.h" | |
| #include "proc.h" | |
| extern int errno; /* error number for PM calls */ | |
| PRIVATE int p_device; /* current device */ | |
| FORWARD _PROTOTYPE( char *p_name, (void) ); | |
| FORWARD _PROTOTYPE( struct device *p_prepare, (int device) ); | |
| FORWARD _PROTOTYPE( int p_transfer, (int proc_nr, int opcode, u64_t position, | |
| iovec_t *iov, unsigned nr_req, int safe)); | |
| FORWARD _PROTOTYPE( int p_do_open, (struct driver *dp, message *m_ptr) ); | |
| FORWARD _PROTOTYPE( void p_geometry, (struct partition *entry) ); | |
| /* Entry points to this driver. */ | |
| PRIVATE struct driver p_dtab = { | |
| p_name, /* current device's name */ | |
| p_do_open, /* open or mount */ | |
| do_nop, /* nothing on a close */ | |
| nop_ioctl, /* no ioctl */ | |
| p_prepare, /* prepare for I/O on a given minor device */ | |
| p_transfer, /* do the I/O */ | |
| nop_cleanup, /* no need to clean up */ | |
| p_geometry, /* memory device "geometry" */ | |
| nop_signal, /* system signals */ | |
| nop_alarm, | |
| nop_cancel, | |
| nop_select, | |
| NULL, | |
| NULL | |
| }; | |
| /* There is no physical device here, so return a dummy device when asked */ | |
| PRIVATE struct device dummy_dev; | |
| #define PROC_BUFSIZE 8192 /* size in bytes of the largest file expected */ | |
| PRIVATE char proc_buffer[PROC_BUFSIZE]; | |
| /* call vector table - defined in proto.h */ | |
| extern void (*pr_vec[NR_DEVS]) (char *buffer, int bufSize); | |
| /******************************************************************************/ | |
| /* p_transfer : This is where the main action of the driver happens */ | |
| /******************************************************************************/ | |
| PRIVATE int p_transfer(proc_nr, opcode, pos64, iov, nr_req, safe) | |
| int proc_nr; /* process doing the request */ | |
| int opcode; /* DEV_GATHER_S or DEV_SCATTER_S */ | |
| u64_t pos64; /* offset on device to read or write */ | |
| iovec_t *iov; /* pointer to read or write request vector */ | |
| unsigned nr_req; /* length of request vector */ | |
| int safe; /* safe copies */ | |
| { | |
| /* Read or write one the driver's minor devices. */ | |
| unsigned bytes_asked_for, bytes_to_copy; | |
| vir_bytes user_vir, vir_offset = 0; | |
| int s, file_length; | |
| off_t file_position; | |
| if(!safe) { | |
| printf("m_transfer: unsafe?\n"); | |
| return EPERM; | |
| } | |
| file_position= cv64ul(pos64); | |
| while (nr_req > 0) { | |
| /* How much to transfer and where to / from. */ | |
| bytes_asked_for = iov->iov_size; | |
| user_vir = iov->iov_addr; | |
| /* only service read requests */ | |
| if (opcode == DEV_GATHER_S) { | |
| /* Fill proc_buffer with file-specific data to return. | |
| Delegate to a different function for each device */ | |
| pr_vec[p_device](proc_buffer, PROC_BUFSIZE); | |
| /* we have the data, now copy just as much | |
| as was asked for, or as much as we have */ | |
| file_length = strlen(proc_buffer); | |
| if (file_position >= file_length) return OK; /* At EOF */ | |
| if (file_position + bytes_asked_for > file_length) | |
| bytes_to_copy = file_length - file_position; | |
| else bytes_to_copy = bytes_asked_for; | |
| s = sys_safecopyto(proc_nr, user_vir, vir_offset, | |
| (vir_bytes) proc_buffer, bytes_to_copy, D); | |
| if (s != OK) report ("PROC", "sys_safecopyto failed", s); | |
| /* Book the number of bytes transferred. */ | |
| file_position += bytes_to_copy; | |
| vir_offset += bytes_to_copy; | |
| iov->iov_size -= bytes_to_copy; | |
| } | |
| if (iov->iov_size == 0 || /* this request is finished */ | |
| opcode == DEV_SCATTER_S) { /* this is a write request */ | |
| iov++; nr_req--; vir_offset = 0; /* move on to the next request */ | |
| } | |
| } | |
| return(OK); | |
| } | |
| /*===========================================================================* | |
| * main * | |
| *===========================================================================*/ | |
| PUBLIC int main(void) | |
| { | |
| /* Main program. Initialize the proc driver and start the main loop. */ | |
| struct sigaction sa; | |
| sa.sa_handler = SIG_MESS; | |
| sigemptyset(&sa.sa_mask); | |
| sa.sa_flags = 0; | |
| if (sigaction(SIGTERM,&sa,NULL)<0) panic("PROC","sigaction failed", errno); | |
| driver_task(&p_dtab); | |
| return(OK); | |
| } | |
| /*===========================================================================* | |
| * p_name * | |
| *===========================================================================*/ | |
| PRIVATE char *p_name() | |
| { | |
| /* Return a name for the current device. */ | |
| static char name[] = "proc"; | |
| return name; | |
| } | |
| /*===========================================================================* | |
| * p_prepare * | |
| *===========================================================================*/ | |
| PRIVATE struct device *p_prepare(device) | |
| int device; | |
| { | |
| /* Prepare for I/O on a device: check if the minor device number is ok. */ | |
| if (device < 0 || device >= NR_DEVS) return(NIL_DEV); | |
| p_device = device; | |
| return(&dummy_dev); | |
| } | |
| /*===========================================================================* | |
| * p_do_open * | |
| *===========================================================================*/ | |
| PRIVATE int p_do_open(dp, m_ptr) | |
| struct driver *dp; | |
| message *m_ptr; | |
| { | |
| /* Check device number on open. */ | |
| if (p_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO); | |
| return(OK); | |
| } | |
| /*===========================================================================* | |
| * p_geometry * | |
| *===========================================================================*/ | |
| PRIVATE void p_geometry(entry) | |
| struct partition *entry; | |
| { | |
| /* /proc doesn't have a geometry, but the outside world insists. */ | |
| entry->cylinders = div64u(dummy_dev.dv_size, SECTOR_SIZE) / (64 * 32); | |
| entry->heads = 64; | |
| entry->sectors = 32; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment