#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/modctl.h>
#include <sys/stat.h>
#include <sys/sunddi.h>
#include <sys/cmn_err.h>
#include <sys/kmem.h>
#include <sys/1394/adapters/hci1394.h>
#define VENDOR_ALIGN_ADDR(addr) (addr & 0x7FC)
int hci1394_set_rio_guid = 0;
static int hci1394_rio_init(hci1394_vendor_t *vendor);
static void hci1394_rio_guid_init(hci1394_vendor_t *vendor);
static int hci1394_rio_resume(hci1394_vendor_t *vendor);
int
hci1394_vendor_init(hci1394_drvinfo_t *drvinfo, hci1394_ohci_handle_t ohci,
hci1394_vendor_info_t *vendor_info, hci1394_vendor_handle_t *vendor_handle)
{
int status;
hci1394_vendor_t *vendor;
ASSERT(drvinfo != NULL);
ASSERT(vendor_info != NULL);
ASSERT(vendor_handle != NULL);
vendor = kmem_alloc(sizeof (hci1394_vendor_t), KM_SLEEP);
vendor->ve_info = *vendor_info;
vendor->ve_drvinfo = drvinfo;
vendor->ve_ohci = ohci;
*vendor_handle = vendor;
switch (vendor_info->vendor_id) {
case VENDOR_VID_SUN_MICROSYSTEMS:
switch (vendor_info->device_id) {
case VENDOR_DID_RIO_1394:
status = hci1394_rio_init(vendor);
if (status != DDI_SUCCESS) {
kmem_free(vendor,
sizeof (hci1394_vendor_t));
*vendor_handle = NULL;
return (DDI_FAILURE);
}
break;
default:
vendor->ve_reg_count = 0;
break;
}
break;
default:
vendor->ve_reg_count = 0;
break;
}
vendor_info->vendor_reg_count = vendor->ve_reg_count;
return (DDI_SUCCESS);
}
void
hci1394_vendor_fini(hci1394_vendor_handle_t *vendor_handle)
{
uint_t index;
ASSERT(vendor_handle != NULL);
for (index = 0; index < (*vendor_handle)->ve_reg_count; index++) {
ddi_regs_map_free(&(*vendor_handle)->
ve_reg_array[index]->vr_reg_handle);
}
kmem_free(*vendor_handle, sizeof (hci1394_vendor_t));
*vendor_handle = NULL;
}
int
hci1394_vendor_resume(hci1394_vendor_handle_t vendor_handle)
{
int status;
hci1394_vendor_info_t *vendor_info;
ASSERT(vendor_handle != NULL);
vendor_info = &vendor_handle->ve_info;
switch (vendor_info->vendor_id) {
case VENDOR_VID_SUN_MICROSYSTEMS:
switch (vendor_info->device_id) {
case VENDOR_DID_RIO_1394:
status = hci1394_rio_resume(vendor_handle);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
break;
default:
break;
}
break;
default:
break;
}
return (DDI_SUCCESS);
}
int
hci1394_vendor_reg_write(hci1394_vendor_handle_t vendor_handle,
uint_t reg_set, uint_t offset, uint32_t data)
{
hci1394_vendor_reg_t *venreg;
uint32_t *regaddr;
ASSERT(vendor_handle != NULL);
if (vendor_handle->ve_reg_count < (reg_set + 1)) {
return (DDI_FAILURE);
}
venreg = vendor_handle->ve_reg_array[reg_set];
regaddr = (uint32_t *)((uintptr_t)venreg->vr_reg_addr +
(uintptr_t)VENDOR_ALIGN_ADDR(offset));
ddi_put32(venreg->vr_reg_handle, regaddr, data);
return (DDI_SUCCESS);
}
int
hci1394_vendor_reg_read(hci1394_vendor_handle_t vendor_handle, uint_t reg_set,
uint_t offset, uint32_t *data)
{
hci1394_vendor_reg_t *venreg;
uint32_t *regaddr;
ASSERT(vendor_handle != NULL);
ASSERT(data != NULL);
if (vendor_handle->ve_reg_count < (reg_set + 1)) {
return (DDI_FAILURE);
}
venreg = vendor_handle->ve_reg_array[reg_set];
regaddr = (uint32_t *)((uintptr_t)venreg->vr_reg_addr +
(uintptr_t)VENDOR_ALIGN_ADDR(offset));
*data = ddi_get32(venreg->vr_reg_handle, regaddr);
return (DDI_SUCCESS);
}
static int
hci1394_rio_init(hci1394_vendor_t *vendor)
{
int status;
ASSERT(vendor != NULL);
vendor->ve_reg_count = 1;
vendor->ve_reg_array[0] = kmem_alloc(sizeof (hci1394_vendor_reg_t),
KM_SLEEP);
status = ddi_regs_map_setup(vendor->ve_drvinfo->di_dip, RIOREG_REG_BASE,
&vendor->ve_reg_array[0]->vr_reg_addr, RIOREG_OFFSET, RIOREG_LENGTH,
&vendor->ve_drvinfo->di_reg_attr,
&vendor->ve_reg_array[0]->vr_reg_handle);
if (status != DDI_SUCCESS) {
vendor->ve_reg_count = 0;
kmem_free(vendor->ve_reg_array[0],
sizeof (hci1394_vendor_reg_t));
return (DDI_FAILURE);
}
status = hci1394_vendor_reg_write(vendor, 0, RIOREG_HOST_CONTROL,
RIOREG_HOST_CONTROL_SETTING);
if (status != DDI_SUCCESS) {
ddi_regs_map_free(&vendor->ve_reg_array[0]->vr_reg_handle);
vendor->ve_reg_count = 0;
kmem_free(vendor->ve_reg_array[0],
sizeof (hci1394_vendor_reg_t));
vendor->ve_reg_array[0] = NULL;
return (DDI_FAILURE);
}
hci1394_rio_guid_init(vendor);
return (DDI_SUCCESS);
}
static int
hci1394_rio_resume(hci1394_vendor_t *vendor)
{
int status;
ASSERT(vendor != NULL);
status = hci1394_vendor_reg_write(vendor, 0, RIOREG_HOST_CONTROL,
RIOREG_HOST_CONTROL_SETTING);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
hci1394_rio_guid_init(vendor);
return (DDI_SUCCESS);
}
static void
hci1394_rio_guid_init(hci1394_vendor_t *vendor)
{
hrtime_t guid_timestamp;
ASSERT(vendor != NULL);
if (hci1394_set_rio_guid != 0) {
guid_timestamp = gethrtime();
guid_timestamp = guid_timestamp & RIOREG_GUID_MASK;
guid_timestamp = guid_timestamp | RIOREG_GUID_SUN_MICROSYSTEMS;
ddi_put32(vendor->ve_ohci->ohci_reg_handle,
&vendor->ve_ohci->ohci_regs->guid_hi,
(uint32_t)(guid_timestamp >> 32));
ddi_put32(vendor->ve_ohci->ohci_reg_handle,
&vendor->ve_ohci->ohci_regs->guid_lo,
(uint32_t)(guid_timestamp & 0xFFFFFFFF));
}
}