e1d867b686
This patch adds support for executing multiple concurrent requests on different devices on the same AHCI controller. The libdriver library has been extended to include a generic multithreading interface, and the AHCI driver has been extended to make use of this interface. The original version of this code has been written by Arne Welzel.
210 lines
4.9 KiB
C
210 lines
4.9 KiB
C
#include <minix/drivers.h>
|
|
#include <minix/driver.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <minix/ds.h>
|
|
#include "hello.h"
|
|
|
|
/*
|
|
* Function prototypes for the hello driver.
|
|
*/
|
|
FORWARD _PROTOTYPE( char * hello_name, (void) );
|
|
FORWARD _PROTOTYPE( int hello_open, (struct driver *d, message *m) );
|
|
FORWARD _PROTOTYPE( int hello_close, (struct driver *d, message *m) );
|
|
FORWARD _PROTOTYPE( struct device * hello_prepare, (int device) );
|
|
FORWARD _PROTOTYPE( int hello_transfer, (int procnr, int opcode,
|
|
u64_t position, iovec_t *iov,
|
|
unsigned nr_req) );
|
|
FORWARD _PROTOTYPE( void hello_geometry, (struct partition *entry) );
|
|
|
|
/* SEF functions and variables. */
|
|
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
|
|
FORWARD _PROTOTYPE( int sef_cb_init, (int type, sef_init_info_t *info) );
|
|
FORWARD _PROTOTYPE( int sef_cb_lu_state_save, (int) );
|
|
FORWARD _PROTOTYPE( int lu_state_restore, (void) );
|
|
|
|
/* Entry points to the hello driver. */
|
|
PRIVATE struct driver hello_tab =
|
|
{
|
|
hello_name,
|
|
hello_open,
|
|
hello_close,
|
|
nop_ioctl,
|
|
hello_prepare,
|
|
hello_transfer,
|
|
nop_cleanup,
|
|
hello_geometry,
|
|
nop_alarm,
|
|
nop_cancel,
|
|
nop_select,
|
|
nop_ioctl,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
/** Represents the /dev/hello device. */
|
|
PRIVATE struct device hello_device;
|
|
|
|
/** State variable to count the number of times the device has been opened. */
|
|
PRIVATE int open_counter;
|
|
|
|
PRIVATE char * hello_name(void)
|
|
{
|
|
printf("hello_name()\n");
|
|
return "hello";
|
|
}
|
|
|
|
PRIVATE int hello_open(d, m)
|
|
struct driver *d;
|
|
message *m;
|
|
{
|
|
printf("hello_open(). Called %d time(s).\n", ++open_counter);
|
|
return OK;
|
|
}
|
|
|
|
PRIVATE int hello_close(d, m)
|
|
struct driver *d;
|
|
message *m;
|
|
{
|
|
printf("hello_close()\n");
|
|
return OK;
|
|
}
|
|
|
|
PRIVATE struct device * hello_prepare(dev)
|
|
int dev;
|
|
{
|
|
hello_device.dv_base = make64(0, 0);
|
|
hello_device.dv_size = make64(strlen(HELLO_MESSAGE), 0);
|
|
return &hello_device;
|
|
}
|
|
|
|
PRIVATE int hello_transfer(proc_nr, opcode, position, iov, nr_req)
|
|
int proc_nr;
|
|
int opcode;
|
|
u64_t position;
|
|
iovec_t *iov;
|
|
unsigned nr_req;
|
|
{
|
|
int bytes, ret;
|
|
|
|
printf("hello_transfer()\n");
|
|
|
|
bytes = strlen(HELLO_MESSAGE) - ex64lo(position) < iov->iov_size ?
|
|
strlen(HELLO_MESSAGE) - ex64lo(position) : iov->iov_size;
|
|
|
|
if (bytes <= 0)
|
|
{
|
|
return OK;
|
|
}
|
|
switch (opcode)
|
|
{
|
|
case DEV_GATHER_S:
|
|
ret = sys_safecopyto(proc_nr, iov->iov_addr, 0,
|
|
(vir_bytes) (HELLO_MESSAGE + ex64lo(position)),
|
|
bytes, D);
|
|
iov->iov_size -= bytes;
|
|
break;
|
|
|
|
default:
|
|
return EINVAL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
PRIVATE void hello_geometry(entry)
|
|
struct partition *entry;
|
|
{
|
|
printf("hello_geometry()\n");
|
|
entry->cylinders = 0;
|
|
entry->heads = 0;
|
|
entry->sectors = 0;
|
|
}
|
|
|
|
PRIVATE int sef_cb_lu_state_save(int state) {
|
|
/* Save the state. */
|
|
ds_publish_u32("open_counter", open_counter, DSF_OVERWRITE);
|
|
|
|
return OK;
|
|
}
|
|
|
|
PRIVATE int lu_state_restore() {
|
|
/* Restore the state. */
|
|
u32_t value;
|
|
|
|
ds_retrieve_u32("open_counter", &value);
|
|
ds_delete_u32("open_counter");
|
|
open_counter = (int) value;
|
|
|
|
return OK;
|
|
}
|
|
|
|
PRIVATE void sef_local_startup()
|
|
{
|
|
/*
|
|
* Register init callbacks. Use the same function for all event types
|
|
*/
|
|
sef_setcb_init_fresh(sef_cb_init);
|
|
sef_setcb_init_lu(sef_cb_init);
|
|
sef_setcb_init_restart(sef_cb_init);
|
|
|
|
/*
|
|
* Register live update callbacks.
|
|
*/
|
|
/* - Agree to update immediately when LU is requested in a valid state. */
|
|
sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
|
|
/* - Support live update starting from any standard state. */
|
|
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
|
|
/* - Register a custom routine to save the state. */
|
|
sef_setcb_lu_state_save(sef_cb_lu_state_save);
|
|
|
|
/* Let SEF perform startup. */
|
|
sef_startup();
|
|
}
|
|
|
|
PRIVATE int sef_cb_init(int type, sef_init_info_t *info)
|
|
{
|
|
/* Initialize the hello driver. */
|
|
int do_announce_driver = TRUE;
|
|
|
|
open_counter = 0;
|
|
switch(type) {
|
|
case SEF_INIT_FRESH:
|
|
printf("%s", HELLO_MESSAGE);
|
|
break;
|
|
|
|
case SEF_INIT_LU:
|
|
/* Restore the state. */
|
|
lu_state_restore();
|
|
do_announce_driver = FALSE;
|
|
|
|
printf("%sHey, I'm a new version!\n", HELLO_MESSAGE);
|
|
break;
|
|
|
|
case SEF_INIT_RESTART:
|
|
printf("%sHey, I've just been restarted!\n", HELLO_MESSAGE);
|
|
break;
|
|
}
|
|
|
|
/* Announce we are up when necessary. */
|
|
if (do_announce_driver) {
|
|
driver_announce();
|
|
}
|
|
|
|
/* Initialization completed successfully. */
|
|
return OK;
|
|
}
|
|
|
|
PUBLIC int main(int argc, char **argv)
|
|
{
|
|
/*
|
|
* Perform initialization.
|
|
*/
|
|
sef_local_startup();
|
|
|
|
/*
|
|
* Run the main loop.
|
|
*/
|
|
driver_task(&hello_tab, DRIVER_STD);
|
|
return OK;
|
|
}
|
|
|