Blame solaris_io/iop.c

Packit d36e9b
/*
Packit d36e9b
 * Driver for IO port access
Packit d36e9b
 *
Packit d36e9b
 * PC-DOS compatibility requirements:
Packit d36e9b
 *      Nearly all locations have defined values, see
Packit d36e9b
 *      the PC AT Hardware reference manual for details.
Packit d36e9b
 *
Packit d36e9b
 */
Packit d36e9b
Packit d36e9b
#include <sys/param.h>
Packit d36e9b
#include <sys/types.h>
Packit d36e9b
#include <sys/sysmacros.h>
Packit d36e9b
#if 0
Packit d36e9b
#include <sys/dir.h>
Packit d36e9b
#endif
Packit d36e9b
#include <sys/signal.h>
Packit d36e9b
#include <sys/systm.h>
Packit d36e9b
#include <sys/user.h>
Packit d36e9b
#include <sys/errno.h>
Packit d36e9b
#include <sys/file.h>
Packit d36e9b
#include <sys/modctl.h>
Packit d36e9b
#include <sys/open.h>
Packit d36e9b
#include <sys/stat.h>
Packit d36e9b
#include <sys/conf.h>
Packit d36e9b
#include <sys/cmn_err.h>
Packit d36e9b
#include <sys/ddi.h>
Packit d36e9b
#include <sys/sunddi.h>
Packit d36e9b
Packit d36e9b
static void *state_head;  /* opaque handle top of state structs */
Packit d36e9b
Packit d36e9b
/* Prototypes */
Packit d36e9b
Packit d36e9b
static int
Packit d36e9b
iopattach(dev_info_t *dip, ddi_attach_cmd_t cmd);
Packit d36e9b
Packit d36e9b
static int
Packit d36e9b
iopgetinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp);
Packit d36e9b
Packit d36e9b
static int 
Packit d36e9b
iopdetach(dev_info_t *dip, ddi_detach_cmd_t cmd);
Packit d36e9b
Packit d36e9b
static int
Packit d36e9b
iopopen(dev_t *devp, int flag, int otyp, cred_t *credp);
Packit d36e9b
Packit d36e9b
static int
Packit d36e9b
iopclose(dev_t dev, int openflags, int otyp, cred_t *credp);
Packit d36e9b
Packit d36e9b
static int
Packit d36e9b
iopioctl(dev_t dev, 
Packit d36e9b
         int cmd, 
Packit d36e9b
         intptr_t arg, 
Packit d36e9b
         int mode, 
Packit d36e9b
         cred_t *credp,
Packit d36e9b
         int *rvalp);
Packit d36e9b
Packit d36e9b
/* device operations */
Packit d36e9b
#define IOPREAD 1
Packit d36e9b
#define IOPWRITE 2
Packit d36e9b
Packit d36e9b
typedef struct iop_struct {         /* per-unit structure */
Packit d36e9b
    dev_info_t *dip;
Packit d36e9b
    kmutex_t mutex;
Packit d36e9b
} iop;
Packit d36e9b
Packit d36e9b
typedef struct iopbuf_struct{
Packit d36e9b
    unsigned int port;
Packit d36e9b
    unsigned char port_value;
Packit d36e9b
} iopbuf;
Packit d36e9b
Packit d36e9b
static struct cb_ops iop_cb_ops = {
Packit d36e9b
    iopopen,
Packit d36e9b
    iopclose,
Packit d36e9b
    nodev,                 /* not a block driver */
Packit d36e9b
    nodev,                 /* no print */
Packit d36e9b
    nodev,                 /* no dump */
Packit d36e9b
    nodev,                 /* no read */
Packit d36e9b
    nodev,                 /* no write */
Packit d36e9b
    iopioctl,
Packit d36e9b
    nodev,                 /* no devmap */
Packit d36e9b
    nodev,                 /* no mmap */
Packit d36e9b
    nodev,                 /* no segmap */
Packit d36e9b
    nochpoll,              /* no chpoll */
Packit d36e9b
    ddi_prop_op,
Packit d36e9b
    0,                     /* not a STREAMS driver */
Packit d36e9b
    D_NEW | D_MP,          /* (hopefully) MT and MP safe */
Packit d36e9b
};
Packit d36e9b
Packit d36e9b
static struct dev_ops iop_ops = 
Packit d36e9b
{
Packit d36e9b
    DEVO_REV,              /* devo_rev */
Packit d36e9b
    0,                     /* devo_refcnt */
Packit d36e9b
    iopgetinfo,            /* devo_getinfo */
Packit d36e9b
    nulldev,               /* devo_identify */
Packit d36e9b
    nulldev,               /* devo_probe */
Packit d36e9b
    iopattach,             /* devo_attach */
Packit d36e9b
    iopdetach,             /* devo_detach */
Packit d36e9b
    nodev,                 /* devo_reset */
Packit d36e9b
    &iop_cb_ops,           /* devo_cb_ops */
Packit d36e9b
    (struct bus_ops *)0,   /* devo_bus_ops */
Packit d36e9b
    nodev                  /* devo_power */
Packit d36e9b
};
Packit d36e9b
Packit d36e9b
extern struct mod_ops mod_driverops;
Packit d36e9b
Packit d36e9b
static struct modldrv modldrv = {
Packit d36e9b
    &mod_driverops,
Packit d36e9b
    "Simon's IO Port driver 0.9",
Packit d36e9b
    &iop_ops
Packit d36e9b
};
Packit d36e9b
    
Packit d36e9b
static struct modlinkage modlinkage = {
Packit d36e9b
    MODREV_1, 
Packit d36e9b
    {(void *)&modldrv, NULL,}
Packit d36e9b
};
Packit d36e9b
Packit d36e9b
/* Globally exported functions */
Packit d36e9b
int
Packit d36e9b
_init(void)
Packit d36e9b
{
Packit d36e9b
    int error;
Packit d36e9b
    
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
    cmn_err(CE_CONT, "_init: start\n");
Packit d36e9b
#endif
Packit d36e9b
    if ((error = ddi_soft_state_init(&state_head, sizeof(iop), 1)) != 0) {
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
        cmn_err(CE_CONT, "_init: couldn't ddi_soft_state_init\n");
Packit d36e9b
#endif
Packit d36e9b
        return error;
Packit d36e9b
    }
Packit d36e9b
    if ((error = mod_install(&modlinkage)) != 0) {
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
        cmn_err(CE_CONT, "_init: couldn't mod_install\n");
Packit d36e9b
#endif
Packit d36e9b
        ddi_soft_state_fini(&state_head);
Packit d36e9b
    }
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
    cmn_err(CE_CONT, "_init: done\n");
Packit d36e9b
#endif
Packit d36e9b
Packit d36e9b
    return error;
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
int
Packit d36e9b
_info(struct modinfo *modinfop)
Packit d36e9b
{
Packit d36e9b
    int retval;
Packit d36e9b
    
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
    cmn_err(CE_CONT, "_info: start\n");
Packit d36e9b
#endif
Packit d36e9b
    retval = mod_info(&modlinkage, modinfop);
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
    cmn_err(CE_CONT, "_info: done\n");
Packit d36e9b
#endif
Packit d36e9b
    return retval;
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
int
Packit d36e9b
_fini(void)
Packit d36e9b
{
Packit d36e9b
    int status;
Packit d36e9b
    
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
    cmn_err(CE_CONT, "_fini: start\n");
Packit d36e9b
#endif
Packit d36e9b
    if ((status = mod_remove(&modlinkage)) != 0) {
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
        cmn_err(CE_CONT, "_fini: couldn't mod_remove\n");
Packit d36e9b
#endif
Packit d36e9b
        return status;
Packit d36e9b
    }
Packit d36e9b
    ddi_soft_state_fini(&state_head);
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
    cmn_err(CE_CONT, "_fini: done\n");
Packit d36e9b
#endif
Packit d36e9b
    return status;
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
static int
Packit d36e9b
iopattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
Packit d36e9b
{
Packit d36e9b
    int instance;
Packit d36e9b
    iop *iop_p;
Packit d36e9b
    
Packit d36e9b
    switch(cmd) {
Packit d36e9b
    case DDI_ATTACH:
Packit d36e9b
        break;
Packit d36e9b
    default:
Packit d36e9b
        return DDI_FAILURE;
Packit d36e9b
    }
Packit d36e9b
    instance = ddi_get_instance(dip);
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
    cmn_err(CE_CONT, "iopattach: start, instance = %d\n", instance);
Packit d36e9b
#endif
Packit d36e9b
    if (ddi_soft_state_zalloc(state_head, instance) != 0) {
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
        cmn_err(CE_CONT, "iopattach: ddi_soft_state_zalloc failed\n");
Packit d36e9b
#endif
Packit d36e9b
        return DDI_FAILURE;
Packit d36e9b
    }
Packit d36e9b
    iop_p = (iop *)ddi_get_soft_state(state_head, instance);
Packit d36e9b
    ddi_set_driver_private(dip, (caddr_t)iop_p);
Packit d36e9b
    iop_p->dip = dip;
Packit d36e9b
    mutex_init(&iop_p->mutex, "iop mutex", MUTEX_DRIVER, (void *)0);
Packit d36e9b
    if (ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR, instance,
Packit d36e9b
                              DDI_PSEUDO, 0) == DDI_FAILURE)
Packit d36e9b
    {
Packit d36e9b
        mutex_destroy(&iop_p->mutex);
Packit d36e9b
        ddi_soft_state_free(state_head, instance);
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
        cmn_err(CE_CONT, "iopattach: ddi_create_minor_node failed\n");
Packit d36e9b
#endif
Packit d36e9b
        return DDI_FAILURE;
Packit d36e9b
    }
Packit d36e9b
    ddi_report_dev(dip);
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
    cmn_err(CE_CONT, "iopattach: done\n");
Packit d36e9b
#endif
Packit d36e9b
    return DDI_SUCCESS;
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
static int
Packit d36e9b
iopgetinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
Packit d36e9b
{
Packit d36e9b
    int error;
Packit d36e9b
    iop *iop_p;
Packit d36e9b
        
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
    cmn_err(CE_CONT, "iopgetinfo: start\n");
Packit d36e9b
#endif
Packit d36e9b
    switch(cmd) {
Packit d36e9b
    case DDI_INFO_DEVT2DEVINFO:
Packit d36e9b
        iop_p = (iop *)ddi_get_soft_state(state_head, 
Packit d36e9b
                                          getminor((dev_t)arg));
Packit d36e9b
        if (iop_p == NULL) {
Packit d36e9b
            *resultp = NULL;
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
            cmn_err(CE_CONT, "iopgetinfo: ddi_get_soft_state failed\n");
Packit d36e9b
#endif
Packit d36e9b
            error = DDI_FAILURE;
Packit d36e9b
        } else {
Packit d36e9b
            mutex_enter(&iop_p->mutex);
Packit d36e9b
            *resultp = iop_p->dip;
Packit d36e9b
            mutex_exit(&iop_p->mutex);
Packit d36e9b
            error = DDI_SUCCESS;
Packit d36e9b
        }
Packit d36e9b
        break;
Packit d36e9b
    case DDI_INFO_DEVT2INSTANCE:
Packit d36e9b
        *resultp = (void *)getminor((dev_t)arg);
Packit d36e9b
        error = DDI_SUCCESS;
Packit d36e9b
        break;
Packit d36e9b
    default:
Packit d36e9b
        *resultp = NULL;
Packit d36e9b
        return DDI_FAILURE;
Packit d36e9b
    }
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
    cmn_err(CE_CONT, "iopgetinfo: done\n");
Packit d36e9b
#endif
Packit d36e9b
    return error;
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
static int 
Packit d36e9b
iopdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
Packit d36e9b
{
Packit d36e9b
    iop *iop_p;
Packit d36e9b
    int instance;
Packit d36e9b
    
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
    cmn_err(CE_CONT, "iopdetach: start\n");
Packit d36e9b
#endif
Packit d36e9b
    switch(cmd) {
Packit d36e9b
    case DDI_DETACH:
Packit d36e9b
        break;
Packit d36e9b
    default:
Packit d36e9b
        return DDI_FAILURE;
Packit d36e9b
    }
Packit d36e9b
    
Packit d36e9b
    instance = ddi_get_instance(dip);
Packit d36e9b
    iop_p = (iop *)ddi_get_soft_state(state_head, instance);
Packit d36e9b
    ddi_remove_minor_node(dip, NULL);
Packit d36e9b
    mutex_destroy(&iop_p->mutex);
Packit d36e9b
    ddi_soft_state_free(state_head, instance);
Packit d36e9b
#ifdef DEBUG
Packit d36e9b
    cmn_err(CE_CONT, "iopdetach: done\n");
Packit d36e9b
#endif
Packit d36e9b
    return DDI_SUCCESS;
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
static int
Packit d36e9b
iopopen(dev_t *devp, int flag, int otyp, cred_t *credp)
Packit d36e9b
{
Packit d36e9b
    int retval = 0;
Packit d36e9b
    iop *iop_p;
Packit d36e9b
    
Packit d36e9b
    iop_p = (iop *)ddi_get_soft_state(state_head, getminor(*devp));
Packit d36e9b
    
Packit d36e9b
    if (iop_p == NULL) {
Packit d36e9b
        return ENXIO;
Packit d36e9b
    }
Packit d36e9b
    
Packit d36e9b
    if (otyp != OTYP_CHR) {
Packit d36e9b
        return EINVAL;
Packit d36e9b
    }
Packit d36e9b
  
Packit d36e9b
    if ((flag & FWRITE) &&
Packit d36e9b
        (drv_priv(credp) != 0)) 
Packit d36e9b
    {
Packit d36e9b
        retval = EACCES;
Packit d36e9b
    } else {
Packit d36e9b
        retval = 0;
Packit d36e9b
    }
Packit d36e9b
    return retval;
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
static int
Packit d36e9b
iopclose(dev_t dev, int openflags, int otyp, cred_t *credp)
Packit d36e9b
{
Packit d36e9b
    iop *iop_p;
Packit d36e9b
    
Packit d36e9b
    iop_p = (iop *)ddi_get_soft_state(state_head, getminor(dev));
Packit d36e9b
    return 0;
Packit d36e9b
}
Packit d36e9b
Packit d36e9b
/* cmd should be IOPREAD or IOPWRITE
Packit d36e9b
   arg is the address (of the io port)
Packit d36e9b
   */
Packit d36e9b
int
Packit d36e9b
iopioctl(dev_t dev, 
Packit d36e9b
         int cmd, 
Packit d36e9b
         intptr_t arg, 
Packit d36e9b
         int mode, 
Packit d36e9b
         cred_t *credp,
Packit d36e9b
         int *rvalp)
Packit d36e9b
{
Packit d36e9b
    iop *iop_p;
Packit d36e9b
    int retval = 0;
Packit d36e9b
    iopbuf tmpbuf;
Packit d36e9b
    
Packit d36e9b
    iop_p = (iop *)ddi_get_soft_state(state_head, getminor(dev));
Packit d36e9b
Packit d36e9b
    /* we will have to check privileges once we do writes */
Packit d36e9b
    switch (cmd) {
Packit d36e9b
    case IOPREAD:
Packit d36e9b
        mutex_enter(&iop_p->mutex);
Packit d36e9b
        if (ddi_copyin((caddr_t)arg, 
Packit d36e9b
                       (caddr_t)&tmpbuf, 
Packit d36e9b
                       sizeof(tmpbuf),
Packit d36e9b
                       mode)) 
Packit d36e9b
        {
Packit d36e9b
            retval = EFAULT;
Packit d36e9b
        } else {
Packit d36e9b
            tmpbuf.port_value = inb(tmpbuf.port);
Packit d36e9b
            ddi_copyout((caddr_t)&tmpbuf.port_value, 
Packit d36e9b
                        (caddr_t)(arg+sizeof(tmpbuf.port)),
Packit d36e9b
                        sizeof(tmpbuf.port),
Packit d36e9b
                        mode);
Packit d36e9b
        }
Packit d36e9b
        mutex_exit(&iop_p->mutex);
Packit d36e9b
        break;
Packit d36e9b
    case IOPWRITE:
Packit d36e9b
        mutex_enter(&iop_p->mutex);
Packit d36e9b
        if (ddi_copyin((caddr_t)arg,
Packit d36e9b
                       (caddr_t)&tmpbuf,
Packit d36e9b
                       sizeof(tmpbuf),
Packit d36e9b
                       mode)) 
Packit d36e9b
        {
Packit d36e9b
            retval = EFAULT;
Packit d36e9b
        } else {
Packit d36e9b
            outb(tmpbuf.port,tmpbuf.port_value);
Packit d36e9b
        }
Packit d36e9b
        mutex_exit(&iop_p->mutex);
Packit d36e9b
        break;
Packit d36e9b
    default:
Packit d36e9b
        retval = EINVAL;
Packit d36e9b
        break;
Packit d36e9b
    }
Packit d36e9b
    return retval;
Packit d36e9b
    
Packit d36e9b
}