#include <sys/types.h>
#include <sys/conf.h>
#include <sys/kmem.h>
#include <sys/async.h>
#include <sys/sysmacros.h>
#include <sys/sunddi.h>
#include <sys/sunndi.h>
#include <sys/ddi_impldefs.h>
#include <sys/open.h>
#include <sys/errno.h>
#include <sys/file.h>
#include <sys/policy.h>
#include "px_obj.h"
#include <sys/pci_tools.h>
#include "px_tools_ext.h"
#include <sys/pcie_pwr.h>
static int px_open(dev_t *devp, int flags, int otyp, cred_t *credp);
static int px_close(dev_t dev, int flags, int otyp, cred_t *credp);
static int px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
cred_t *credp, int *rvalp);
struct cb_ops px_cb_ops = {
px_open,
px_close,
nodev,
nodev,
nodev,
nodev,
nodev,
px_ioctl,
nodev,
nodev,
nodev,
nochpoll,
pcie_prop_op,
NULL,
D_NEW | D_MP | D_HOTPLUG,
CB_REV,
nodev,
nodev
};
static int
px_open(dev_t *devp, int flags, int otyp, cred_t *credp)
{
px_t *px_p = PX_DEV_TO_SOFTSTATE(*devp);
int minor = getminor(*devp);
int rval;
if (otyp != OTYP_CHR)
return (EINVAL);
if (px_p == NULL)
return (ENXIO);
DBG(DBG_OPEN, px_p->px_dip, "devp=%x: flags=%x\n", devp, flags);
mutex_enter(&px_p->px_mutex);
switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
case PCI_TOOL_REG_MINOR_NUM:
case PCI_TOOL_INTR_MINOR_NUM:
break;
default:
if (rval = pcie_open(px_p->px_dip, devp, flags, otyp, credp)) {
mutex_exit(&px_p->px_mutex);
return (rval);
}
}
if (flags & FEXCL) {
if (px_p->px_soft_state != PCI_SOFT_STATE_CLOSED) {
mutex_exit(&px_p->px_mutex);
DBG(DBG_OPEN, px_p->px_dip, "busy\n");
return (EBUSY);
}
px_p->px_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
} else {
if (px_p->px_soft_state == PCI_SOFT_STATE_OPEN_EXCL) {
mutex_exit(&px_p->px_mutex);
DBG(DBG_OPEN, px_p->px_dip, "busy\n");
return (EBUSY);
}
px_p->px_soft_state = PCI_SOFT_STATE_OPEN;
}
mutex_exit(&px_p->px_mutex);
return (0);
}
static int
px_close(dev_t dev, int flags, int otyp, cred_t *credp)
{
px_t *px_p = PX_DEV_TO_SOFTSTATE(dev);
int minor = getminor(dev);
int rval;
if (otyp != OTYP_CHR)
return (EINVAL);
if (px_p == NULL)
return (ENXIO);
DBG(DBG_CLOSE, px_p->px_dip, "dev=%x: flags=%x\n", dev, flags);
mutex_enter(&px_p->px_mutex);
switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
case PCI_TOOL_REG_MINOR_NUM:
case PCI_TOOL_INTR_MINOR_NUM:
break;
default:
if (rval = pcie_close(px_p->px_dip, dev, flags, otyp, credp)) {
mutex_exit(&px_p->px_mutex);
return (rval);
}
}
px_p->px_soft_state = PCI_SOFT_STATE_CLOSED;
mutex_exit(&px_p->px_mutex);
return (0);
}
static int
px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
{
px_t *px_p = PX_DEV_TO_SOFTSTATE(dev);
int minor = getminor(dev);
dev_info_t *dip;
int rv = ENOTTY;
if (px_p == NULL)
return (ENXIO);
dip = px_p->px_dip;
DBG(DBG_IOCTL, dip, "dev=%x: cmd=%x\n", dev, cmd);
#ifdef PX_DMA_TEST
if (IS_DMATEST(cmd)) {
*rvalp = px_dma_test(cmd, dip, px_p, arg);
return (0);
}
#endif
switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
case PCI_TOOL_REG_MINOR_NUM:
switch (cmd) {
case PCITOOL_DEVICE_SET_REG:
case PCITOOL_DEVICE_GET_REG:
if (secpolicy_kmdb(credp))
rv = EPERM;
else
rv = pxtool_dev_reg_ops(dip,
(void *)arg, cmd, mode);
break;
case PCITOOL_NEXUS_SET_REG:
case PCITOOL_NEXUS_GET_REG:
if (secpolicy_kmdb(credp))
rv = EPERM;
else
rv = pxtool_bus_reg_ops(dip,
(void *)arg, cmd, mode);
break;
default:
rv = ENOTTY;
}
return (rv);
case PCI_TOOL_INTR_MINOR_NUM:
switch (cmd) {
case PCITOOL_DEVICE_SET_INTR:
if (secpolicy_kmdb(credp)) {
rv = EPERM;
break;
}
case PCITOOL_DEVICE_GET_INTR:
case PCITOOL_SYSTEM_INTR_INFO:
rv = pxtool_intr(dip, (void *)arg, cmd, mode);
break;
default:
rv = ENOTTY;
}
return (rv);
default:
rv = pcie_ioctl(dip, dev, cmd, arg, mode, credp, rvalp);
break;
}
if ((cmd & ~PPMREQ_MASK) == PPMREQ) {
if (drv_priv(credp)) {
DBG(DBG_TOOLS, dip,
"px_tools: Insufficient privileges\n");
return (EPERM);
}
return (px_lib_pmctl(cmd, px_p));
}
return (rv);
}