1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * CDDL HEADER START
1c42de6d020629af774dd9e9fc81be3f3ed9398egd *
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * The contents of this file are subject to the terms of the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Common Development and Distribution License (the "License").
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * You may not use this file except in compliance with the License.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd *
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * or http://www.opensolaris.org/os/licensing.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * See the License for the specific language governing permissions
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * and limitations under the License.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd *
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * When distributing Covered Code, include this CDDL HEADER in each
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * If applicable, add the following below this CDDL HEADER, with the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * fields enclosed by brackets "[]" replaced with your own identifying
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * information: Portions Copyright [yyyy] [name of copyright owner]
1c42de6d020629af774dd9e9fc81be3f3ed9398egd *
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * CDDL HEADER END
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
193974072f41a843678abf5f61979c748687e66bSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Use is subject to license terms.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * i2bsc.c is the nexus driver i2c traffic against devices hidden behind the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Blade Support Chip (BSC). It supports both interrupt and polled
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * mode operation, but defaults to interrupt.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/types.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/conf.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/file.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/open.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/ddi.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/sunddi.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/sunndi.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/modctl.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/stat.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/kmem.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/platform_module.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/stream.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/strlog.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/log.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/debug.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/note.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/bscbus.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/lom_ebuscodes.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/i2c/clients/i2c_client.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/i2c/misc/i2c_svc.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/i2c/misc/i2c_svc_impl.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#include <sys/i2c/nexus/i2bsc_impl.h>
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * static function declarations
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void i2bsc_resume(dev_info_t *dip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void i2bsc_suspend(dev_info_t *dip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int i2bsc_bus_ctl(dev_info_t *dip, dev_info_t *rdip,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_ctl_enum_t op, void *arg, void *result);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void i2bsc_acquire(i2bsc_t *, dev_info_t *dip,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c_transfer_t *tp);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void i2bsc_release(i2bsc_t *);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int i2bsc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int i2bsc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int i2bsc_open(dev_t *devp, int flag, int otyp,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd cred_t *cred_p);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int i2bsc_close(dev_t dev, int flag, int otyp,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd cred_t *cred_p);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int i2bsc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int i2bsc_initchild(dev_info_t *dip, dev_info_t *cdip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int i2bsc_uninitchild(dev_info_t *dip, dev_info_t *cdip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int i2bsc_setup_regs(i2bsc_t *);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void i2bsc_start_session(i2bsc_t *);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void i2bsc_fail_session(i2bsc_t *);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int i2bsc_end_session(i2bsc_t *);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void i2bsc_free_regs(i2bsc_t *);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int i2bsc_reportdev(dev_info_t *dip, dev_info_t *rdip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdint i2bsc_transfer(dev_info_t *dip, i2c_transfer_t *tp);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void i2bsc_trace(i2bsc_t *, char, const char *,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd const char *, ...);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int i2bsc_notify_max_transfer_size(i2bsc_t *);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int i2bsc_discover_capability(i2bsc_t *);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void i2bsc_put8(i2bsc_t *, uint8_t, uint8_t, uint8_t);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic uint8_t i2bsc_get8(i2bsc_t *, uint8_t, uint8_t);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int i2bsc_safe_upload(i2bsc_t *, i2c_transfer_t *);
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic boolean_t i2bsc_is_firmware_broken(i2bsc_t *);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic struct bus_ops i2bsc_busops = {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd BUSO_REV,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd nullbusmap, /* bus_map */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd NULL, /* bus_get_intrspec */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd NULL, /* bus_add_intrspec */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd NULL, /* bus_remove_intrspec */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd NULL, /* bus_map_fault */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_no_dma_map, /* bus_dma_map */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_no_dma_allochdl, /* bus_dma_allochdl */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_no_dma_freehdl, /* bus_dma_freehdl */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_no_dma_bindhdl, /* bus_dma_bindhdl */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_no_dma_unbindhdl, /* bus_unbindhdl */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_no_dma_flush, /* bus_dma_flush */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_no_dma_win, /* bus_dma_win */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_no_dma_mctl, /* bus_dma_ctl */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_bus_ctl, /* bus_ctl */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_bus_prop_op, /* bus_prop_op */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd NULL, /* bus_get_eventcookie */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd NULL, /* bus_add_eventcall */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd NULL, /* bus_remove_eventcall */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd NULL, /* bus_post_event */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* bus_intr_ctl */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* bus_config */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* bus_unconfig */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* bus_fm_init */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* bus_fm_fini */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* bus_fm_access_enter */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* bus_fm_access_exit */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* bus_power */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i_ddi_intr_ops /* bus_intr_op */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd};
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstruct cb_ops i2bsc_cb_ops = {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_open, /* open */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_close, /* close */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd nodev, /* strategy */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd nodev, /* print */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd nodev, /* dump */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd nodev, /* read */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd nodev, /* write */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_ioctl, /* ioctl */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd nodev, /* devmap */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd nodev, /* mmap */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd nodev, /* segmap */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd nochpoll, /* poll */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_prop_op, /* cb_prop_op */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0, /* streamtab */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd D_MP | D_NEW /* Driver compatibility flag */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd};
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic struct dev_ops i2bsc_ops = {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd DEVO_REV,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd 0,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_getinfo_1to1,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd nulldev,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd nulldev,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_attach,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_detach,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd nodev,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd &i2bsc_cb_ops,
193974072f41a843678abf5f61979c748687e66bSherry Moore &i2bsc_busops,
193974072f41a843678abf5f61979c748687e66bSherry Moore NULL,
193974072f41a843678abf5f61979c748687e66bSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd};
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#ifdef DEBUG
193974072f41a843678abf5f61979c748687e66bSherry Moore#define I2BSC_VERSION_STRING "i2bsc driver - Debug"
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#else
193974072f41a843678abf5f61979c748687e66bSherry Moore#define I2BSC_VERSION_STRING "i2bsc driver"
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#endif
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic struct modldrv modldrv = {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd &mod_driverops, /* Type of module. This one is a driver */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd I2BSC_VERSION_STRING, /* Name of the module. */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd &i2bsc_ops, /* driver ops */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd};
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic struct modlinkage modlinkage = {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd MODREV_1,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd &modldrv,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd NULL
1c42de6d020629af774dd9e9fc81be3f3ed9398egd};
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * i2bsc soft state
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void *i2bsc_state;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2c_nexus_reg_t i2bsc_regvec = {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd I2C_NEXUS_REV,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_transfer,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd};
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdint
1c42de6d020629af774dd9e9fc81be3f3ed9398egd_init(void)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int status;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd status = ddi_soft_state_init(&i2bsc_state, sizeof (i2bsc_t),
193974072f41a843678abf5f61979c748687e66bSherry Moore I2BSC_INITIAL_SOFT_SPACE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (status != 0) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (status);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if ((status = mod_install(&modlinkage)) != 0) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_soft_state_fini(&i2bsc_state);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (status);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdint
1c42de6d020629af774dd9e9fc81be3f3ed9398egd_fini(void)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int status;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if ((status = mod_remove(&modlinkage)) == 0) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_soft_state_fini(&i2bsc_state);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (status);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * The loadable-module _info(9E) entry point
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egdint
1c42de6d020629af774dd9e9fc81be3f3ed9398egd_info(struct modinfo *modinfop)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (mod_info(&modlinkage, modinfop));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_dodetach(dev_info_t *dip)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_t *i2c;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int instance = ddi_get_instance(dip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if ((i2c->i2bsc_attachflags & IMUTEX) != 0) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd mutex_destroy(&i2c->i2bsc_imutex);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd cv_destroy(&i2c->i2bsc_icv);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if ((i2c->i2bsc_attachflags & SETUP_REGS) != 0) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_free_regs(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if ((i2c->i2bsc_attachflags & NEXUS_REGISTER) != 0) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c_nexus_unregister(dip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if ((i2c->i2bsc_attachflags & MINOR_NODE) != 0) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_remove_minor_node(dip, NULL);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_soft_state_free(i2bsc_state, instance);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_doattach(dev_info_t *dip)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_t *i2c;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int instance = ddi_get_instance(dip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Allocate soft state structure.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (ddi_soft_state_zalloc(i2bsc_state, instance) != DDI_SUCCESS) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->majornum = ddi_driver_major(dip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->minornum = instance;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_dip = dip;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->debug = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
193974072f41a843678abf5f61979c748687e66bSherry Moore DDI_PROP_DONTPASS, "debug", 0);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd (void) snprintf(i2c->i2bsc_name, sizeof (i2c->i2bsc_name),
193974072f41a843678abf5f61979c748687e66bSherry Moore "%s_%d", ddi_node_name(dip), instance);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_setup_regs(i2c) != DDI_SUCCESS) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd goto bad;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_attachflags |= SETUP_REGS;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd mutex_init(&i2c->i2bsc_imutex, NULL, MUTEX_DRIVER,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd (void *) 0);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd cv_init(&i2c->i2bsc_icv, NULL, CV_DRIVER, NULL);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_attachflags |= IMUTEX;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c_nexus_register(dip, &i2bsc_regvec);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_attachflags |= NEXUS_REGISTER;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd DDI_NT_NEXUS, 0) == DDI_FAILURE) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd cmn_err(CE_WARN, "%s ddi_create_minor_node failed",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_name);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd goto bad;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_attachflags |= MINOR_NODE;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Now actually start talking to the microcontroller. The first
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * thing to check is whether the firmware is broken.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_is_firmware_broken(i2c)) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd cmn_err(CE_WARN, "Underlying BSC hardware not communicating;"
1c42de6d020629af774dd9e9fc81be3f3ed9398egd " shutting down my i2c services");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd goto bad;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_attachflags |= FIRMWARE_ALIVE;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Now see if the BSC chip supports the i2c service we rely upon.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd (void) i2bsc_discover_capability(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_notify_max_transfer_size(i2c) == DDI_SUCCESS)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_attachflags |= TRANSFER_SZ;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'A', "i2bsc_doattach", "attachflags %d",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_attachflags);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_SUCCESS);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdbad:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_dodetach(dip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (cmd) {
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_ATTACH:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (i2bsc_doattach(dip));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_RESUME:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_resume(dip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_SUCCESS);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
193974072f41a843678abf5f61979c748687e66bSherry Moore default:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (cmd) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd case DDI_DETACH:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_dodetach(dip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_SUCCESS);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd case DDI_SUSPEND:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_suspend(dip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_SUCCESS);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd default:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*ARGSUSED*/
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int instance;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_t *i2c;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Make sure the open is for the right file type
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (otyp != OTYP_CHR)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (EINVAL);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd instance = getminor(*devp);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2c == NULL)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (ENXIO);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Enforce exclusive access
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd mutex_enter(&i2c->i2bsc_imutex);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2c->i2bsc_open) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd mutex_exit(&i2c->i2bsc_imutex);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (EBUSY);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd } else
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_open = 1;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd mutex_exit(&i2c->i2bsc_imutex);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (0);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*ARGSUSED*/
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int instance;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_t *i2c;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Make sure the close is for the right file type
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (otyp != OTYP_CHR)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (EINVAL);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd instance = getminor(dev);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2c == NULL)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (ENXIO);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd mutex_enter(&i2c->i2bsc_imutex);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_open = 0;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd mutex_exit(&i2c->i2bsc_imutex);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (0);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*ARGSUSED*/
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int *rvalp)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_t *i2c;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd dev_info_t *self;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd dev_info_t *child;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd struct devctl_iocdata *dcp;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int rv;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, getminor(dev));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2c == NULL)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (ENXIO);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd self = (dev_info_t *)i2c->i2bsc_dip;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * read devctl ioctl data
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (EFAULT);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (cmd) {
193974072f41a843678abf5f61979c748687e66bSherry Moore case DEVCTL_BUS_DEV_CREATE:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd rv = ndi_dc_devi_create(dcp, self, 0, NULL);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd break;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
193974072f41a843678abf5f61979c748687e66bSherry Moore case DEVCTL_DEVICE_REMOVE:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (ndi_dc_getname(dcp) == NULL ||
193974072f41a843678abf5f61979c748687e66bSherry Moore ndi_dc_getaddr(dcp) == NULL) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd rv = EINVAL;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd break;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * lookup and hold child device
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd child = ndi_devi_find(self,
193974072f41a843678abf5f61979c748687e66bSherry Moore ndi_dc_getname(dcp), ndi_dc_getaddr(dcp));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (child == NULL) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd rv = ENXIO;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd break;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if ((rv = ndi_devi_offline(child, NDI_DEVI_REMOVE)) !=
193974072f41a843678abf5f61979c748687e66bSherry Moore NDI_SUCCESS) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd rv = (rv == NDI_BUSY) ? EBUSY : EIO;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd break;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
193974072f41a843678abf5f61979c748687e66bSherry Moore default:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd rv = ENOTSUP;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ndi_dc_freehdl(dcp);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (rv);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd void *arg, void *result)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_t *i2c;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int instance = ddi_get_instance(dip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'A', "i2bsc_bus_ctl", "dip/rdip,op/arg"
1c42de6d020629af774dd9e9fc81be3f3ed9398egd " %p/%p,%d/%p", dip, rdip, (int)op, arg);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (op) {
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_CTLOPS_INITCHILD:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (i2bsc_initchild(dip, (dev_info_t *)arg));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_CTLOPS_UNINITCHILD:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (i2bsc_uninitchild(dip, (dev_info_t *)arg));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_CTLOPS_REPORTDEV:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (i2bsc_reportdev(dip, rdip));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_CTLOPS_DMAPMAPC:
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_CTLOPS_POKE:
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_CTLOPS_PEEK:
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_CTLOPS_IOMIN:
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_CTLOPS_REPORTINT:
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_CTLOPS_SIDDEV:
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_CTLOPS_SLAVEONLY:
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_CTLOPS_AFFINITY:
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_CTLOPS_PTOB:
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_CTLOPS_BTOP:
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_CTLOPS_BTOPR:
193974072f41a843678abf5f61979c748687e66bSherry Moore case DDI_CTLOPS_DVMAPAGESIZE:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
193974072f41a843678abf5f61979c748687e66bSherry Moore default:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (ddi_ctlops(dip, rdip, op, arg, result));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * i2bsc_suspend() is called before the system suspends. Existing
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * transfer in progress or waiting will complete, but new transfers are
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * effectively blocked by "acquiring" the bus.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_suspend(dev_info_t *dip)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_t *i2c;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int instance;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd instance = ddi_get_instance(dip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_acquire(i2c, NULL, NULL);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * i2bsc_resume() is called when the system resumes from CPR. It releases
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * the hold that was placed on the i2c bus, which allows any real
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * transfers to continue.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_resume(dev_info_t *dip)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_t *i2c;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int instance;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd instance = ddi_get_instance(dip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, instance);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_release(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * i2bsc_acquire() is called by a thread wishing to "own" the I2C bus.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * It should not be held across multiple transfers.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_acquire(i2bsc_t *i2c, dev_info_t *dip, i2c_transfer_t *tp)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd mutex_enter(&i2c->i2bsc_imutex);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd while (i2c->i2bsc_busy) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd cv_wait(&i2c->i2bsc_icv, &i2c->i2bsc_imutex);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_busy = 1;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_cur_tran = tp;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_cur_dip = dip;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd mutex_exit(&i2c->i2bsc_imutex);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * i2bsc_release() is called to release a hold made by i2bsc_acquire().
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_release(i2bsc_t *i2c)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd mutex_enter(&i2c->i2bsc_imutex);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_busy = 0;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2bsc_cur_tran = NULL;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd cv_signal(&i2c->i2bsc_icv);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd mutex_exit(&i2c->i2bsc_imutex);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_initchild(dev_info_t *dip, dev_info_t *cdip)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_t *i2c;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int32_t address_cells;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int len;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int32_t regs[3];
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int err;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_ppvt_t *ppvt;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd char name[30];
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, ddi_get_instance(dip));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'A', "i2bsc_initchild", "dip/cdip %p/%p", dip, cdip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ppvt = kmem_alloc(sizeof (i2bsc_ppvt_t), KM_SLEEP);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd len = sizeof (address_cells);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd err = ddi_getlongprop_buf(DDI_DEV_T_ANY, cdip,
193974072f41a843678abf5f61979c748687e66bSherry Moore DDI_PROP_CANSLEEP, "#address-cells",
193974072f41a843678abf5f61979c748687e66bSherry Moore (caddr_t)&address_cells, &len);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (err != DDI_PROP_SUCCESS || len != sizeof (address_cells)) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd len = sizeof (regs);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd err = ddi_getlongprop_buf(DDI_DEV_T_ANY, cdip,
193974072f41a843678abf5f61979c748687e66bSherry Moore DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP,
193974072f41a843678abf5f61979c748687e66bSherry Moore "reg", (caddr_t)regs, &len);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (err != DDI_PROP_SUCCESS)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (address_cells == 1) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ppvt->i2bsc_ppvt_bus = I2BSC_DEFAULT_BUS;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ppvt->i2bsc_ppvt_addr = regs[0];
1c42de6d020629af774dd9e9fc81be3f3ed9398egd (void) sprintf(name, "%x", regs[0]);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'A', "i2bsc_initchild", "#address-cells = 1"
1c42de6d020629af774dd9e9fc81be3f3ed9398egd " regs[0] = %d", regs[0]);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd } else if (address_cells == 2) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ppvt->i2bsc_ppvt_bus = regs[0];
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ppvt->i2bsc_ppvt_addr = regs[1];
1c42de6d020629af774dd9e9fc81be3f3ed9398egd (void) sprintf(name, "%x,%x", regs[0], regs[1]);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'A', "i2bsc_initchild", "#address-cells = 2"
1c42de6d020629af774dd9e9fc81be3f3ed9398egd " regs[0] = %d, regs[1] = %d", regs[0], regs[1]);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd } else {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Attach the parent's private data structure to the child's devinfo
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * node, and store the child's address on the nexus in the child's
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * devinfo node.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_set_parent_data(cdip, ppvt);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_set_name_addr(cdip, name);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'A', "i2bsc_initchild", "success(%s)",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_node_name(cdip));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_SUCCESS);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_uninitchild(dev_info_t *dip, dev_info_t *cdip)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_t *i2c;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_ppvt_t *ppvt;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state, ddi_get_instance(dip));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'D', "i2bsc_uninitchild", "dip/cdip %p/%p", dip, cdip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ppvt = ddi_get_parent_data(cdip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd kmem_free(ppvt, sizeof (i2bsc_ppvt_t));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_set_parent_data(cdip, NULL);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_set_name_addr(cdip, NULL);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'D', "i2bsc_uninitchild", "success(%s)",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_node_name(cdip));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_SUCCESS);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * i2bsc_setup_regs() is called to map in registers specific to
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * the i2bsc.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_setup_regs(i2bsc_t *i2c)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int nregs;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->bscbus_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->bscbus_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->bscbus_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (ddi_dev_nregs(i2c->i2bsc_dip, &nregs) != DDI_SUCCESS) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (nregs < 1) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (ddi_regs_map_setup(i2c->i2bsc_dip, 0,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd (caddr_t *)&i2c->bscbus_regs, 0, 0, &i2c->bscbus_attr,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd &i2c->bscbus_handle) != DDI_SUCCESS) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_SUCCESS);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * i2bsc_free_regs() frees any registers previously
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * allocated.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_free_regs(i2bsc_t *i2c)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2c->bscbus_regs != NULL) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_regs_map_free(&i2c->bscbus_handle);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*ARGSUSED*/
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_reportdev(dev_info_t *dip, dev_info_t *rdip)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (rdip == (dev_info_t *)0)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd cmn_err(CE_CONT, "?i2bsc-device: %s@%s, %s%d\n",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_node_name(rdip), ddi_get_name_addr(rdip), ddi_driver_name(rdip),
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_get_instance(rdip));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_SUCCESS);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * I/O Functions
1c42de6d020629af774dd9e9fc81be3f3ed9398egd *
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * i2bsc_{put,get}8_once are wrapper functions to ddi_{get,put}8.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * i2bsc_{put,get}8 are equivalent functions but with retry code.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * i2bsc_bscbus_state determines underlying bus error status.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * i2bsc_clear_acc_fault clears the underlying bus error status.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd *
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * I/O Flags
1c42de6d020629af774dd9e9fc81be3f3ed9398egd *
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * bscbus_fault - Error register in underlying bus for last IO operation.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * session_failure - Set by any failed IO command. This is a sticky flag
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * reset explicitly using i2bsc_start_session
1c42de6d020629af774dd9e9fc81be3f3ed9398egd *
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Session Management
1c42de6d020629af774dd9e9fc81be3f3ed9398egd *
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * i2bsc_{start,end}_session need to be used to detect an error across multiple
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * gets/puts rather than having to test for an error on each get/put.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int i2bsc_bscbus_state(i2bsc_t *i2c)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd uint32_t retval;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd retval = ddi_get32(i2c->bscbus_handle,
193974072f41a843678abf5f61979c748687e66bSherry Moore (uint32_t *)I2BSC_NEXUS_ADDR(i2c, EBUS_CMD_SPACE_GENERIC,
193974072f41a843678abf5f61979c748687e66bSherry Moore LOMBUS_FAULT_REG));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->bscbus_fault = retval;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return ((retval == 0) ? DDI_SUCCESS : DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void i2bsc_clear_acc_fault(i2bsc_t *i2c)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, '@', "i2bsc_clear_acc_fault", "clearing acc fault");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_put32(i2c->bscbus_handle,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd (uint32_t *)I2BSC_NEXUS_ADDR(i2c, EBUS_CMD_SPACE_GENERIC,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd LOMBUS_FAULT_REG), 0);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_start_session(i2bsc_t *i2c)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'S', "i2bsc_start_session", "session started");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->bscbus_session_failure = 0;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_fail_session(i2bsc_t *i2c)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'S', "i2bsc_fail_session", "session failed");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->bscbus_session_failure = 1;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_end_session(i2bsc_t *i2c)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * The ONLY way to get the session status is to end the session.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * If clients of the session interface ever wanted the status mid-way
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * then they are really working with multiple contigious sessions.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'S', "i2bsc_end_session", "session ended with %d",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->bscbus_session_failure);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return ((i2c->bscbus_session_failure) ? DDI_FAILURE : DDI_SUCCESS);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic boolean_t
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_is_firmware_broken(i2bsc_t *i2c)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int i;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int niterations = I2BSC_SHORT_RETRY_LIMIT;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'A', "i2bsc_is_firmware_broken", "called");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd for (i = 0; i < niterations; i++) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd (void) ddi_get8(i2c->bscbus_handle,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd I2BSC_NEXUS_ADDR(i2c, EBUS_CMD_SPACE_I2C,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd EBUS_IDX12_RESULT));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_clear_acc_fault(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd continue;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd } else {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Firmware communication succeeded.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'A', "i2bsc_is_firmware_broken",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "firmware communications okay");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (B_FALSE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Firmware is not communicative. Some possible causes :
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Broken hardware
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * BSC held in reset
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Corrupt BSC image
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * OBP incompatiblity preventing drivers loading properly
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'A', "i2bsc_is_firmware_broken", "%d read fails",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd niterations);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (B_TRUE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_put8(i2bsc_t *i2c, uint8_t space, uint8_t index, uint8_t value)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int retryable = I2BSC_RETRY_LIMIT;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, '@', "i2bsc_put8", "(space,index)<-val (%d,%d)<-%d",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd space, index, value);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_clear_acc_fault(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * If a session failure has already occurred, reduce the level of
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * retries to a minimum. This is a optimization of the failure
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * recovery strategy.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2c->bscbus_session_failure)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd retryable = 1;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd while (retryable--) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_put8(i2c->bscbus_handle,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd I2BSC_NEXUS_ADDR(i2c, space, index), value);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_clear_acc_fault(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd } else
1c42de6d020629af774dd9e9fc81be3f3ed9398egd break;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_fail_session(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, '@', "i2bsc_put8", "tried %d time(s)",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd I2BSC_RETRY_LIMIT - retryable);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic uint8_t
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_get8(i2bsc_t *i2c, uint8_t space, uint8_t index)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd uint8_t value;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int retryable = I2BSC_RETRY_LIMIT;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_clear_acc_fault(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * If a session failure has already occurred, reduce the level of
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * retries to a minimum. This is a optimization of the failure
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * recovery strategy.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2c->bscbus_session_failure)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd retryable = 1;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd while (retryable--) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd value = ddi_get8(i2c->bscbus_handle,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd I2BSC_NEXUS_ADDR(i2c, space, index));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_clear_acc_fault(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd } else
1c42de6d020629af774dd9e9fc81be3f3ed9398egd break;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_fail_session(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, '@', "i2bsc_get8", "tried %d time(s)",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd I2BSC_RETRY_LIMIT - retryable);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, '@', "i2bsc_get8", "(space,index)->val (%d,%d)->%d",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd space, index, value);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (value);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_put8_once(i2bsc_t *i2c, uint8_t space, uint8_t index, uint8_t value)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, '@', "i2bsc_put8_once",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "(space,index)<-val (%d,%d)<-%d", space, index, value);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_clear_acc_fault(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ddi_put8(i2c->bscbus_handle,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd I2BSC_NEXUS_ADDR(i2c, space, index), value);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_fail_session(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic uint8_t
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_get8_once(i2bsc_t *i2c, uint8_t space, uint8_t index)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd uint8_t value;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_clear_acc_fault(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd value = ddi_get8(i2c->bscbus_handle,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd I2BSC_NEXUS_ADDR(i2c, space, index));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_bscbus_state(i2c) != DDI_SUCCESS)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_fail_session(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, '@', "i2bsc_get8_once",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "(space,index)->val (%d,%d)->%d", space, index, value);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (value);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_notify_max_transfer_size(i2bsc_t *i2c)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * If the underlying hardware does not support the i2c service and
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * we are not running in fake_mode, then we cannot set the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * MAX_TRANSFER_SZ.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2c->i2c_proxy_support == 0)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_start_session(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_MAX_TRANSFER_SZ,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd I2BSC_MAX_TRANSFER_SZ);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_end_session(i2c) != DDI_SUCCESS)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_SUCCESS);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Discover if the microcontroller implements the I2C Proxy Service this
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * driver requires. If it does not, i2c transactions will abort with
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * I2C_FAILURE, unless fake_mode is being used.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_discover_capability(i2bsc_t *i2c)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_start_session(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2c_proxy_support = i2bsc_get8(i2c, EBUS_CMD_SPACE_GENERIC,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd EBUS_IDX_CAP0);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c->i2c_proxy_support &= EBUS_CAP0_I2C_PROXY;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_end_session(i2c) != DDI_SUCCESS)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_FAILURE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (DDI_SUCCESS);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_upload_preamble(i2bsc_t *i2c, i2c_transfer_t *tp)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_ppvt_t *ppvt;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int wr_rd;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ppvt = ddi_get_parent_data(i2c->i2bsc_cur_dip);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Get a lock on the i2c devices owned by the microcontroller */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_TRANSACTION_LOCK, 1);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (!i2bsc_get8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_TRANSACTION_LOCK)) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * i2c client driver must timeout retry, NOT this nexus
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_result = I2C_INCOMPLETE;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'U', "i2bsc_upload_preamble",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "Couldn't get transaction lock");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (tp->i2c_result);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_BUS_ADDRESS,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ppvt->i2bsc_ppvt_bus);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * The Solaris architecture for I2C uses 10-bit I2C addresses where
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * bit-0 is zero (the read/write bit). The microcontroller uses 7 bit
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * I2C addresses (read/write bit excluded). Hence we need to convert
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * the address by bit-shifting.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_CLIENT_ADDRESS,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd ppvt->i2bsc_ppvt_addr >> 1);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_TRANSFER_TYPE,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_flags);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * We have only one register used for data input and output. When
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * a WR_RD is issued, this means we want to do a Random-Access-Read.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * First a series of bytes are written which define the address to
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * read from. In hardware this sets an address pointer. Then a series
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * of bytes are read. The read/write boundary tells you how many
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * bytes are to be written before reads will be issued.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (tp->i2c_flags == I2C_WR_RD)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd wr_rd = tp->i2c_wlen;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd else
1c42de6d020629af774dd9e9fc81be3f3ed9398egd wr_rd = 0;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_WR_RD_BOUNDARY, wr_rd);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (I2C_SUCCESS);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Function i2bsc_upload
1c42de6d020629af774dd9e9fc81be3f3ed9398egd *
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Description This function runs the i2c transfer protocol down to the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * microcontroller. Its goal is to be as reliable as possible.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * This is achieved by making all the state-less aspects
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * re-tryable. For stateful aspects, we take care to ensure the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * counters are decremented only when data transfer has been
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * successful.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_upload(i2bsc_t *i2c, i2c_transfer_t *tp)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int quota = I2BSC_MAX_TRANSFER_SZ;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd uint8_t res;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int residual;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Total amount of data outstanding
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd residual = tp->i2c_w_resid + tp->i2c_r_resid;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Anything in this session *could* be re-tried without side-effects.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Therefore, error exit codes are I2C_INCOMPLETE rather than
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * I2C_FAILURE.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_start_session(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_upload_preamble(i2c, tp) != I2C_SUCCESS)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (I2C_INCOMPLETE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_end_session(i2c) != DDI_SUCCESS)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (I2C_INCOMPLETE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* The writes done here are not retryable */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd while (tp->i2c_w_resid && quota) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_put8_once(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_DATA_INOUT,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_wbuf[tp->i2c_wlen - tp->i2c_w_resid]);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_bscbus_state(i2c) == DDI_SUCCESS) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_w_resid--;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd quota--;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd residual--;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd } else {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'T', "i2bsc_upload", "write failed");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (tp->i2c_result = I2C_INCOMPLETE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* The reads done here are not retryable */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd while (tp->i2c_r_resid && quota) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_rbuf[tp->i2c_rlen - tp->i2c_r_resid] =
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_get8_once(i2c, EBUS_CMD_SPACE_I2C,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd EBUS_IDX12_DATA_INOUT);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_bscbus_state(i2c) == DDI_SUCCESS) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_r_resid--;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd quota--;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd residual--;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd } else {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'T', "i2bsc_upload", "read failed");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (tp->i2c_result = I2C_INCOMPLETE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_start_session(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * A possible future enhancement would be to allow early breakout of the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * loops seen above. In such circumstances, "residual" would be non-
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * zero. This may be useful if we want to support the interruption of
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * transfer part way through an i2c_transfer_t.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_put8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_RESIDUAL_DATA, residual);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd res = i2bsc_get8(i2c, EBUS_CMD_SPACE_I2C, EBUS_IDX12_RESULT);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2bsc_end_session(i2c) != DDI_SUCCESS)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (tp->i2c_result = I2C_INCOMPLETE);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd switch (res) {
193974072f41a843678abf5f61979c748687e66bSherry Moore case EBUS_I2C_SUCCESS:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_result = I2C_SUCCESS;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd break;
193974072f41a843678abf5f61979c748687e66bSherry Moore case EBUS_I2C_FAILURE:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * This is rare but possible. A retry may still fix this
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * so lets allow that by returning I2C_INCOMPLETE.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * "hifTxRing still contains 1 bytes" is reported by the
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * microcontroller when this return value is seen.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'T', "i2bsc_upload", "EBUS_I2C_FAILURE"
1c42de6d020629af774dd9e9fc81be3f3ed9398egd " but returning I2C_INCOMPLETE for possible re-try");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_result = I2C_INCOMPLETE;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd break;
193974072f41a843678abf5f61979c748687e66bSherry Moore case EBUS_I2C_INCOMPLETE:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_result = I2C_INCOMPLETE;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd break;
193974072f41a843678abf5f61979c748687e66bSherry Moore default:
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_result = I2C_FAILURE;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (tp->i2c_result);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Function i2bsc_safe_upload
1c42de6d020629af774dd9e9fc81be3f3ed9398egd *
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Description This function is called "safe"-upload because it attempts to
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * do transaction re-tries for cases where state is not spoiled
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * by a transaction-level retry.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic int
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_safe_upload(i2bsc_t *i2c, i2c_transfer_t *tp)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int retryable = I2BSC_RETRY_LIMIT;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd int result;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'T', "i2bsc_safe_upload", "Transaction %s",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd (tp->i2c_flags == I2C_WR_RD) ? "retryable" : "single-shot");
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * The only re-tryable transaction type is I2C_WR_RD. If we don't
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * have this we can only use session-based recovery offered by
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * i2bsc_upload.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (tp->i2c_flags != I2C_WR_RD)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (i2bsc_upload(i2c, tp));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd while (retryable--) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd result = i2bsc_upload(i2c, tp);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (result == I2C_INCOMPLETE) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd /* Have another go */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_r_resid = tp->i2c_rlen;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_w_resid = tp->i2c_wlen;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_result = I2C_SUCCESS;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'T', "i2bsc_safe_upload",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "Retried (%d)", I2BSC_RETRY_LIMIT - retryable);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd continue;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd } else {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'T', "i2bsc_safe_upload",
1c42de6d020629af774dd9e9fc81be3f3ed9398egd "Exiting while loop on result %d", result);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (result);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'T', "i2bsc_safe_upload", "Exiting on %d", result);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (result);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Function i2bsc_transfer
1c42de6d020629af774dd9e9fc81be3f3ed9398egd *
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * Description This is the entry-point that clients use via the Solaris i2c
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * framework. It kicks off the servicing of i2c transfer requests.
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egdint
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_transfer(dev_info_t *dip, i2c_transfer_t *tp)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_t *i2c;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2c = (i2bsc_t *)ddi_get_soft_state(i2bsc_state,
193974072f41a843678abf5f61979c748687e66bSherry Moore ddi_get_instance(ddi_get_parent(dip)));
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_acquire(i2c, dip, tp);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_r_resid = tp->i2c_rlen;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_w_resid = tp->i2c_wlen;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_result = I2C_SUCCESS;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'T', "i2bsc_transfer", "Transaction i2c_version/flags"
1c42de6d020629af774dd9e9fc81be3f3ed9398egd " %d/%d", tp->i2c_version, tp->i2c_flags);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'T', "i2bsc_transfer", "Transaction buffer rlen/wlen"
1c42de6d020629af774dd9e9fc81be3f3ed9398egd " %d/%d", tp->i2c_rlen, tp->i2c_wlen);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'T', "i2bsc_transfer", "Transaction ptrs wbuf/rbuf"
1c42de6d020629af774dd9e9fc81be3f3ed9398egd " %p/%p", tp->i2c_wbuf, tp->i2c_rbuf);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (i2c->i2c_proxy_support)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd (void) i2bsc_safe_upload(i2c, tp);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd else
1c42de6d020629af774dd9e9fc81be3f3ed9398egd tp->i2c_result = I2C_FAILURE;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'T', "i2bsc_transfer", "Residual writes/reads"
1c42de6d020629af774dd9e9fc81be3f3ed9398egd " %d/%d", tp->i2c_w_resid, tp->i2c_r_resid);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_trace(i2c, 'T', "i2bsc_transfer", "i2c_result"
1c42de6d020629af774dd9e9fc81be3f3ed9398egd " %d", tp->i2c_result);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd i2bsc_release(i2c);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd return (tp->i2c_result);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd/*
1c42de6d020629af774dd9e9fc81be3f3ed9398egd * General utility routines ...
1c42de6d020629af774dd9e9fc81be3f3ed9398egd */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#ifdef DEBUG
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_trace(i2bsc_t *ssp, char code, const char *caller,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd const char *fmt, ...)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd char buf[256];
1c42de6d020629af774dd9e9fc81be3f3ed9398egd char *p;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd va_list va;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd if (ssp->debug & (1 << (code-'@'))) {
1c42de6d020629af774dd9e9fc81be3f3ed9398egd p = buf;
1c42de6d020629af774dd9e9fc81be3f3ed9398egd (void) snprintf(p, sizeof (buf) - (p - buf),
193974072f41a843678abf5f61979c748687e66bSherry Moore "%s/%s: ", ssp->i2bsc_name, caller);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd p += strlen(p);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd va_start(va, fmt);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd (void) vsnprintf(p, sizeof (buf) - (p - buf), fmt, va);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd va_end(va);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd buf[sizeof (buf) - 1] = '\0';
1c42de6d020629af774dd9e9fc81be3f3ed9398egd (void) strlog(ssp->majornum, ssp->minornum, code, SL_TRACE,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd buf);
1c42de6d020629af774dd9e9fc81be3f3ed9398egd }
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#else /* DEBUG */
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd_NOTE(ARGSUSED(0))
1c42de6d020629af774dd9e9fc81be3f3ed9398egdstatic void
1c42de6d020629af774dd9e9fc81be3f3ed9398egdi2bsc_trace(i2bsc_t *ssp, char code, const char *caller,
1c42de6d020629af774dd9e9fc81be3f3ed9398egd const char *fmt, ...)
1c42de6d020629af774dd9e9fc81be3f3ed9398egd{
1c42de6d020629af774dd9e9fc81be3f3ed9398egd}
1c42de6d020629af774dd9e9fc81be3f3ed9398egd
1c42de6d020629af774dd9e9fc81be3f3ed9398egd#endif /* DEBUG */