Example #1
0
/*ARGSUSED*/
void
isadma_put16(ddi_acc_impl_t *hdlp, uint16_t *addr, uint16_t value)
{
	ddi_acc_handle_t phdl = hdlp->ahi_common.ah_platform_private;
	isadma_devstate_t *isadmap = hdlp->ahi_common.ah_bus_private;
	off_t offset = (caddr_t)addr - hdlp->ahi_common.ah_addr;

	if (IN_CHILD_SPACE(offset)) {	/* Pass to parent */
#ifdef DEBUG
		isadma_punt++;
#endif
		ddi_put16(phdl, addr, value);
		return;
	}
#ifdef DEBUG
	isadma_check_waiters(isadmap);
#endif
	mutex_enter(&isadmap->isadma_access_lock);
	isadma_dmawait(isadmap);	/* wait until on-going dma completes */

	/* Only Allow access to the 16 bit count and address registers */
	if (!IN_16BIT_SPACE(offset))
		goto exit;

	/* Set the sequencing register to the low byte */
	ddi_put8(phdl, (uint8_t *)HDL_TO_SEQREG_ADDR(hdlp, offset), 0);

	/* Write the low byte, then the high byte */
	ddi_put8(phdl, (uint8_t *)addr, value & 0xff);
	ddi_put8(phdl, (uint8_t *)addr, (value >> 8) & 0xff);
exit:
	isadma_wakeup(isadmap);
	mutex_exit(&isadmap->isadma_access_lock);
}
void
ehc_init_pcf8584(struct ehc_envcunit *ehcp)
{
	/*
	 * Writing PIN bit of S1 causes software reset.
	 * The next write to S0 will be S0' "own address".
	 */

	ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1, EHC_S1_PIN);

	/*
	 * Write the address which the controller chip will use
	 * (when addressed as a slave) on the I2C bus.
	 * DAF - should own address be passed as argument?
	 */

	ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0, EHC_S0_OWN);

	/*
	 * Writing PIN bit and ES1 bit of S1 causes software
	 * reset and selects the S2 register for writing.
	 * Now, the next write to S0 will be the S2 clock
	 * control register.
	 */

	ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1,
		EHC_S1_PIN | EHC_S1_ES1);

	/*
	 * Write the value into register that sets internal system clock
	 * to 12 Mhz, and the I2C bus rate (SCL) to 9 Khz.
	 * DAF - should these be parameters?
	 */

	ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0, EHC_S0_CLK);

	/*
	 * Writing PIN bit causes software reset and the ES0 bit
	 * selects the (S0) register for reading/writing.  The ACK
	 * bit being set causes controller to send ACK after each
	 * byte.
	 */

	ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1,
		EHC_S1_PIN | EHC_S1_ES0 | EHC_S1_ACK);

	/*
	 * Multi-Master: Wait for a period of time equal to the
	 * longest I2C message.  This accounts for the case
	 * where multiple controllers and, if this particular one
	 * is "lagging", misses the BB (bus busy) condition.
	 * DAF - What does this need?
	 * We wait 200 ms since the longest transaction at this time
	 * on the i2c bus is a 256 byte read from the seprom which takes
	 * about 75 ms. Some additional buffer does no harm to the driver.
	 */

	drv_usecwait(EHC_LONGEST_MSG);

}
Example #3
0
/*ARGSUSED*/
void
isadma_put8(ddi_acc_impl_t *hdlp, uint8_t *addr, uint8_t value)
{
	ddi_acc_handle_t phdl = hdlp->ahi_common.ah_platform_private;
	isadma_devstate_t *isadmap = hdlp->ahi_common.ah_bus_private;
	off_t offset = (caddr_t)addr - hdlp->ahi_common.ah_addr;

	if (IN_CHILD_SPACE(offset)) {	/* Pass to parent */
#ifdef DEBUG
		isadma_punt++;
#endif
		ddi_put8(phdl, addr, value);
		return;
	}
#ifdef DEBUG
	isadma_check_waiters(isadmap);
#endif
	mutex_enter(&isadmap->isadma_access_lock);

	if (isadmap->isadma_ldip == hdlp->ahi_common.ah_dip) { /* owned lock? */
		if (END_ISADMA(offset, value)) {
			isadmap->isadma_ldip = NULL;	/* reset lock owner */
#ifdef DEBUG
			isadma_clearing_wdip++;
#endif
		}
	} else	{	/* we don't own the lock */
		/* wait until on-going dma completes */
		isadma_dmawait(isadmap);

		if (BEGIN_ISADMA(offset, value)) {
			isadmap->isadma_ldip = hdlp->ahi_common.ah_dip;
#ifdef DEBUG
			isadma_setting_wdip++;
#endif
		}
	}

	/* No 8 bit access to 16 bit address or count registers */
	if (IN_16BIT_SPACE(offset))
		goto exit;

	/* No 8 bit access to first/last flip-flop registers */
	if (IS_SEQREG(offset))
		goto exit;

	ddi_put8(phdl, addr, value);	/* Pass to parent */
exit:
	isadma_wakeup(isadmap);
	mutex_exit(&isadmap->isadma_access_lock);
}
Example #4
0
static void
kb8042_send_to_keyboard(struct kb8042 *kb8042, int byte, boolean_t polled)
{
	if (polled) {
		ddi_put8(kb8042->handle,
		    kb8042->addr + I8042_POLL_OUTPUT_DATA, byte);
	} else {
		ddi_put8(kb8042->handle,
		    kb8042->addr + I8042_INT_OUTPUT_DATA, byte);
	}

#if	defined(KD_DEBUG)
	if (kb8042_low_level_debug)
		prom_printf(" >K:%x ", byte);
#endif
}
Example #5
0
/*
 * Generate an SBBC interrupt to the SC
 * Called from iosram_send_intr()
 *
 * send_intr == 0, check if EPLD register clear
 *	           for sync'ing SC/OS
 * send_intr == 1, send the interrupt
 */
int
sbbc_send_intr(sbbc_softstate_t *softsp, int send_intr)
{

	uchar_t			*epld_int;
	volatile uchar_t 	epld_status;

	ASSERT(MUTEX_HELD(&master_iosram->iosram_lock));

	if ((softsp == (sbbc_softstate_t *)NULL) ||
		(softsp->epld_regs == (struct sbbc_epld_regs *)NULL))
		return (ENXIO);

	/*
	 * Check the L1 EPLD Interrupt register. If the
	 * interrupt bit is set, theres an interrupt outstanding
	 * (we assume) so return (EBUSY).
	 */

	epld_int = &softsp->epld_regs->epld_reg[EPLD_INTERRUPT];

	epld_status = ddi_get8(softsp->sbbc_reg_handle2, epld_int);

	if (epld_status & INTERRUPT_ON)
		return (EBUSY);

	if (send_intr == TRUE)
		ddi_put8(softsp->sbbc_reg_handle2, epld_int,
			(epld_status | INTERRUPT_ON));

	return (0);
}
Example #6
0
static void
fipe_ioat_cancel(void)
{
	uint32_t status;
	uint8_t	*addr = fipe_ioat_ctrl.ioat_reg_addr;
	ddi_acc_handle_t handle = fipe_ioat_ctrl.ioat_reg_handle;

	/*
	 * Reset channel. Sometimes reset is not reliable,
	 * so check completion or abort status after reset.
	 */
	/* LINTED: constant in conditional context */
	while (1) {
		/* Issue reset channel command. */
		ddi_put8(handle, (uint8_t *)(addr + FIPE_IOAT_CHAN_CMD), 0x20);

		/* Query command status. */
		status = ddi_get32(handle,
		    (uint32_t *)(addr + FIPE_IOAT_CHAN_STS_LO));
		if (status & 0x1) {
			/* Reset channel completed. */
			break;
		} else {
			SMT_PAUSE();
		}
	}

	/* Put channel into "not in use" state. */
	ddi_put16(handle, (uint16_t *)(addr + FIPE_IOAT_CHAN_CTRL), 0);
}
static void
rge_chip_poke_reg(rge_t *rgep, rge_peekpoke_t *ppd)
{
	uint64_t regval;
	void *regaddr;

	RGE_TRACE(("rge_chip_poke_reg($%p, $%p)",
	    (void *)rgep, (void *)ppd));

	regaddr = PIO_ADDR(rgep, ppd->pp_acc_offset);
	regval = ppd->pp_acc_data;

	switch (ppd->pp_acc_size) {
	case 1:
		ddi_put8(rgep->io_handle, regaddr, regval);
		break;

	case 2:
		ddi_put16(rgep->io_handle, regaddr, regval);
		break;

	case 4:
		ddi_put32(rgep->io_handle, regaddr, regval);
		break;

	case 8:
		ddi_put64(rgep->io_handle, regaddr, regval);
		break;
	}
}
static void
rge_reg_put8(rge_t *rgep, uintptr_t regno, uint8_t data)
{
	RGE_TRACE(("rge_reg_put8($%p, 0x%lx, 0x%x)",
	    (void *)rgep, regno, data));

	ddi_put8(rgep->io_handle, REG8(rgep, regno), data);
}
Example #9
0
void
virtio_write_device_config_1(struct virtio_softc *sc, unsigned int index,
    uint8_t value)
{
	ASSERT(sc->sc_config_offset);
	ddi_put8(sc->sc_ioh,
	    (uint8_t *)(sc->sc_io_addr + sc->sc_config_offset + index), value);
}
/*
 * Returns 1 if the caller should stop processing messages
 */
static int
mouse8042_process_data_msg(queue_t *q, mblk_t *mp, struct mouse_state *state)
{
	mblk_t *bp;
	mblk_t *next;

	bp = mp;
	do {
		while (bp->b_rptr < bp->b_wptr) {
			/*
			 * Detect an attempt to reset the mouse.  Lock out any
			 * further mouse writes until the reset has completed.
			 */
			if (*bp->b_rptr == MSERESET) {

				/*
				 * If we couldn't allocate memory and we
				 * we couldn't register a bufcall,
				 * mouse8042_initiate_reset returns 0 and
				 * has already used the message to send an
				 * error reply back upstream, so there is no
				 * need to deallocate or put this message back
				 * on the queue.
				 */
				if (mouse8042_initiate_reset(q, bp, state) == 0)
					return (1);

				/*
				 * If there's no data remaining in this block,
				 * free this block and put the following blocks
				 * of this message back on the queue. If putting
				 * the rest of the message back on the queue
				 * fails, free the the message.
				 */
				if (MBLKL(bp) == 0) {
					next = bp->b_cont;
					freeb(bp);
					bp = next;
				}
				if (bp != NULL) {
					if (!putbq(q, bp))
						freemsg(bp);
				}

				return (1);

			}
			ddi_put8(state->ms_handle,
			    state->ms_addr + I8042_INT_OUTPUT_DATA,
			    *bp->b_rptr++);
		}
		next = bp->b_cont;
		freeb(bp);
	} while ((bp = next) != NULL);

	return (0);
}
static int
ehc_after_read_pcf8584(struct ehc_envcunit *ehcp, uint8_t *data)
{
	uint8_t discard;
	uint8_t poll_status;
	int i = 0;

	/* set ACK in register S1 to 0 */
	ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1, EHC_S1_ES0);

	/*
	 * Read the "byte-before-the-last-byte" - sets PIN bit to '1'
	 */

	*data = ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0);

	/* wait for completion of transmission */
	do {
		drv_usecwait(1000);
		poll_status =
			ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
		i++;
	} while ((poll_status & EHC_S1_PIN) && i < EHC_MAX_WAIT);

	if (i == EHC_MAX_WAIT) {
		DCMN_ERR(CE_WARN, "ehc_after_rd_pcf8584(): read of S1 failed");
		return (EHC_FAILURE);
	}

	if (poll_status & EHC_S1_BER) {
		DCMN2_ERR(CE_WARN, "ehc_after_rd_pcf8584(): Bus error");
		ehc_init_pcf8584(ehcp);
		return (EHC_FAILURE);
	}

	if (poll_status & EHC_S1_LAB) {
		DCMN2_ERR(CE_WARN, "ehc_after_rd_pcf8584(): Lost Arbitration");
		ehc_init_pcf8584(ehcp);
		return (EHC_FAILURE);
	}

	/*
	 * Generate the "stop" condition.
	 */
	ehc_stop_pcf8584(ehcp);

	/*
	 * Read the "last" byte.
	 */
	discard = ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0);
#ifdef lint
	discard = discard;
#endif

	return (EHC_SUCCESS);
}
Example #12
0
/**
 * Virtio Pci set (write) routine.
 *
 * @param pDevice           Pointer to the Virtio device instance.
 * @param off               Offset into the PCI config space.
 * @param pv                Pointer to the buffer to write from.
 * @param cb                Size of the buffer in bytes.
 */
static void VirtioPciSet(PVIRTIODEVICE pDevice, off_t off, void *pv, size_t cb)
{
    LogFlowFunc((VIRTIOLOGNAME ":VirtioPciSet pDevice=%p\n", pDevice));
    virtio_pci_t *pPciData = pDevice->pvHyper;
    AssertReturnVoid(pPciData);

    uint8_t *pb = pv;
    for (size_t i = 0; i < cb; i++, pb++)
        ddi_put8(pPciData->hIO, (uint8_t *)(pPciData->addrIOBase + VIRTIO_PCI_CONFIG + off + i), *pb);
}
Example #13
0
void
pci_config_putb(ddi_acc_handle_t handle, off_t offset, uint8_t value)
{
	caddr_t	cfgaddr;
	ddi_acc_hdl_t *hp;

	hp = impl_acc_hdl_get(handle);
	cfgaddr = hp->ah_addr + offset;
	ddi_put8(handle, (uint8_t *)cfgaddr, value);
}
Example #14
0
/*
 * Lowest-level serial I/O chip register read/write
 */
static void
sio_put_reg(struct rmc_comm_state *rcs, uint_t reg, uint8_t val)
{
	DPRINTF(rcs, DSER, (CE_CONT, "REG[%d]<-$%02x", reg, val));

	if (rcs->sd_state.sio_handle != NULL && !rcs->sd_state.sio_fault) {
		/*
		 * The chip is mapped as "I/O" (e.g. with the side-effect
		 * bit on SPARC), therefore accesses are required to be
		 * in-order, with no value cacheing.  However, there can
		 * still be write-behind buffering, so it is not guaranteed
		 * that a write actually reaches the chip in a given time.
		 *
		 * To force the access right through to the chip, we follow
		 * the write with another write (to the SCRATCH register)
		 * and a read (of the value just written to the SCRATCH
		 * register).  The SCRATCH register is specifically provided
		 * for temporary data and has no effect on the SIO's own
		 * operation, making it ideal as a synchronising mechanism.
		 *
		 * If we didn't do this, it would be possible that the new
		 * value wouldn't reach the chip (and have the *intended*
		 * side-effects, such as disabling interrupts), for such a
		 * long time that the processor could execute a *lot* of
		 * instructions - including exiting the interrupt service
		 * routine and re-enabling interrupts.  This effect was
		 * observed to lead to spurious (unclaimed) interrupts in
		 * some circumstances.
		 *
		 * This will no longer be needed once "synchronous" access
		 * handles are available (see PSARC/2000/269 and 2000/531).
		 */
		ddi_put8(rcs->sd_state.sio_handle,
		    rcs->sd_state.sio_regs + reg, val);
		ddi_put8(rcs->sd_state.sio_handle,
		    rcs->sd_state.sio_regs + SIO_SCR, val);
		membar_sync();
		(void) ddi_get8(rcs->sd_state.sio_handle,
		    rcs->sd_state.sio_regs + SIO_SCR);
	}
}
Example #15
0
void
virtio_set_status(struct virtio_softc *sc, unsigned int status)
{
	int old = 0;

	if (status != 0) {
		old = ddi_get8(sc->sc_ioh, (uint8_t *)(sc->sc_io_addr +
		    VIRTIO_CONFIG_DEVICE_STATUS));
	}

	ddi_put8(sc->sc_ioh, (uint8_t *)(sc->sc_io_addr +
	    VIRTIO_CONFIG_DEVICE_STATUS), status | old);
}
Example #16
0
static int
fipe_ioat_trigger(void)
{
	uint16_t ctrl;
	uint32_t err;
	uint8_t	*addr = fipe_ioat_ctrl.ioat_reg_addr;
	ddi_acc_handle_t handle = fipe_ioat_ctrl.ioat_reg_handle;

	/* Check channel in use flag. */
	ctrl = ddi_get16(handle, (uint16_t *)(addr + FIPE_IOAT_CHAN_CTRL));
	if (ctrl & 0x100) {
		/*
		 * Channel is in use by somebody else. IOAT driver may have
		 * been loaded, forbid fipe from accessing IOAT hardware
		 * anymore.
		 */
		fipe_ioat_ctrl.ioat_ready = B_FALSE;
		fipe_ioat_ctrl.ioat_failed = B_TRUE;
		FIPE_KSTAT_INC(ioat_start_fail_cnt);
		return (-1);
	} else {
		/* Set channel in use flag. */
		ddi_put16(handle,
		    (uint16_t *)(addr + FIPE_IOAT_CHAN_CTRL), 0x100);
	}

	/* Write command address. */
	ddi_put32(handle,
	    (uint32_t *)(addr + FIPE_IOAT_CHAN_ADDR_LO),
	    (uint32_t)fipe_ioat_ctrl.ioat_cmd_physaddr);
	ddi_put32(handle, (uint32_t *)(addr + FIPE_IOAT_CHAN_ADDR_HI),
	    (uint32_t)(fipe_ioat_ctrl.ioat_cmd_physaddr >> 32));

	/* Check and clear error flags. */
	err = ddi_get32(handle, (uint32_t *)(addr + FIPE_IOAT_CHAN_ERR));
	if (err != 0) {
		ddi_put32(handle, (uint32_t *)(addr + FIPE_IOAT_CHAN_ERR), err);
	}

	/* Start channel. */
	ddi_put8(handle, (uint8_t *)(addr + FIPE_IOAT_CHAN_CMD), 0x1);

	return (0);
}
static int
ehc_write_pcf8584(struct ehc_envcunit *ehcp, uint8_t data)
{
	uint8_t poll_status;
	int i = 0;

	/* send the data, EHC_S1_PIN should go to "1" immediately */
	ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0, data);

	/* wait for completion of transmission */
	do {
		drv_usecwait(1000);
		poll_status =
			ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
		i++;
	} while ((poll_status & EHC_S1_PIN) && i < EHC_MAX_WAIT);

	if (i == EHC_MAX_WAIT) {
		DCMN_ERR(CE_WARN, "ehc_write_pcf8584(): read of S1 failed");
		return (EHC_FAILURE);
	}

	if (poll_status & EHC_S1_BER) {
		DCMN2_ERR(CE_WARN, "ehc_write_pcf8584(): Bus error");
		ehc_init_pcf8584(ehcp);
		return (EHC_FAILURE);
	}

	if (poll_status & EHC_S1_LAB) {
		DCMN2_ERR(CE_WARN, "ehc_write_pcf8584(): Lost Arbitration");
		ehc_init_pcf8584(ehcp);
		return (EHC_FAILURE);
	}

	if (poll_status & EHC_S1_LRB) {
		DCMN_ERR(CE_WARN, "ehc_write_pcf8584(): No slave ACK");
		return (EHC_NO_SLAVE_ACK);
	}

	return (EHC_SUCCESS);
}
/*
 * put host interface into slave/receiver mode
 */
static void
ehc_stop_pcf8584(struct ehc_envcunit *ehcp)
{
	ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1,
		EHC_S1_PIN | EHC_S1_ES0 | EHC_S1_STO | EHC_S1_ACK);
}
/*
 * put host interface into master mode
 */
static int
ehc_start_pcf8584(struct ehc_envcunit *ehcp, uint8_t byteaddress)
{
	uint8_t poll_status;
	uint8_t discard;
	int i;

	/* wait if bus is busy */

	i = 0;
	do {
		drv_usecwait(1000);
		poll_status =
			ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
		i++;
	} while (((poll_status & EHC_S1_NBB) == 0) && i < EHC_MAX_WAIT);

	if (i == EHC_MAX_WAIT) {
		DCMN_ERR(CE_WARN, "ehc_start_pcf8584(): busy bit clear failed");
		return (EHC_FAILURE);
	}

	if (poll_status & EHC_S1_BER) {
		DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()1: Bus error");
		ehc_init_pcf8584(ehcp);
		return (EHC_FAILURE);
	}

	if (poll_status & EHC_S1_LAB) {
		DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()1: Lost Arbitration");
		ehc_init_pcf8584(ehcp);
		return (EHC_FAILURE);
	}

	/*
	 * This is a dummy arbitration using the lowest unused address
	 * possible. This step allows the PCF8584 to always win arbitration
	 * except in the case of "general call" being issued by the other
	 * master.
	 */
	ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0, DUMMY_WRITE_ADDR);

	/* generate the "start condition" and clock out the slave address */
	ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1,
		EHC_S1_PIN | EHC_S1_ES0 | EHC_S1_STA | EHC_S1_ACK);

	/* wait for completion of transmission */
	i = 0;
	do {
		drv_usecwait(1000);
		poll_status =
			ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
		i++;
	} while ((poll_status & EHC_S1_PIN) && i < EHC_MAX_WAIT);

	if (i == EHC_MAX_WAIT) {
		DCMN_ERR(CE_WARN, "ehc_start_pcf8584_5(): read of S1 failed");
		return (EHC_FAILURE);
	}

	if (poll_status & EHC_S1_BER) {
		DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()5: Bus error");
		ehc_init_pcf8584(ehcp);
		return (EHC_FAILURE);
	}

	if (poll_status & EHC_S1_LAB) {
		DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()5: Lost Arbitration");
		ehc_init_pcf8584(ehcp);
		return (EHC_FAILURE);
	}

	/* dummy write */
	ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0, DUMMY_WRITE_DATA);

	/* wait for completion of transmission */
	i = 0;
	do {
		drv_usecwait(1000);
		poll_status =
			ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
		i++;
	} while ((poll_status & EHC_S1_PIN) && i < EHC_MAX_WAIT);

	if (i == EHC_MAX_WAIT) {
		DCMN_ERR(CE_WARN, "ehc_start_pcf8584(): read of S1 failed");
		return (EHC_FAILURE);
	}

	if (poll_status & EHC_S1_BER) {
		DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()4: Bus error");
		ehc_init_pcf8584(ehcp);
		return (EHC_FAILURE);
	}

	if (poll_status & EHC_S1_LAB) {
		DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()4: Lost Arbitration");
		ehc_init_pcf8584(ehcp);
		return (EHC_FAILURE);
	}

	/*
	 * generate the repeated "start condition" and
	 * clock out the slave address
	 */
	ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1,
		EHC_S1_ES0 | EHC_S1_STA | EHC_S1_ACK);

	/* load the slave address */
	ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0, byteaddress);

	/* wait for completion of transmission */
	i = 0;
	do {
		drv_usecwait(1000);
		poll_status =
			ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
		i++;
	} while ((poll_status & EHC_S1_PIN) && i < EHC_MAX_WAIT);

	if (i == EHC_MAX_WAIT) {
		DCMN_ERR(CE_WARN, "ehc_start_pcf8584(): read of S1 failed");
		return (EHC_FAILURE);
	}

	if (poll_status & EHC_S1_BER) {
		DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()2: Bus error");
		ehc_init_pcf8584(ehcp);
		return (EHC_FAILURE);
	}

	if (poll_status & EHC_S1_LAB) {
		DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()2: Lost Arbitration");
		ehc_init_pcf8584(ehcp);
		return (EHC_FAILURE);
	}

	if (poll_status & EHC_S1_LRB) {
		DCMN_ERR(CE_WARN, "ehc_start_pcf8584(): No slave ACK");
		return (EHC_NO_SLAVE_ACK);
	}

	/*
	 * If this is a read we are setting up for (as indicated by
	 * the least significant byte being set), read
	 * and discard the first byte off the bus - this
	 * is the slave address.
	 */

	i = 0;
	if (byteaddress & EHC_BYTE_READ) {
		discard = ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0);
#ifdef lint
		discard = discard;
#endif

		/* wait for completion of transmission */
		do {
			drv_usecwait(1000);
			poll_status =
			ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
			i++;
		} while ((poll_status & EHC_S1_PIN) && i < EHC_MAX_WAIT);

		if (i == EHC_MAX_WAIT) {
			DCMN_ERR(CE_WARN,
				"ehc_start_pcf8584(): read of S1 failed");
			return (EHC_FAILURE);
		}

		if (poll_status & EHC_S1_BER) {
			DCMN2_ERR(CE_WARN, "ehc_start_pcf8584()3: Bus error");
			ehc_init_pcf8584(ehcp);
			return (EHC_FAILURE);
		}
		if (poll_status & EHC_S1_LAB) {
			DCMN2_ERR(CE_WARN,
				"ehc_start_pcf8584()3: Lost Arbitration");
			ehc_init_pcf8584(ehcp);
			return (EHC_FAILURE);
		}

	}

	return (EHC_SUCCESS);
}
Example #20
0
/* ARGSUSED */
static int
gpio_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
	int *rvalp)
{
	int instance = getminor(dev);
	struct gpio_softc *softc = getsoftc(instance);
	gpio_87317_op_t info;
	uint8_t byte;

	DBG(softc->gp_dip, "ioctl: instance is %d", instance, 0, 0, 0, 0);

	if (softc == NULL)
		return (ENXIO);

	/* Copy the command from user space. */
	if (ddi_copyin((caddr_t)arg, (caddr_t)&info, sizeof (gpio_87317_op_t),
	    mode) != 0)
		return (EFAULT);

	/* Check the command arguments.  We only support port 1 in bank 0. */
	if ((info.gpio_bank != 0) ||
	    (info.gpio_offset != GPIO_87317_PORT1_DATA)) {
		return (EINVAL);
	}

	/* Grap the instance's mutex to insure exclusive access. */
	mutex_enter(&softc->gp_mutex);

	/* Get the contents of the GPIO register we're suppose to modify. */
	byte = ddi_get8(softc->gp_handle, &softc->gp_regs[info.gpio_offset]);

	switch (cmd) {
	case GPIO_CMD_SET_BITS:
		DBG(softc->gp_dip, "ioctl: SET_BITS, byte is %x", byte, 0, 0,
		    0, 0);
		byte |= info.gpio_data;
		ddi_put8(softc->gp_handle, &softc->gp_regs[info.gpio_offset],
		    byte);
		byte = ddi_get8(softc->gp_handle,
		    &softc->gp_regs[info.gpio_offset]);
		DBG(softc->gp_dip, "ioctl: SET_BITS, byte is %x", byte, 0, 0,
		    0, 0);
		break;

	case GPIO_CMD_CLR_BITS:
		DBG(softc->gp_dip, "ioctl: CLR_BITS, byte is %x", byte, 0, 0,
		    0, 0);
		byte &= ~info.gpio_data;
		ddi_put8(softc->gp_handle, &softc->gp_regs[info.gpio_offset],
		    byte);
		byte = ddi_get8(softc->gp_handle,
		    &softc->gp_regs[info.gpio_offset]);
		DBG(softc->gp_dip, "ioctl: CLR_BITS, byte is %x", byte, 0, 0,
		    0, 0);
		break;

	case GPIO_CMD_GET:
		DBG(softc->gp_dip, "ioctl: GPIO_CMD_GET", 0, 0, 0, 0, 0);
		info.gpio_data = byte;
		if (ddi_copyout((caddr_t)&info, (caddr_t)arg,
		    sizeof (gpio_87317_op_t), mode) != 0) {
			mutex_exit(&softc->gp_mutex);
			return (EFAULT);
		}
		break;

	case GPIO_CMD_SET:
		DBG(softc->gp_dip, "ioctl: GPIO_CMD_SET", 0, 0, 0, 0, 0);
		ddi_put8(softc->gp_handle, &softc->gp_regs[info.gpio_offset],
		    info.gpio_data);
		break;

	default:
		mutex_exit(&softc->gp_mutex);
		return (EINVAL);
	}

	mutex_exit(&softc->gp_mutex);
	return (0);
}
void
ipw2200_csr_put8(struct ipw2200_softc *sc, uint32_t off,
	uint8_t val)
{
	ddi_put8(sc->sc_ioh, (uint8_t *)(sc->sc_regs + off), val);
}
/*
 * Read from the PCF8591 chip.
 */
int
ehc_read_pcf8591(struct ehc_envcunit *ehcp, int byteaddress, int channel,
	int autoinc, int amode, int aenable,  uint8_t *buf, int size)
{
	int i;
	int status;
	register uint8_t control;
	uint8_t discard;

	ASSERT((byteaddress & 0x1) == 0);
	ASSERT(channel < 4);
	ASSERT(amode < 4);
	ASSERT(MUTEX_HELD(&ehcp->umutex));

	/*
	 * Write the control word to the PCF8591.
	 * Follow the control word with a repeated START byte
	 * rather than a STOP so that reads can follow without giving
	 * up the bus.
	 */

	control = ((aenable << 6) | (amode << 4) | (autoinc << 2) | channel);

	if ((status = ehc_start_pcf8584(ehcp, byteaddress)) != EHC_SUCCESS) {
		if (status == EHC_NO_SLAVE_ACK) {
			ehc_stop_pcf8584(ehcp);
		}
		return (EHC_FAILURE);
	}

	if ((status = ehc_write_pcf8584(ehcp, control)) != EHC_SUCCESS) {
		if (status == EHC_NO_SLAVE_ACK)
			ehc_stop_pcf8584(ehcp);
		return (EHC_FAILURE);
	}

	/*
	 * The following two operations, 0x45 to S1, and the byteaddress
	 * to S0, will result in a repeated START being sent out on the bus.
	 * Refer to Fig.8 of Philips Semiconductors PCF8584 product spec.
	 */

	ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1,
		EHC_S1_ES0 | EHC_S1_STA | EHC_S1_ACK);

	ddi_put8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0,
		EHC_BYTE_READ | byteaddress);

	i = 0;

	do {
		drv_usecwait(1000);
		status =
			ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s1);
		i++;
	} while ((status & EHC_S1_PIN) && i < EHC_MAX_WAIT);

	if (i == EHC_MAX_WAIT) {
		DCMN_ERR(CE_WARN, "ehc_read_pcf8591(): read of S1 failed");
		return (EHC_FAILURE);
	}

	if (status & EHC_S1_BER) {
		DCMN2_ERR(CE_WARN, "ehc_read_pcf8591(): Bus error");
		ehc_init_pcf8584(ehcp);
		return (EHC_FAILURE);
	}

	if (status & EHC_S1_LAB) {
		DCMN2_ERR(CE_WARN, "ehc_read_pcf8591(): Lost Arbitration");
		ehc_init_pcf8584(ehcp);
		return (EHC_FAILURE);
	}

	if (status & EHC_S1_LRB) {
		DCMN_ERR(CE_WARN, "ehc_read_pcf8591(): No slave ACK");
		/*
		 * Send the stop condition.
		 */
		ehc_stop_pcf8584(ehcp);
		/*
		 * Read the last byte - discard it.
		 */
		discard = ddi_get8(ehcp->ctlr_handle, &ehcp->bus_ctl_regs->s0);
#ifdef lint
		discard = discard;
#endif
		return (EHC_FAILURE);
	}

	/*
	 * Discard first read as per PCF8584 master receiver protocol.
	 * This is normally done in the ehc_start_pcf8584() routine.
	 */
	if ((status = ehc_read_pcf8584(ehcp, &discard)) != EHC_SUCCESS) {
		return (EHC_FAILURE);
	}

	/* Discard second read as per PCF8591 protocol */
	if ((status = ehc_read_pcf8584(ehcp, &discard)) != EHC_SUCCESS) {
		return (EHC_FAILURE);
	}

	for (i = 0; i < size - 1; i++) {
		if ((status = ehc_read_pcf8584(ehcp, &buf[i])) != EHC_SUCCESS) {
			return (EHC_FAILURE);
		}
	}

	if (ehc_after_read_pcf8584(ehcp, &buf[i]) != EHC_SUCCESS) {
		return (EHC_FAILURE);
	}

	return (EHC_SUCCESS);
}
/*
 * Returns 1 if the caller should put the message (bp) back on the queue
 */
static int
mouse8042_initiate_reset(queue_t *q, mblk_t *mp, struct mouse_state *state)
{
	mutex_enter(&state->reset_mutex);
	/*
	 * If we're in the middle of a reset, put the message back on the queue
	 * for processing later.
	 */
	if (state->reset_state != MSE_RESET_IDLE) {
		/*
		 * We noenable the queue again here in case it was backenabled
		 * by an upper-level module.
		 */
		noenable(q);

		mutex_exit(&state->reset_mutex);
		return (1);
	}

	/*
	 * Drop the reset state lock before allocating the response message and
	 * grabbing the 8042 exclusive-access lock (since those operations
	 * may take an extended period of time to complete).
	 */
	mutex_exit(&state->reset_mutex);

	if (state->reply_mp == NULL)
		state->reply_mp = allocb(2, BPRI_MED);
	if (state->reset_ack_mp == NULL)
		state->reset_ack_mp = allocb(1, BPRI_MED);

	if (state->reply_mp == NULL || state->reset_ack_mp == NULL) {
		/*
		 * Allocation failed -- set up a bufcall to enable the queue
		 * whenever there is enough memory to allocate the response
		 * message.
		 */
		state->bc_id = qbufcall(q, (state->reply_mp == NULL) ? 2 : 1,
		    BPRI_MED, (void (*)(void *))qenable, q);

		if (state->bc_id == 0) {
			/*
			 * If the qbufcall failed, we cannot proceed, so use the
			 * message we were sent to respond with an error.
			 */
			*mp->b_rptr = MSEERROR;
			mp->b_wptr = mp->b_rptr + 1;
			qreply(q, mp);
			return (0);
		}

		return (1);
	} else {
		/* Bufcall completed successfully (or wasn't needed) */
		state->bc_id = 0;
	}

	/*
	 * Gain exclusive access to the 8042 for the duration of the reset.
	 * The unlock will occur when the reset has either completed or timed
	 * out.
	 */
	(void) ddi_get8(state->ms_handle,
	    state->ms_addr + I8042_LOCK);

	mutex_enter(&state->reset_mutex);

	state->reset_state = MSE_RESET_PRE;
	noenable(q);

	state->reset_tid = qtimeout(q,
	    mouse8042_reset_timeout,
	    state,
	    drv_usectohz(
	    MOUSE8042_RESET_TIMEOUT_USECS));

	ddi_put8(state->ms_handle,
	    state->ms_addr +
	    I8042_INT_OUTPUT_DATA, MSERESET);

	mp->b_rptr++;

	mutex_exit(&state->reset_mutex);
	return (1);
}