#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/modctl.h>
#include <sys/sunddi.h>
#include <sys/cmn_err.h>
#include <sys/types.h>
#include <sys/ddi_impldefs.h>
#include <sys/1394/t1394.h>
#include <sys/1394/s1394.h>
#include <sys/1394/h1394.h>
static int nx1394_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
ddi_dma_attr_t *attr, int (*waitfnp)(caddr_t), caddr_t arg,
ddi_dma_handle_t *handlep);
static int nx1394_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op,
void *arg, void *result);
static int nx1394_get_event_cookie(dev_info_t *dip, dev_info_t *rdip,
char *name, ddi_eventcookie_t *event_cookiep);
static int nx1394_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
ddi_eventcookie_t eventhdl, void (*callback)(), void *arg,
ddi_callback_id_t *cb_id);
static int nx1394_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id);
static int nx1394_post_event(dev_info_t *dip, dev_info_t *rdip,
ddi_eventcookie_t eventhdl, void *impl_data);
struct bus_ops nx1394_busops = {
BUSO_REV,
nullbusmap,
NULL,
NULL,
NULL,
i_ddi_map_fault,
NULL,
nx1394_dma_allochdl,
ddi_dma_freehdl,
ddi_dma_bindhdl,
ddi_dma_unbindhdl,
ddi_dma_flush,
ddi_dma_win,
ddi_dma_mctl,
nx1394_bus_ctl,
ddi_bus_prop_op,
nx1394_get_event_cookie,
nx1394_add_eventcall,
nx1394_remove_eventcall,
nx1394_post_event,
0,
0,
0,
0,
0,
0,
0,
0,
i_ddi_intr_ops
};
#define NX1394_EVENT_TAG_HOT_REMOVAL 0
#define NX1394_EVENT_TAG_HOT_INSERTION 1
#define NX1394_EVENT_TAG_BUS_RESET 2
static ndi_event_definition_t nx1394_event_defs[] = {
{NX1394_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL,
NDI_EVENT_POST_TO_TGT},
{NX1394_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL,
NDI_EVENT_POST_TO_TGT},
{NX1394_EVENT_TAG_BUS_RESET, DDI_DEVI_BUS_RESET_EVENT, EPL_KERNEL,
NDI_EVENT_POST_TO_ALL},
};
#define NX1394_N_EVENTS \
(sizeof (nx1394_event_defs) / sizeof (ndi_event_definition_t))
static ndi_event_set_t nx1394_events = {
NDI_EVENTS_REV1, NX1394_N_EVENTS, nx1394_event_defs
};
static int
nx1394_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg,
void *result)
{
int status;
switch (op) {
case DDI_CTLOPS_REPORTDEV: {
dev_info_t *pdip = ddi_get_parent(rdip);
cmn_err(CE_CONT, "?%s%d at %s%d",
ddi_node_name(rdip), ddi_get_instance(rdip),
ddi_node_name(pdip), ddi_get_instance(pdip));
return (DDI_SUCCESS);
}
case DDI_CTLOPS_INITCHILD: {
dev_info_t *ocdip, *cdip = (dev_info_t *)arg;
dev_info_t *pdip = ddi_get_parent(cdip);
int reglen, i;
uint32_t *regptr;
char addr[MAXNAMELEN];
i = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
DDI_PROP_DONTPASS, "reg", (int **)®ptr,
(uint_t *)®len);
if (i != DDI_PROP_SUCCESS) {
cmn_err(CE_NOTE, "!%s(%d): \"reg\" property not found",
ddi_node_name(cdip), ddi_get_instance(cdip));
return (DDI_NOT_WELL_FORMED);
}
ASSERT(reglen != 0);
if (regptr[2] || regptr[3]) {
(void) sprintf(addr, "%08x%08x,%04x%08x", regptr[0],
regptr[1], regptr[2], regptr[3]);
} else {
(void) sprintf(addr, "%08x%08x", regptr[0], regptr[1]);
}
ddi_prop_free(regptr);
ddi_set_name_addr(cdip, addr);
if ((ocdip = ndi_devi_find(pdip, ddi_node_name(cdip), addr)) !=
NULL && ocdip != cdip) {
cmn_err(CE_NOTE,
"!%s(%d): Duplicate dev_info node found %s@%s",
ddi_node_name(cdip), ddi_get_instance(cdip),
ddi_node_name(ocdip), addr);
ddi_set_name_addr(cdip, NULL);
return (DDI_NOT_WELL_FORMED);
}
if (ddi_prop_exists(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
"active-dma-flush") != 0) {
status = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
"active-dma-flush", 1);
if (status != NDI_SUCCESS) {
cmn_err(CE_NOTE, "!%s(%d): Unable to add "
"\"active-dma-flush\" property",
ddi_node_name(cdip),
ddi_get_instance(cdip));
ddi_set_name_addr(cdip, NULL);
return (DDI_NOT_WELL_FORMED);
}
}
return (DDI_SUCCESS);
}
case DDI_CTLOPS_UNINITCHILD: {
ddi_prop_remove_all((dev_info_t *)arg);
ddi_set_name_addr((dev_info_t *)arg, NULL);
return (DDI_SUCCESS);
}
case DDI_CTLOPS_IOMIN: {
status = ddi_ctlops(dip, rdip, op, arg, result);
return (status);
}
case DDI_CTLOPS_POWER: {
return (DDI_SUCCESS);
}
case DDI_CTLOPS_DMAPMAPC:
case DDI_CTLOPS_REPORTINT:
case DDI_CTLOPS_REGSIZE:
case DDI_CTLOPS_NREGS:
case DDI_CTLOPS_SIDDEV:
case DDI_CTLOPS_SLAVEONLY:
case DDI_CTLOPS_AFFINITY:
case DDI_CTLOPS_POKE:
case DDI_CTLOPS_PEEK: {
cmn_err(CE_CONT, "!%s(%d): invalid op (%d) from %s(%d)",
ddi_node_name(dip), ddi_get_instance(dip),
op, ddi_node_name(rdip), ddi_get_instance(rdip));
return (DDI_FAILURE);
}
default: {
status = ddi_ctlops(dip, rdip, op, arg, result);
return (status);
}
}
}
static int
nx1394_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
int (*waitfnp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
{
s1394_hal_t *hal;
ddi_dma_attr_t *hal_attr;
int status;
_NOTE(SCHEME_PROTECTS_DATA("unique (per thread)", ddi_dma_attr_t))
if (dip != rdip) {
hal = s1394_dip_to_hal(ddi_get_parent(rdip));
ASSERT(hal);
hal_attr = &hal->halinfo.dma_attr;
ASSERT(hal_attr);
ddi_dma_attr_merge(attr, hal_attr);
}
status = ddi_dma_allochdl(dip, rdip, attr, waitfnp, arg, handlep);
return (status);
}
static int
nx1394_get_event_cookie(dev_info_t *dip, dev_info_t *rdip, char *name,
ddi_eventcookie_t *event_cookiep)
{
int ret;
s1394_hal_t *hal;
hal = s1394_dip_to_hal(dip);
ASSERT(hal);
ret = ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl,
rdip, name, event_cookiep, 0);
return (ret);
}
static int
nx1394_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
ddi_eventcookie_t cookie, void (*callback)(), void *arg,
ddi_callback_id_t *cb_id)
{
int ret;
s1394_hal_t *hal;
#if defined(DEBUG)
char *event_name = NULL;
#endif
hal = s1394_dip_to_hal(dip);
ASSERT(hal);
ret = ndi_event_add_callback(hal->hal_ndi_event_hdl, rdip, cookie,
callback, arg, NDI_NOSLEEP, cb_id);
#if defined(DEBUG)
event_name = ndi_event_cookie_to_name(hal->hal_ndi_event_hdl, cookie);
if (event_name == NULL)
event_name = "";
#endif
return (ret);
}
static int
nx1394_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
{
int ret;
s1394_hal_t *hal;
ddi_eventcookie_t cookie;
#if defined(DEBUG)
char *event_name = NULL;
#endif
ASSERT(cb_id);
cookie = ((ndi_event_callbacks_t *)cb_id)->ndi_evtcb_cookie;
hal = s1394_dip_to_hal(dip);
ASSERT(hal);
ret = ndi_event_remove_callback(hal->hal_ndi_event_hdl, cb_id);
#if defined(DEBUG)
event_name = ndi_event_cookie_to_name(hal->hal_ndi_event_hdl, cookie);
if (event_name == NULL)
event_name = "";
#endif
return (ret);
}
static int
nx1394_post_event(dev_info_t *dip, dev_info_t *rdip, ddi_eventcookie_t cookie,
void *impl_data)
{
int ret;
char *name;
s1394_hal_t *hal;
t1394_localinfo_t localinfo;
hal = s1394_dip_to_hal(dip);
ASSERT(hal);
name = ndi_event_cookie_to_name(hal->hal_ndi_event_hdl, cookie);
if (name != NULL) {
mutex_enter(&hal->topology_tree_mutex);
localinfo.bus_generation = hal->generation_count;
localinfo.local_nodeID = hal->node_id;
mutex_exit(&hal->topology_tree_mutex);
impl_data = &localinfo;
ret = ndi_event_run_callbacks(hal->hal_ndi_event_hdl,
rdip, cookie, impl_data);
return (ret);
} else {
ret = ndi_post_event(ddi_get_parent(dip), rdip, cookie,
impl_data);
return (ret);
}
}
int
nx1394_define_events(s1394_hal_t *hal)
{
int ret;
ret = ndi_event_alloc_hdl(hal->halinfo.dip, hal->halinfo.hw_interrupt,
&hal->hal_ndi_event_hdl, NDI_SLEEP);
if (ret == NDI_SUCCESS) {
ret = ndi_event_bind_set(hal->hal_ndi_event_hdl, &nx1394_events,
NDI_SLEEP);
if (ret != NDI_SUCCESS) {
(void) ndi_event_free_hdl(hal->hal_ndi_event_hdl);
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
void
nx1394_undefine_events(s1394_hal_t *hal)
{
int ret;
ret = ndi_event_unbind_set(hal->hal_ndi_event_hdl, &nx1394_events,
NDI_SLEEP);
if (ret == NDI_SUCCESS)
ret = ndi_event_free_hdl(hal->hal_ndi_event_hdl);
}