128257Smsmith/*-
255939Snsouch * Copyright (c) 1997, 1998, 1999 Nicolas Souchu
328257Smsmith * All rights reserved.
428257Smsmith *
528257Smsmith * Redistribution and use in source and binary forms, with or without
628257Smsmith * modification, are permitted provided that the following conditions
728257Smsmith * are met:
828257Smsmith * 1. Redistributions of source code must retain the above copyright
928257Smsmith *    notice, this list of conditions and the following disclaimer.
1028257Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1128257Smsmith *    notice, this list of conditions and the following disclaimer in the
1228257Smsmith *    documentation and/or other materials provided with the distribution.
1328257Smsmith *
1428257Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1528257Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1628257Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1728257Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1828257Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1928257Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2028257Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2128257Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2228257Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2328257Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2428257Smsmith * SUCH DAMAGE.
2528257Smsmith */
26119418Sobrien
27119418Sobrien#include <sys/cdefs.h>
28119418Sobrien__FBSDID("$FreeBSD$");
29119418Sobrien
3028257Smsmith#include <sys/param.h>
31187576Sjhb#include <sys/lock.h>
3228257Smsmith#include <sys/kernel.h>
3355939Snsouch#include <sys/module.h>
34187576Sjhb#include <sys/mutex.h>
35187576Sjhb#include <sys/systm.h>
3655939Snsouch#include <sys/bus.h>
3755939Snsouch
3828257Smsmith#include <dev/ppbus/ppbconf.h>
39185003Sjhb
4055939Snsouch#include "ppbus_if.h"
4128257Smsmith
4255939Snsouch#include <dev/ppbus/ppbio.h>
43185003Sjhb
44119284SimpMODULE_VERSION(ppbus, 1);
45119284Simp
4655939Snsouch#define DEVTOSOFTC(dev) ((struct ppb_data *)device_get_softc(dev))
47185003Sjhb
4828257Smsmith/*
4955939Snsouch * ppb_poll_bus()
5028257Smsmith *
5155939Snsouch * Polls the bus
5228257Smsmith *
5328257Smsmith * max is a delay in 10-milliseconds
5428257Smsmith */
5528257Smsmithint
5655939Snsouchppb_poll_bus(device_t bus, int max,
57305555Sdim	     uint8_t mask, uint8_t status, int how)
5828257Smsmith{
59187576Sjhb	struct ppb_data *ppb = DEVTOSOFTC(bus);
6042475Snsouch	int i, j, error;
61305555Sdim	uint8_t r;
6228257Smsmith
63227814Sattilio	ppb_assert_locked(bus);
64187576Sjhb
6542475Snsouch	/* try at least up to 10ms */
6642475Snsouch	for (j = 0; j < ((how & PPB_POLL) ? max : 1); j++) {
6742475Snsouch		for (i = 0; i < 10000; i++) {
6855939Snsouch			r = ppb_rstr(bus);
6942475Snsouch			DELAY(1);
7042475Snsouch			if ((r & mask) == status)
7142475Snsouch				return (0);
7242475Snsouch		}
7342475Snsouch	}
7442475Snsouch
7542475Snsouch	if (!(how & PPB_POLL)) {
7642475Snsouch	   for (i = 0; max == PPB_FOREVER || i < max-1; i++) {
7755939Snsouch		if ((ppb_rstr(bus) & mask) == status)
7828257Smsmith			return (0);
7928257Smsmith
80187576Sjhb		/* wait 10 ms */
81187576Sjhb		error = mtx_sleep((caddr_t)bus, ppb->ppc_lock, PPBPRI |
82187576Sjhb		    (how == PPB_NOINTR ? 0 : PCATCH), "ppbpoll", hz/100);
83187576Sjhb		if (error != EWOULDBLOCK)
84187576Sjhb			return (error);
8542475Snsouch	   }
8628257Smsmith	}
8728257Smsmith
8828257Smsmith	return (EWOULDBLOCK);
8928257Smsmith}
9028257Smsmith
9128257Smsmith/*
9255939Snsouch * ppb_get_epp_protocol()
9338061Smsmith *
9455939Snsouch * Return the chipset EPP protocol
9538061Smsmith */
9638061Smsmithint
9755939Snsouchppb_get_epp_protocol(device_t bus)
9838061Smsmith{
9955939Snsouch	uintptr_t protocol;
10038061Smsmith
101227814Sattilio	ppb_assert_locked(bus);
10255939Snsouch	BUS_READ_IVAR(device_get_parent(bus), bus, PPC_IVAR_EPP_PROTO, &protocol);
10338061Smsmith
10455939Snsouch	return (protocol);
10555939Snsouch}
10655939Snsouch
10755939Snsouch/*
10855939Snsouch * ppb_get_mode()
10955939Snsouch *
11055939Snsouch */
11155939Snsouchint
11255939Snsouchppb_get_mode(device_t bus)
11355939Snsouch{
11455939Snsouch	struct ppb_data *ppb = DEVTOSOFTC(bus);
11555939Snsouch
11638061Smsmith	/* XXX yet device mode = ppbus mode = chipset mode */
117227814Sattilio	ppb_assert_locked(bus);
11855939Snsouch	return (ppb->mode);
11955939Snsouch}
12038061Smsmith
12155939Snsouch/*
12255939Snsouch * ppb_set_mode()
12355939Snsouch *
12455939Snsouch * Set the operating mode of the chipset, return the previous mode
12555939Snsouch */
12655939Snsouchint
12755939Snsouchppb_set_mode(device_t bus, int mode)
12855939Snsouch{
12955939Snsouch	struct ppb_data *ppb = DEVTOSOFTC(bus);
13055939Snsouch	int old_mode = ppb_get_mode(bus);
13155939Snsouch
132227814Sattilio	ppb_assert_locked(bus);
13363458Sn_hibma	if (PPBUS_SETMODE(device_get_parent(bus), mode))
134185003Sjhb		return (-1);
13555939Snsouch
13663458Sn_hibma	/* XXX yet device mode = ppbus mode = chipset mode */
13763458Sn_hibma	ppb->mode = (mode & PPB_MASK);
13863458Sn_hibma
13938061Smsmith	return (old_mode);
14038061Smsmith}
14138061Smsmith
14238061Smsmith/*
14342475Snsouch * ppb_write()
14442475Snsouch *
14542475Snsouch * Write charaters to the port
14642475Snsouch */
14742475Snsouchint
14855939Snsouchppb_write(device_t bus, char *buf, int len, int how)
14942475Snsouch{
150187576Sjhb
151227814Sattilio	ppb_assert_locked(bus);
15255939Snsouch	return (PPBUS_WRITE(device_get_parent(bus), buf, len, how));
15342475Snsouch}
15442475Snsouch
15542475Snsouch/*
15628257Smsmith * ppb_reset_epp_timeout()
15728257Smsmith *
15838061Smsmith * Reset the EPP timeout bit in the status register
15928257Smsmith */
16028257Smsmithint
16155939Snsouchppb_reset_epp_timeout(device_t bus)
16228257Smsmith{
163187576Sjhb
164227814Sattilio	ppb_assert_locked(bus);
16555939Snsouch	return(PPBUS_RESET_EPP(device_get_parent(bus)));
16628257Smsmith}
16728257Smsmith
16828257Smsmith/*
16928257Smsmith * ppb_ecp_sync()
17028257Smsmith *
17138061Smsmith * Wait for the ECP FIFO to be empty
17228257Smsmith */
17328257Smsmithint
17455939Snsouchppb_ecp_sync(device_t bus)
17528257Smsmith{
176187576Sjhb
177227814Sattilio	ppb_assert_locked(bus);
17855939Snsouch	return (PPBUS_ECP_SYNC(device_get_parent(bus)));
17928257Smsmith}
18028257Smsmith
18128257Smsmith/*
18228257Smsmith * ppb_get_status()
18328257Smsmith *
18438061Smsmith * Read the status register and update the status info
18528257Smsmith */
18628257Smsmithint
18755939Snsouchppb_get_status(device_t bus, struct ppb_status *status)
18828257Smsmith{
189305555Sdim	uint8_t r;
19028257Smsmith
191227814Sattilio	ppb_assert_locked(bus);
192187576Sjhb
19355939Snsouch	r = status->status = ppb_rstr(bus);
19428257Smsmith
19528257Smsmith	status->timeout	= r & TIMEOUT;
19628257Smsmith	status->error	= !(r & nFAULT);
19728257Smsmith	status->select	= r & SELECT;
19839134Snsouch	status->paper_end = r & PERROR;
19928257Smsmith	status->ack	= !(r & nACK);
20028257Smsmith	status->busy	= !(r & nBUSY);
20128257Smsmith
20228257Smsmith	return (0);
20328257Smsmith}
204187576Sjhb
205187576Sjhbvoid
206187576Sjhbppb_lock(device_t bus)
207187576Sjhb{
208187576Sjhb	struct ppb_data *ppb = DEVTOSOFTC(bus);
209187576Sjhb
210187576Sjhb	mtx_lock(ppb->ppc_lock);
211187576Sjhb}
212187576Sjhb
213187576Sjhbvoid
214187576Sjhbppb_unlock(device_t bus)
215187576Sjhb{
216187576Sjhb	struct ppb_data *ppb = DEVTOSOFTC(bus);
217187576Sjhb
218187576Sjhb	mtx_unlock(ppb->ppc_lock);
219187576Sjhb}
220187576Sjhb
221187576Sjhbvoid
222187576Sjhb_ppb_assert_locked(device_t bus, const char *file, int line)
223187576Sjhb{
224187576Sjhb
225227758Sattilio	mtx_assert_(DEVTOSOFTC(bus)->ppc_lock, MA_OWNED, file, line);
226187576Sjhb}
227187576Sjhb
228187576Sjhbvoid
229187576Sjhbppb_init_callout(device_t bus, struct callout *c, int flags)
230187576Sjhb{
231187576Sjhb	struct ppb_data *ppb = DEVTOSOFTC(bus);
232187576Sjhb
233187576Sjhb	callout_init_mtx(c, ppb->ppc_lock, flags);
234187576Sjhb}
235187576Sjhb
236187576Sjhbint
237187576Sjhbppb_sleep(device_t bus, void *wchan, int priority, const char *wmesg, int timo)
238187576Sjhb{
239187576Sjhb	struct ppb_data *ppb = DEVTOSOFTC(bus);
240187576Sjhb
241187576Sjhb	return (mtx_sleep(wchan, ppb->ppc_lock, priority, wmesg, timo));
242187576Sjhb}
243