/* driver.c  A skeletal ram drive device driver */

#include <KernelExport.h>
#include <Drivers.h>
#include <Errors.h>
#include <OS.h>
#include <string.h>
#include <stdlib.h>

static void     format_ram_drive(void* buf);
static uchar*   create_ram_drive_area(size_t drive_size);
static status_t delete_ram_drive_area(void);

#define RAM_DRIVE_SIZE           (4*1024*1024) // size of the RAMDrive in bytes
#define RAM_DRIVE_RELEASE_MEMORY (B_DEVICE_OP_CODES_END+1)
#define RAM_DRIVE_EMULATE_SEEK   (B_DEVICE_OP_CODES_END+2)
#define RAM_BLOCK_SIZE            512
#define MAX_SEEK_TIME             1000.0 /* microseconds */
#define	PREFETCH_BUFFER_SIZE     (32*1024)

static const char* const ram_drive_area_name =  "RAM_drive_area";
uchar * ram = NULL;

uchar icon_disk [] = {
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0x00,
	0x15,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x3f,0x00,0x15,
	0x3f,0x15,0x15,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x15,0x3f,
	0x15,0x15,0x15,0x16,0x15,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0x00,0x15,0x3f,0x15,
	0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x3f,0x00,0x15,0x3f,0x15,0x15,
	0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x00,0x00,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x15,0x3f,0x15,0x15,0x15,
	0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x3f,0x0e,0x00,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0x00,0x15,0x3f,0x15,0x15,0x15,0x16,
	0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x3f,0x00,0x15,0x3f,0x15,0x15,0x15,0x16,0x15,
	0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x3f,0x00,0x3f,0x3f,0x00,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x15,0x3f,0x15,0x15,0x15,0x16,0x15,0x15,
	0x15,0x16,0x15,0x15,0x15,0x16,0x3f,0x00,0x00,0x00,0x3f,0x00,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0x00,0xff,0x00,0x15,0x3f,0x15,0x15,0x15,0x16,0x15,0x15,0x15,
	0x16,0x15,0x15,0x15,0x16,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0x00,0x3f,0x00,0x15,0x3f,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,
	0x15,0x15,0x15,0x16,0x3f,0x00,0x3f,0x3f,0x00,0x00,0x15,0x00,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0x00,0x00,0x15,0x3f,0x15,0x15,0x16,0x16,0x15,0x15,0x15,0x16,0x15,
	0x16,0x15,0x15,0x3f,0x00,0x00,0x00,0x3f,0x00,0x00,0x15,0x00,0x0f,0xff,0xff,0xff,
	0xff,0xff,0xff,0x00,0x15,0x3f,0x15,0x15,0x16,0x16,0x15,0x15,0x15,0x16,0x15,0x15,
	0x15,0x16,0x00,0x00,0x00,0x00,0x00,0x15,0x00,0x00,0x15,0x00,0x0f,0xff,0xff,0xff,
	0xff,0xff,0x00,0x15,0x3f,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x16,0x15,0x15,
	0x15,0x3f,0x00,0x3f,0x3f,0x00,0x00,0x15,0x00,0x00,0x15,0x00,0x0f,0xff,0xff,0xff,
	0xff,0xff,0x00,0x3f,0x3f,0x15,0x15,0x16,0x15,0x15,0x15,0x16,0x15,0x15,0x16,0x15,
	0x3f,0x00,0x00,0x00,0x3f,0x00,0x00,0x15,0x00,0x0f,0x00,0x0f,0xff,0xff,0xff,0xff,
	0xff,0xff,0x00,0x00,0x15,0x3f,0x3f,0x15,0x16,0x15,0x16,0x15,0x15,0x15,0x15,0x00,
	0x00,0x00,0x00,0x00,0x16,0x00,0x00,0x15,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0x00,0x15,0x00,0x00,0x15,0x3f,0x3f,0x16,0x15,0x15,0x15,0x16,0x3f,0x00,
	0x3f,0x3f,0x00,0x00,0x15,0x00,0x00,0x15,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0x00,0x15,0x38,0x35,0x00,0x00,0x15,0x3f,0x3f,0x15,0x15,0x3f,0x00,0x00,
	0x00,0x3f,0x00,0x00,0x15,0x00,0x0f,0x00,0x0f,0x0e,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0x00,0x00,0x35,0x35,0xeb,0x2c,0x00,0x00,0x15,0x3f,0x3f,0x0e,0x0f,0x00,
	0x00,0x16,0x00,0x00,0x15,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0x00,0x00,0x2c,0x2c,0x15,0x15,0x00,0x00,0x15,0x0f,0x00,0x16,
	0x00,0x15,0x00,0x00,0x15,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x15,0x15,0x15,0x15,0x00,0x00,0x15,0x0f,
	0x00,0x15,0x00,0x0f,0x00,0x0f,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x15,0x15,0x15,0x00,0x0f,0x00,
	0x00,0x16,0x00,0x0e,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x15,0x0f,0x00,0x0f,
	0x00,0x15,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x0e,0x0f,
	0x0f,0x00,0x0f,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff } ;

//uchar	icon_disk_mini[B_MINI_ICON * B_MINI_ICON];
uchar icon_disk_mini [] = {
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x3f,0x15,0x00,0x00,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x3f,0x15,0x15,0x15,0x16,0x00,0x00,0xff,0xff,
	0xff,0xff,0xff,0xff,0x00,0x00,0x3f,0x15,0x15,0x15,0x16,0x15,0x15,0x15,0x00,0xff,
	0xff,0xff,0x00,0x00,0x00,0x3f,0x15,0x15,0x15,0x16,0x15,0x15,0x00,0x00,0x00,0xff,
	0xff,0xff,0x00,0x00,0x3f,0x15,0x15,0x15,0x16,0x15,0x15,0x3f,0x15,0x00,0x00,0xff,
	0xff,0xff,0x00,0x3f,0x15,0x15,0x15,0x16,0x16,0x15,0x00,0x00,0x08,0x00,0xff,0xff,
	0xff,0x00,0x3f,0x15,0x15,0x15,0x16,0x15,0x15,0x3f,0x15,0x00,0x00,0x00,0xff,0xff,
	0xff,0x00,0x3f,0x3f,0x15,0x16,0x15,0x15,0x00,0x00,0x08,0x00,0xff,0x00,0xff,0xff,
	0xff,0x00,0x0e,0x34,0x3f,0x3f,0x16,0x3f,0x15,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
	0xff,0xff,0x00,0x00,0x2a,0x0e,0x3f,0x0e,0x09,0x00,0xff,0x00,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0x00,0x00,0x0e,0x09,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff } ;

/* init_hardware - This function is called when the system is booted, which lets 
the driver detect and reset the hardware it controls. The function should return 
B_OK if the initialization is successful; otherwise, an appropriate error code 
should be returned. If this function returns an error, the driver won't be used. */

status_t init_hardware (void)
{ set_dprintf_enabled(true); dprintf("<<<< Init Hardware >>>>\n"); return B_OK; }

/* init_driver - optional function - called every time the driver is loaded. 
Drivers are loaded and unloaded on an as-needed basis. When a driver is loaded 
by devfs, this function is called to let the driver allocate memory and other 
needed system resources. Return B_OK if initialization succeeds, otherwise 
return an appropriate error code. <<<what happens if this returns an error?>>> */

status_t init_driver (void)
{ set_dprintf_enabled(true); dprintf("<<<< Init Driver >>>>\n");
  ram = create_ram_drive_area(RAM_DRIVE_SIZE);
  if (ram == NULL) { dprintf("<<<< Init Driver FAILED >>>>\n"); return B_ERROR; }
  dprintf("<<<< Init Driver OK >>>>\n"); return B_OK; }

/* uninit_driver - This function is called by devfs just before the driver is 
unloaded from memory. This lets the driver clean up after itself, freeing any 
resources it allocated. */

void uninit_driver(void)
{ set_dprintf_enabled(true); dprintf("<<<< UnInit Driver >>>>\n"); return; }

/* publish_devices - return a null-terminated array of devices supported by this 
driver.  Devfs calls publish_devices() to learn the names, relative to /dev, of 
the devices the driver supports. The driver should return a NULL-terminated array 
of strings indicating all the installed devices the driver supports. For example, 
an ethernet device driver might return: 
      static char *devices[] = { 
            "net/ether", 
            NULL 
      };
In this case, devfs will then create the pseudo-file /dev/net/ether, through 
which all user applications can access the driver.  Since only one instance of 
the driver will be loaded, if support for multiple devices of the same type is 
desired, the driver must be capable of supporting them. If the driver senses 
(and supports) two ethernet cards, it might return: 
      static char *devices[] = { 
            "net/ether1", 
            "net/ether2", 
            NULL 
       }; */

/* null-terminated array of device names supported by this driver */
static const char *my_device_name[] = { "disk/virtual/ram_drive", NULL } ;

const char** publish_devices(void)
{ set_dprintf_enabled(true); dprintf("<<<< Published RAMDrive Device >>>>\n"); 
  return my_device_name; }

/* api_version - This variable defines the API version to which the driver was 
written, and should be set to B_CUR_DRIVER_API_VERSION at compile time. The value 
of this variable will be changed with every revision to the driver API; the value 
with which your driver was compiled will tell devfs how it can communicate with 
the driver. */

int32 api_version = B_CUR_DRIVER_API_VERSION;

/* open_hook() - status_t open_hook(const char *name, uint32 flags, void **cookie) 
This hook function is called when a program opens one of the devices supported 
by the driver. The name of the device (as returned by publish_devices()) is 
passed in name, along with the flags passed to the Posix open() function. cookie 
points to space large enough for you to store a single pointer. You can use this 
to store state information specific to the open() instance. If you need to track 
information on a per-open() basis, allocate the memory you need and store a 
pointer to it in *cookie. */
/* my_device_open - handle open() calls */

static status_t my_device_open (const char *name, uint32 flags, void** cookie)
{ set_dprintf_enabled(true); dprintf("<<<< MY_Device_Open >>>>\n"); return B_OK; }

/* close_hook() - status_t close_hook(void **cookie) 
This hook is called when an open instance of the driver is closed using the close() 
Posix function. Note that because of the multithreaded nature of the BeOS, it's 
possible there may still be transactions pending, and you may receive more calls 
on the device. For that reason, you shouldn't free instance-wide system resources 
here.  Instead, you should do this in free_hook(). However, if there are any 
blocked transactions pending, you should unblock them here. */
/* my_device_close - handle close() calls */

static status_t my_device_close (void* cookie)
{ set_dprintf_enabled(true); dprintf("<<<< MY_Device_Closed >>>>\n"); return B_OK; }

/* free_hook() - status_t free_hook(void **cookie) 
This hook is called once all pending transactions on an open (but closing) instance 
of your driver are completed. This is where your driver should release instancewide 
system resources. free_hook() doesn't correspond to any Posix function. */
/* my_device_free - called after the last device is closed, and after all i/o is complete. */

static status_t my_device_free (void* cookie)
{ set_dprintf_enabled(true); dprintf("<<<< MY_Device_Free >>>>\n"); return B_OK; }

/* read_hook() - status_t read_hook(void *cookie, off_t position, void *data, size_t *len) 
This hook handles the Posix read() function for an open instance of your driver. 
Implement it to read len bytes of data starting at the specified byte position on the 
device, storing the read bytes at data. Exactly what this does is device-specific 
(disk devices would read from the specified offset on the disk, but a graphics driver 
might have some other interpretation of this request). Before returning, you should 
set len to the actual number of bytes read into the buffer. Return B_OK if data was 
read (even if the number of returned bytes is less than requested), otherwise return 
an appropriate error. */
/* my_device_read - handle read() calls */

static status_t my_device_read (void* cookie, off_t pos, void *buf, size_t* count)
{ size_t len; status_t ret = B_NO_ERROR;
  set_dprintf_enabled(true); dprintf("<<<< MY_Device_Read >>>>\n"); 
  if (pos >= RAM_DRIVE_SIZE)
     { len = 0; }
  else
	 { len = (pos + (*count) > RAM_DRIVE_SIZE) ? (RAM_DRIVE_SIZE - pos) : (*count); memcpy(buf, ram+pos, len); }
  *count = len; return ret; }

/* write_hook() - status_t write_hook(void *cookie, off_t position, void *data, size_t len) 
This hook handles the Posix write() function for an open instance of your driver. 
Implement it to write len bytes of data starting at the specified byte position on 
the device, from the buffer pointed to by data. Exactly what this does is device-
specific (disk devices would write to the specified offset on the disk, but a 
graphics driver might have some other interpretation of this request). Return B_OK 
if data was read (even if the number of returned bytes is less than requested), 
otherwise return an appropriate error. */ 
/* my_device_write - handle write() calls */

static status_t my_device_write (void* cookie, off_t pos, const void* buf, size_t* count)
{ size_t len;
  status_t ret = B_NO_ERROR;
  set_dprintf_enabled(true); dprintf("<<<< MY_Device_Write >>>>\n"); 
  if (pos >= RAM_DRIVE_SIZE)
     { len = 0; }
  else
     { len = (pos + (*count) > RAM_DRIVE_SIZE) ? (RAM_DRIVE_SIZE - pos) : (*count); memcpy(ram+pos, buf, len); }
  *count = len; return ret; }

/* readv_hook() - status_t readv_hook(void *cookie, off_t position, const struct iovec *vec, size_t count, size_t *len) 
This hook handles the Posix readv() function for an open instance of your driver. 
This is a scatter/gather read function; given an array of iovec structures describing 
address/length pairs for a group of destination buffers, your implementation should 
fill each successive buffer with bytes, up to a total of len bytes. The vec array has 
count items in it. As with read_hook(), set len to the actual number of bytes read, 
and return an appropriate result code. */

static status_t my_device_readv(void *cookie, off_t position, const iovec *vec, size_t count, size_t *len)
{ set_dprintf_enabled(true); dprintf("<<<< MY_Device_ReadV >>>>\n"); return B_OK; }

/* writev_hook() - status_t writev_hook(void *cookie, off_t position, const struct iovec *vec, size_t count, size_t *len) 
This hook handles the Posix writev() function for an open instance of your driver. 
This is a scatter/gather write function; given an array of iovec structures 
describing address/length pairs for a group of source buffers, your implementation 
should write each successive buffer to disk, up to a total of len bytes. The vec 
array has count items in it. Before returning, set len to the actual number of 
bytes written, and return an appropriate result code. */

static status_t my_device_writev(void *cookie, off_t position, const iovec *vec, size_t count, size_t *len)
{ set_dprintf_enabled(true); dprintf("<<<< MY_Device_WriteV >>>>\n"); return B_OK; }

/* control_hook() - status_t control_hook(void *cookie, uint32 op, void *data, size_t len) 
This hook handles the ioctl() function for an open instance of your driver. The 
control hook provides a means to perform operations that don't map directly to 
either read() or write(). It receives the cookie for the open instance, plus 
the command code op and the data and len arguments specified by ioctl()'s caller. 
These arguments have no inherent relationship; they're simply arguments to ioctl() 
that are forwarded to your hook function. Their definitions are defined by the 
driver. Common command codes can be found in be/drivers/Drivers.h.  The len 
argument is only valid when ioctl() is called from user space; the kernel always 
sets it to 0. */ 
/* my_device_control - handle ioctl calls */

static status_t my_device_control (void* cookie, uint32 msg, void* arg1, size_t len)
{ device_geometry *dinfo;
  set_dprintf_enabled(true); dprintf("<<<< MY_Device_Control >>>>\n"); 
  switch (msg) {
    case B_GET_GEOMETRY:
         dinfo = (device_geometry *) arg1;
         dinfo->sectors_per_track = RAM_DRIVE_SIZE/RAM_BLOCK_SIZE;
         dinfo->cylinder_count =    1;
         dinfo->head_count =        1;
         dinfo->bytes_per_sector =  RAM_BLOCK_SIZE;
         dinfo->removable =         FALSE ;
         dinfo->read_only =         FALSE;
         dinfo->device_type =       B_DISK;
         dinfo->write_once =        FALSE;	
         return B_NO_ERROR;

    case B_FORMAT_DEVICE:
         if (!*((char *) arg1))	return B_NO_ERROR;
         format_ram_drive(ram); return B_NO_ERROR;

	case B_GET_DEVICE_SIZE:
		*(size_t*)arg1 = RAM_DRIVE_SIZE; return B_NO_ERROR;

	case B_GET_ICON:
		switch (((device_icon *)arg1)->icon_size) {
		case 32: //B_LARGE_ICON * B_LARGE_ICON):
			 memcpy(((device_icon *)arg1)->icon_data, icon_disk, 32*32 ); break;
		case 16: //B_MINI_ICON * B_MINI_ICON):
             memcpy(((device_icon *)arg1)->icon_data, icon_disk_mini, 16*16 ); break;
		default: //B_LARGE_ICON * B_LARGE_ICON;
             memcpy(((device_icon *)arg1)->icon_data, icon_disk, 32*32 ); break;
        }
        return B_NO_ERROR;
	case RAM_DRIVE_RELEASE_MEMORY: // device specific IO control codes
		return delete_ram_drive_area(); 
	default:
		return B_ERROR;
	}
}

/* select_hook() , deselect_hook() */
/* These hooks are reserved for future use. Set the corresponding entries in your 
device_hooks structure to NULL. */

status_t my_device_select(void *cookie, uint8 event, uint32 ref, selectsync *sync) 
{ set_dprintf_enabled(true); dprintf("MY_Device_Select\n"); return B_OK; }

status_t my_device_deselect(void *cookie, uint8 event, selectsync *sync) 
{ set_dprintf_enabled(true); dprintf("MY_Device_DeSelect\n"); return B_OK; }

static void format_ram_drive(void* buf)
{ static const char format_str[16] = "RAM.drive.........";
  set_dprintf_enabled(true); dprintf("Format Drive\n");
  uchar* ptr = (uchar*)buf;
  off_t i;
  for (i=0; i<RAM_DRIVE_SIZE/16; i++) { memcpy(ptr, format_str, 16); ptr += 16; } }

static uchar* create_ram_drive_area(size_t drive_size)
{ void* addr;
  set_dprintf_enabled(true); dprintf("Create Ram Area\n");
  area_id area = find_area(ram_drive_area_name);
  if ( area == B_NAME_NOT_FOUND)
     { area = create_area (ram_drive_area_name, &addr, B_ANY_KERNEL_ADDRESS, /* kernel team will own this area */
              drive_size, B_LAZY_LOCK, B_READ_AREA | B_WRITE_AREA);
       if ( (area==B_ERROR) || (area==B_NO_MEMORY) || (area==B_BAD_VALUE) )
          { addr = NULL; }
	   else
	      { area_info info; get_area_info(area, &info); addr = info.address; }
}
  return (uchar*)addr;
}

static status_t delete_ram_drive_area(void)
{ area_id area = find_area(ram_drive_area_name);
  set_dprintf_enabled(true); dprintf("Delete Ram Area\n"); 
  if (area == B_NAME_NOT_FOUND) return B_ERROR; else return delete_area(area); }
  
/* Device Hooks - The hook functions specified in the device_hooks function returned 
by the driver's find_device() function handle requests made by devfs (and through 
devfs, from user applications). These are described in this section. 
The structure itself looks like this: 
      typedef struct { 
            device_open_hook open; 
            device_close_hook close; 
            device_free_hook free; 
            device_control_hook control; 
            device_read_hook read; 
            device_write_hook write; 
            device_select_hook select; 
            device_deselect_hook deselect; 
            device_readv_hook readv; 
            device_writev_hook writev; 
      } device_hooks;
In all cases, return B_OK if the operation is successfully completed, or an 
appropriate error code if not. */

/* function pointers for the device hooks entry points */
device_hooks my_device_hooks = {
	my_device_open,     /* -> open entry point */
	my_device_close,    /* -> close entry point */
	my_device_free,     /* -> free cookie */
	my_device_control,  /* -> control entry point */
	my_device_read,     /* -> read entry point */
	my_device_write,    /* -> write entry point */
	my_device_select,   /* -> select entry point */
	my_device_deselect, /* -> deselect entry point */
	my_device_readv,    /* -> posix read entry point */
	my_device_writev    /* -> posix write entry point */
};

/* find_device - return ptr to device hooks structure for a	given device name. 
When a device published by the driver is accessed, devfs communicates with it 
through a series of hook functions that handle the requests.The find_device() 
function is called to obtain a list of these hook functions, so that devfs can 
call them. The device_hooks structure returned lists out the hook functions. 
The device_hooks structure, and what each hook does, is described in the next 
section. */

device_hooks* find_device(const char* name)
{ return &my_device_hooks; }