Various small changes.
Clean up one bug in a DPRINTF in arrs_input which could panic on some packets. Gut the ack/response functionality and clean it up so all packets get checked correctly and the abuf struct isn't used once the ab_cb has happened (there still could be ack packets waiting to be processed at that time). Finally, add some documentation explaining read/write/inreg and their purpose/argument calling.
This commit is contained in:
parent
d91da495a9
commit
c3967bca55
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: fwohci.c,v 1.30 2001/05/13 05:01:42 jmc Exp $ */
|
/* $NetBSD: fwohci.c,v 1.31 2001/05/15 06:52:30 jmc Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||||
@ -147,9 +147,9 @@ static int fwohci_if_output(struct device *, struct mbuf *,
|
|||||||
void (*)(struct device *, struct mbuf *));
|
void (*)(struct device *, struct mbuf *));
|
||||||
static int fwohci_read(struct ieee1394_abuf *);
|
static int fwohci_read(struct ieee1394_abuf *);
|
||||||
static int fwohci_write(struct ieee1394_abuf *);
|
static int fwohci_write(struct ieee1394_abuf *);
|
||||||
static int fwohci_extract_resp(struct fwohci_softc *, void *,
|
static int fwohci_read_resp(struct fwohci_softc *, void *, struct fwohci_pkt *);
|
||||||
struct fwohci_pkt *);
|
static int fwohci_write_ack(struct fwohci_softc *, void *, struct fwohci_pkt *);
|
||||||
static int fwohci_multi_resp(struct fwohci_softc *, void *,
|
static int fwohci_read_multi_resp(struct fwohci_softc *, void *,
|
||||||
struct fwohci_pkt *);
|
struct fwohci_pkt *);
|
||||||
static int fwohci_inreg(struct ieee1394_abuf *, int);
|
static int fwohci_inreg(struct ieee1394_abuf *, int);
|
||||||
static int fwohci_parse_input(struct fwohci_softc *, void *,
|
static int fwohci_parse_input(struct fwohci_softc *, void *,
|
||||||
@ -1550,15 +1550,8 @@ fwohci_arrs_input(struct fwohci_softc *sc, struct fwohci_ctx *fc)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef FW_DEBUG
|
if (fh == NULL)
|
||||||
if (fh == NULL) {
|
|
||||||
DPRINTFN(1, ("fwohci_arrs_input: no listner\n"));
|
DPRINTFN(1, ("fwohci_arrs_input: no listner\n"));
|
||||||
DPRINTFN(1, ("src: %d, rcode: %d, tlabel: %d, tcode: "
|
|
||||||
"%d hdr[3]: 0x%08x, data: 0x%08lx\n", srcid, rcode,
|
|
||||||
tlabel, pkt.fp_tcode, pkt.fp_hdr[3],
|
|
||||||
(unsigned long)(*((int *)pkt.fp_iov[0].iov_base))));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
fwohci_buf_next(sc, fc);
|
fwohci_buf_next(sc, fc);
|
||||||
OHCI_ASYNC_DMA_WRITE(sc, fc->fc_ctx,
|
OHCI_ASYNC_DMA_WRITE(sc, fc->fc_ctx,
|
||||||
@ -2771,6 +2764,52 @@ fwohci_if_output(struct device *self, struct mbuf *m0,
|
|||||||
* send/receive data.
|
* send/receive data.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These break down into 4 routines as follows:
|
||||||
|
*
|
||||||
|
* int fwohci_read(struct ieee1394_abuf *)
|
||||||
|
*
|
||||||
|
* This routine will attempt to read a region from the requested node.
|
||||||
|
* A callback must be provided which will be called when either the completed
|
||||||
|
* read is done or an unrecoverable error occurs. This is mainly a convenience
|
||||||
|
* routine since it will encapsulate retrying a region as quadlet vs. block reads
|
||||||
|
* and recombining all the returned data. This could also be done with a series
|
||||||
|
* of write/inreg's for each packet sent.
|
||||||
|
*
|
||||||
|
* int fwohci_write(struct ieee1394_abuf *)
|
||||||
|
*
|
||||||
|
* The work horse main entry point for putting packets on the bus. This is the
|
||||||
|
* generalized interface for fwnode/etc code to put packets out onto the bus.
|
||||||
|
* It accepts all standard ieee1394 tcodes (XXX: only a few today) and optionally
|
||||||
|
* will callback via a func pointer to the calling code with the resulting ACK
|
||||||
|
* code from the packet. If the ACK code is to be ignored (i.e. no cb) then the
|
||||||
|
* write routine will take care of free'ing the abuf since the fwnode/etc code
|
||||||
|
* won't have any knowledge of when to do this. This allows for simple one-off
|
||||||
|
* packets to be sent from the upper-level code without worrying about a callback
|
||||||
|
* for cleanup.
|
||||||
|
*
|
||||||
|
* int fwohci_inreg(struct ieee1394_abuf *, int)
|
||||||
|
*
|
||||||
|
* This is very simple. It evals the abuf passed in and registers an internal
|
||||||
|
* handler as the callback for packets received for that operation.
|
||||||
|
* The integer argument specifies whether on a block read/write operation to
|
||||||
|
* allow sub-regions to be read/written (in block form) as well.
|
||||||
|
*
|
||||||
|
* XXX: This whole structure needs to be redone as a list of regions and
|
||||||
|
* operations allowed on those regions.
|
||||||
|
*
|
||||||
|
* int fwohci_unreg(struct ieee1394_abuf *, int)
|
||||||
|
*
|
||||||
|
* XXX: TBD. For now passing in a NULL ab_cb to inreg will unregister. This
|
||||||
|
* routine will simply verify ab_cb is NULL and call inreg.
|
||||||
|
*
|
||||||
|
* This simply unregisters the respective callback done via inreg for items
|
||||||
|
* which only need to register an area for a one-time operation (like a status
|
||||||
|
* buffer a remote node will write to when the current operation is done). The
|
||||||
|
* int argument specifies the same behavior as inreg, except in reverse (i.e.
|
||||||
|
* it unregisters).
|
||||||
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
fwohci_read(struct ieee1394_abuf *ab)
|
fwohci_read(struct ieee1394_abuf *ab)
|
||||||
{
|
{
|
||||||
@ -2778,9 +2817,19 @@ fwohci_read(struct ieee1394_abuf *ab)
|
|||||||
struct ieee1394_softc *sc = ab->ab_req;
|
struct ieee1394_softc *sc = ab->ab_req;
|
||||||
struct fwohci_softc *psc =
|
struct fwohci_softc *psc =
|
||||||
(struct fwohci_softc *)sc->sc1394_dev.dv_parent;
|
(struct fwohci_softc *)sc->sc1394_dev.dv_parent;
|
||||||
|
struct fwohci_cb *fcb;
|
||||||
u_int32_t high, lo;
|
u_int32_t high, lo;
|
||||||
int rv, tcode;
|
int rv, tcode;
|
||||||
|
|
||||||
|
/* Have to have a callback when reading. */
|
||||||
|
if (ab->ab_cb == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
fcb = malloc(sizeof(struct fwohci_cb), M_DEVBUF, M_WAITOK);
|
||||||
|
fcb->ab = ab;
|
||||||
|
fcb->count = 0;
|
||||||
|
fcb->abuf_valid = 1;
|
||||||
|
|
||||||
high = ((ab->ab_csr & 0x0000ffff00000000) >> 32);
|
high = ((ab->ab_csr & 0x0000ffff00000000) >> 32);
|
||||||
lo = (ab->ab_csr & 0x00000000ffffffff);
|
lo = (ab->ab_csr & 0x00000000ffffffff);
|
||||||
|
|
||||||
@ -2802,15 +2851,19 @@ fwohci_read(struct ieee1394_abuf *ab)
|
|||||||
pkt.fp_hdr[0] = 0x00000100 | (sc->sc1394_link_speed << 16) |
|
pkt.fp_hdr[0] = 0x00000100 | (sc->sc1394_link_speed << 16) |
|
||||||
(psc->sc_tlabel << 10) | (pkt.fp_tcode << 4);
|
(psc->sc_tlabel << 10) | (pkt.fp_tcode << 4);
|
||||||
|
|
||||||
pkt.fp_statusarg = ab;
|
pkt.fp_statusarg = fcb;
|
||||||
pkt.fp_statuscb = fwohci_extract_resp;
|
pkt.fp_statuscb = fwohci_read_resp;
|
||||||
|
|
||||||
rv = fwohci_handler_set(psc, tcode, ab->ab_req->sc1394_node_id,
|
rv = fwohci_handler_set(psc, tcode, ab->ab_req->sc1394_node_id,
|
||||||
psc->sc_tlabel, fwohci_extract_resp, ab);
|
psc->sc_tlabel, fwohci_read_resp, fcb);
|
||||||
if (rv)
|
if (rv)
|
||||||
return rv;
|
return rv;
|
||||||
psc->sc_tlabel = (psc->sc_tlabel + 1) & 0x3f;
|
|
||||||
rv = fwohci_at_output(psc, psc->sc_ctx_atrq, &pkt);
|
rv = fwohci_at_output(psc, psc->sc_ctx_atrq, &pkt);
|
||||||
|
if (rv)
|
||||||
|
fwohci_handler_set(psc, tcode, ab->ab_req->sc1394_node_id,
|
||||||
|
psc->sc_tlabel, NULL, NULL);
|
||||||
|
psc->sc_tlabel = (psc->sc_tlabel + 1) & 0x3f;
|
||||||
|
fcb->count = 1;
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2836,6 +2889,9 @@ fwohci_write(struct ieee1394_abuf *ab)
|
|||||||
pkt.fp_uio.uio_segflg = UIO_SYSSPACE;
|
pkt.fp_uio.uio_segflg = UIO_SYSSPACE;
|
||||||
pkt.fp_uio.uio_rw = UIO_WRITE;
|
pkt.fp_uio.uio_rw = UIO_WRITE;
|
||||||
|
|
||||||
|
pkt.fp_statusarg = ab;
|
||||||
|
pkt.fp_statuscb = fwohci_write_ack;
|
||||||
|
|
||||||
switch (ab->ab_tcode) {
|
switch (ab->ab_tcode) {
|
||||||
case IEEE1394_TCODE_WRITE_RESP:
|
case IEEE1394_TCODE_WRITE_RESP:
|
||||||
pkt.fp_hlen = 12;
|
pkt.fp_hlen = 12;
|
||||||
@ -2880,12 +2936,6 @@ fwohci_write(struct ieee1394_abuf *ab)
|
|||||||
rv = fwohci_at_output(psc, psc->sc_ctx_atrs, &pkt);
|
rv = fwohci_at_output(psc, psc->sc_ctx_atrs, &pkt);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rv = fwohci_handler_set(psc, IEEE1394_TCODE_WRITE_RESP,
|
|
||||||
ab->ab_req->sc1394_node_id, psc->sc_tlabel,
|
|
||||||
fwohci_extract_resp, ab);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
psc->sc_tlabel = (psc->sc_tlabel + 1) & 0x3f;
|
|
||||||
rv = fwohci_at_output(psc, psc->sc_ctx_atrq, &pkt);
|
rv = fwohci_at_output(psc, psc->sc_ctx_atrq, &pkt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2893,76 +2943,70 @@ fwohci_write(struct ieee1394_abuf *ab)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
fwohci_extract_resp(struct fwohci_softc *sc, void *arg, struct fwohci_pkt *pkt)
|
fwohci_read_resp(struct fwohci_softc *sc, void *arg, struct fwohci_pkt *pkt)
|
||||||
{
|
{
|
||||||
struct ieee1394_abuf *ab = (struct ieee1394_abuf *)arg;
|
struct fwohci_cb *fcb = arg;
|
||||||
|
struct ieee1394_abuf *ab = fcb->ab;
|
||||||
struct fwohci_pkt newpkt;
|
struct fwohci_pkt newpkt;
|
||||||
u_int16_t status;
|
|
||||||
u_int32_t *cur, high, lo;
|
u_int32_t *cur, high, lo;
|
||||||
int i, rcode, rv;
|
int i, tcode, rcode, status, rv;
|
||||||
|
|
||||||
status = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* No callback just means we want to have something clean up the abuf.
|
* Both the ACK handling and normal response callbacks are handled here.
|
||||||
|
* The main reason for this is the various error conditions that can
|
||||||
|
* occur trying to block read some areas and the ways that gets reported
|
||||||
|
* back to calling station. This is a variety of ACK codes, responses,
|
||||||
|
* etc which makes it much more difficult to process if both aren't
|
||||||
|
* handled here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (ab->ab_cb == NULL) {
|
|
||||||
if (ab->ab_data)
|
|
||||||
free(ab->ab_data, M_1394DATA);
|
|
||||||
if (ab)
|
|
||||||
free(ab, M_1394DATA);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for status packet. */
|
/* Check for status packet. */
|
||||||
|
|
||||||
if (pkt->fp_tcode == -1) {
|
if (pkt->fp_tcode == -1) {
|
||||||
status = pkt->fp_status & OHCI_DESC_STATUS_ACK_MASK;
|
status = pkt->fp_status & OHCI_DESC_STATUS_ACK_MASK;
|
||||||
pkt->fp_tcode = (pkt->fp_hdr[0] >> 4) & 0xf;
|
rcode = -1;
|
||||||
|
tcode = (pkt->fp_hdr[0] >> 4) & 0xf;
|
||||||
|
if ((status != OHCI_CTXCTL_EVENT_ACK_COMPLETE) &&
|
||||||
|
(status != OHCI_CTXCTL_EVENT_ACK_PENDING))
|
||||||
|
DPRINTF(("Got status packet: 0x%02x\n",
|
||||||
|
(unsigned int)status));
|
||||||
|
fcb->count--;
|
||||||
|
|
||||||
/* See below for this exception that's trapped internally. */
|
/*
|
||||||
if (ab->ab_ackcb &&
|
* Got all the ack's back and the buffer is invalid (i.e. the
|
||||||
!((status == OHCI_CTXCTL_EVENT_ACK_TYPE_ERROR) &&
|
* callback has been called. Clean up.
|
||||||
(pkt->fp_tcode == IEEE1394_TCODE_READ_REQ_BLOCK))) {
|
*/
|
||||||
|
|
||||||
/*
|
if (fcb->abuf_valid == 0) {
|
||||||
* XXX: Deal with this better. Trap OHCI code and
|
if (fcb->count == 0)
|
||||||
* translate/deal with the results.
|
free(fcb, M_DEVBUF);
|
||||||
*/
|
|
||||||
|
|
||||||
if (status >= OHCI_CTXCTL_EVENT_RESERVED16)
|
|
||||||
status = status & 0xf;
|
|
||||||
else
|
|
||||||
status = 0;
|
|
||||||
ab->ab_ackcb(ab, status);
|
|
||||||
return IEEE1394_RCODE_COMPLETE;
|
return IEEE1394_RCODE_COMPLETE;
|
||||||
}
|
}
|
||||||
if (!((status == OHCI_CTXCTL_EVENT_ACK_TYPE_ERROR) &&
|
} else {
|
||||||
(pkt->fp_tcode == IEEE1394_TCODE_READ_REQ_BLOCK)))
|
status = -1;
|
||||||
return IEEE1394_RCODE_COMPLETE;
|
tcode = pkt->fp_tcode;
|
||||||
|
|
||||||
} else
|
|
||||||
rcode = (pkt->fp_hdr[1] & 0x0000f000) >> 12;
|
rcode = (pkt->fp_hdr[1] & 0x0000f000) >> 12;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some area's (like the config rom want to be read as quadlets only.
|
* Some area's (like the config rom want to be read as quadlets only.
|
||||||
*
|
*
|
||||||
* The current ideas to try are:
|
* The current ideas to try are:
|
||||||
*
|
*
|
||||||
* Got an ACK_TYPE_ERROR on a block read
|
* Got an ACK_TYPE_ERROR on a block read.
|
||||||
*
|
*
|
||||||
* Got either RCODE_TYPE or RCODE_ADDRESS errors in a read block response
|
* Got either RCODE_TYPE or RCODE_ADDRESS errors in a block read
|
||||||
|
* response.
|
||||||
*
|
*
|
||||||
* If all cases construct a new packet for a quadlet read and let
|
* In all cases construct a new packet for a quadlet read and let
|
||||||
* mutli_resp handle the iteration over the space.
|
* mutli_resp handle the iteration over the space.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (((status == OHCI_CTXCTL_EVENT_ACK_TYPE_ERROR) &&
|
if (((status == OHCI_CTXCTL_EVENT_ACK_TYPE_ERROR) &&
|
||||||
(pkt->fp_tcode == IEEE1394_TCODE_READ_REQ_BLOCK)) ||
|
(tcode == IEEE1394_TCODE_READ_REQ_BLOCK)) ||
|
||||||
(((rcode == IEEE1394_RCODE_TYPE_ERROR) ||
|
(((rcode == IEEE1394_RCODE_TYPE_ERROR) ||
|
||||||
(rcode == IEEE1394_RCODE_ADDRESS_ERROR)) &&
|
(rcode == IEEE1394_RCODE_ADDRESS_ERROR)) &&
|
||||||
(pkt->fp_tcode == IEEE1394_TCODE_READ_RESP_BLOCK))) {
|
(tcode == IEEE1394_TCODE_READ_RESP_BLOCK))) {
|
||||||
|
|
||||||
/* Read the area in quadlet chunks (internally track this). */
|
/* Read the area in quadlet chunks (internally track this). */
|
||||||
|
|
||||||
@ -2982,49 +3026,80 @@ fwohci_extract_resp(struct fwohci_softc *sc, void *arg, struct fwohci_pkt *pkt)
|
|||||||
|
|
||||||
rv = fwohci_handler_set(sc, IEEE1394_TCODE_READ_RESP_QUAD,
|
rv = fwohci_handler_set(sc, IEEE1394_TCODE_READ_RESP_QUAD,
|
||||||
ab->ab_req->sc1394_node_id, sc->sc_tlabel,
|
ab->ab_req->sc1394_node_id, sc->sc_tlabel,
|
||||||
fwohci_multi_resp, ab);
|
fwohci_read_multi_resp, fcb);
|
||||||
if (rv)
|
if (rv) {
|
||||||
return rv;
|
(*ab->ab_cb)(ab, -1);
|
||||||
sc->sc_tlabel = (sc->sc_tlabel + 1) & 0x3f;
|
goto cleanup;
|
||||||
if (ab->ab_ackcb) {
|
|
||||||
newpkt.fp_statusarg = ab;
|
|
||||||
newpkt.fp_statuscb = fwohci_extract_resp;
|
|
||||||
}
|
}
|
||||||
fwohci_at_output(sc, sc->sc_ctx_atrq, &newpkt);
|
newpkt.fp_statusarg = fcb;
|
||||||
} else {
|
newpkt.fp_statuscb = fwohci_read_resp;
|
||||||
|
rv = fwohci_at_output(sc, sc->sc_ctx_atrq, &newpkt);
|
||||||
|
if (rv) {
|
||||||
|
fwohci_handler_set(sc, IEEE1394_TCODE_READ_RESP_QUAD,
|
||||||
|
ab->ab_req->sc1394_node_id, sc->sc_tlabel, NULL,
|
||||||
|
NULL);
|
||||||
|
(*ab->ab_cb)(ab, -1);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
fcb->count++;
|
||||||
|
sc->sc_tlabel = (sc->sc_tlabel + 1) & 0x3f;
|
||||||
|
return IEEE1394_RCODE_COMPLETE;
|
||||||
|
} else if ((rcode != -1) || ((status != -1) &&
|
||||||
|
(status != OHCI_CTXCTL_EVENT_ACK_COMPLETE) &&
|
||||||
|
(status != OHCI_CTXCTL_EVENT_ACK_PENDING))) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Recombine all the iov data into 1 chunk for higher
|
* Recombine all the iov data into 1 chunk for higher
|
||||||
* level code.
|
* level code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
cur = ab->ab_data;
|
if (rcode != -1) {
|
||||||
for (i = 0; i < pkt->fp_uio.uio_iovcnt; i++) {
|
cur = ab->ab_data;
|
||||||
/*
|
for (i = 0; i < pkt->fp_uio.uio_iovcnt; i++) {
|
||||||
* Make sure and don't exceed the buffer
|
/*
|
||||||
* allocated for return.
|
* Make sure and don't exceed the buffer
|
||||||
*/
|
* allocated for return.
|
||||||
if ((ab->ab_retlen + pkt->fp_iov[i].iov_len) >
|
*/
|
||||||
ab->ab_length) {
|
if ((ab->ab_retlen + pkt->fp_iov[i].iov_len) >
|
||||||
|
ab->ab_length) {
|
||||||
|
memcpy(cur, pkt->fp_iov[i].iov_base,
|
||||||
|
(ab->ab_length - ab->ab_retlen));
|
||||||
|
ab->ab_retlen = ab->ab_length;
|
||||||
|
break;
|
||||||
|
}
|
||||||
memcpy(cur, pkt->fp_iov[i].iov_base,
|
memcpy(cur, pkt->fp_iov[i].iov_base,
|
||||||
(ab->ab_length - ab->ab_retlen));
|
pkt->fp_iov[i].iov_len);
|
||||||
ab->ab_retlen = ab->ab_length;
|
cur += pkt->fp_iov[i].iov_len;
|
||||||
break;
|
ab->ab_retlen += pkt->fp_iov[i].iov_len;
|
||||||
}
|
}
|
||||||
memcpy(cur, pkt->fp_iov[i].iov_base,
|
|
||||||
pkt->fp_iov[i].iov_len);
|
|
||||||
cur += pkt->fp_iov[i].iov_len;
|
|
||||||
ab->ab_retlen += pkt->fp_iov[i].iov_len;
|
|
||||||
}
|
}
|
||||||
|
if (status != -1)
|
||||||
|
/* XXX: Need a complete tlabel interface. */
|
||||||
|
for (i = 0; i < 64; i++)
|
||||||
|
fwohci_handler_set(sc,
|
||||||
|
IEEE1394_TCODE_READ_RESP_QUAD,
|
||||||
|
ab->ab_req->sc1394_node_id, i, NULL, NULL);
|
||||||
(*ab->ab_cb)(ab, rcode);
|
(*ab->ab_cb)(ab, rcode);
|
||||||
}
|
goto cleanup;
|
||||||
|
} else
|
||||||
|
/* Good ack packet. */
|
||||||
|
return IEEE1394_RCODE_COMPLETE;
|
||||||
|
|
||||||
|
/* Can't get here unless ab->ab_cb has been called. */
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
fcb->abuf_valid = 0;
|
||||||
|
if (fcb->count == 0)
|
||||||
|
free(fcb, M_DEVBUF);
|
||||||
return IEEE1394_RCODE_COMPLETE;
|
return IEEE1394_RCODE_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
fwohci_multi_resp(struct fwohci_softc *sc, void *arg, struct fwohci_pkt *pkt)
|
fwohci_read_multi_resp(struct fwohci_softc *sc, void *arg,
|
||||||
|
struct fwohci_pkt *pkt)
|
||||||
{
|
{
|
||||||
struct ieee1394_abuf *ab = (struct ieee1394_abuf *)arg;
|
struct fwohci_cb *fcb = arg;
|
||||||
|
struct ieee1394_abuf *ab = fcb->ab;
|
||||||
struct fwohci_pkt newpkt;
|
struct fwohci_pkt newpkt;
|
||||||
u_int32_t high, lo;
|
u_int32_t high, lo;
|
||||||
int rcode, rv;
|
int rcode, rv;
|
||||||
@ -3034,11 +3109,15 @@ fwohci_multi_resp(struct fwohci_softc *sc, void *arg, struct fwohci_pkt *pkt)
|
|||||||
* buf.
|
* buf.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Make sure a response packet didn't arrive after a bad ACK. */
|
||||||
|
if (fcb->abuf_valid == 0)
|
||||||
|
return IEEE1394_RCODE_COMPLETE;
|
||||||
|
|
||||||
rcode = (pkt->fp_hdr[1] & 0x0000f000) >> 12;
|
rcode = (pkt->fp_hdr[1] & 0x0000f000) >> 12;
|
||||||
|
|
||||||
if (rcode) {
|
if (rcode) {
|
||||||
(*ab->ab_cb)(ab, rcode);
|
(*ab->ab_cb)(ab, rcode);
|
||||||
return rcode;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ab->ab_retlen + pkt->fp_iov[0].iov_len) > ab->ab_length) {
|
if ((ab->ab_retlen + pkt->fp_iov[0].iov_len) > ab->ab_length) {
|
||||||
@ -3066,25 +3145,64 @@ fwohci_multi_resp(struct fwohci_softc *sc, void *arg, struct fwohci_pkt *pkt)
|
|||||||
newpkt.fp_hdr[0] = 0x00000100 | (sc->sc_tlabel << 10) |
|
newpkt.fp_hdr[0] = 0x00000100 | (sc->sc_tlabel << 10) |
|
||||||
(newpkt.fp_tcode << 4);
|
(newpkt.fp_tcode << 4);
|
||||||
|
|
||||||
|
newpkt.fp_statusarg = fcb;
|
||||||
|
newpkt.fp_statuscb = fwohci_read_resp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bad return code. Just give up and return what's
|
* Bad return code. Just give up and return what's
|
||||||
* come in now.
|
* come in now.
|
||||||
*/
|
*/
|
||||||
rv = fwohci_handler_set(sc, IEEE1394_TCODE_READ_RESP_QUAD,
|
rv = fwohci_handler_set(sc, IEEE1394_TCODE_READ_RESP_QUAD,
|
||||||
ab->ab_req->sc1394_node_id, sc->sc_tlabel,
|
ab->ab_req->sc1394_node_id, sc->sc_tlabel,
|
||||||
fwohci_multi_resp, ab);
|
fwohci_read_multi_resp, fcb);
|
||||||
if (rv) {
|
if (rv)
|
||||||
(*ab->ab_cb)(ab, rcode);
|
(*ab->ab_cb)(ab, -1);
|
||||||
return IEEE1394_RCODE_DATA_ERROR;
|
else {
|
||||||
|
rv = fwohci_at_output(sc, sc->sc_ctx_atrq, &newpkt);
|
||||||
|
if (rv) {
|
||||||
|
fwohci_handler_set(sc,
|
||||||
|
IEEE1394_TCODE_READ_RESP_QUAD,
|
||||||
|
ab->ab_req->sc1394_node_id, sc->sc_tlabel,
|
||||||
|
NULL, NULL);
|
||||||
|
(*ab->ab_cb)(ab, -1);
|
||||||
|
} else {
|
||||||
|
sc->sc_tlabel = (sc->sc_tlabel + 1) & 0x3f;
|
||||||
|
fcb->count++;
|
||||||
|
return IEEE1394_RCODE_COMPLETE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sc->sc_tlabel = (sc->sc_tlabel + 1) & 0x3f;
|
} else
|
||||||
rv = fwohci_at_output(sc, sc->sc_ctx_atrq, &newpkt);
|
(*ab->ab_cb)(ab, IEEE1394_RCODE_COMPLETE);
|
||||||
if (rv) {
|
|
||||||
(*ab->ab_cb)(ab, rcode);
|
cleanup:
|
||||||
return IEEE1394_RCODE_DATA_ERROR;
|
/* Can't get here unless ab_cb has been called. */
|
||||||
}
|
fcb->abuf_valid = 0;
|
||||||
} else
|
if (fcb->count == 0)
|
||||||
(*ab->ab_cb)(ab, rcode);
|
free(fcb, M_DEVBUF);
|
||||||
|
return IEEE1394_RCODE_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
fwohci_write_ack(struct fwohci_softc *sc, void *arg, struct fwohci_pkt *pkt)
|
||||||
|
{
|
||||||
|
struct ieee1394_abuf *ab = arg;
|
||||||
|
u_int16_t status;
|
||||||
|
|
||||||
|
|
||||||
|
status = pkt->fp_status & OHCI_DESC_STATUS_ACK_MASK;
|
||||||
|
if ((status != OHCI_CTXCTL_EVENT_ACK_COMPLETE) &&
|
||||||
|
(status != OHCI_CTXCTL_EVENT_ACK_PENDING))
|
||||||
|
DPRINTF(("Got status packet: 0x%02x\n",
|
||||||
|
(unsigned int)status));
|
||||||
|
|
||||||
|
/* No callback means this level should free the buffers. */
|
||||||
|
if (ab->ab_cb)
|
||||||
|
(*ab->ab_cb)(ab, status);
|
||||||
|
else {
|
||||||
|
if (ab->ab_data)
|
||||||
|
free(ab->ab_data, M_1394DATA);
|
||||||
|
free(ab, M_1394DATA);
|
||||||
|
}
|
||||||
return IEEE1394_RCODE_COMPLETE;
|
return IEEE1394_RCODE_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3095,31 +3213,51 @@ fwohci_inreg(struct ieee1394_abuf *ab, int allow)
|
|||||||
struct fwohci_softc *psc =
|
struct fwohci_softc *psc =
|
||||||
(struct fwohci_softc *)sc->sc1394_dev.dv_parent;
|
(struct fwohci_softc *)sc->sc1394_dev.dv_parent;
|
||||||
u_int32_t high, lo;
|
u_int32_t high, lo;
|
||||||
int i, rv;
|
int i, j, rv;
|
||||||
|
|
||||||
high = ((ab->ab_csr & 0x0000ffff00000000) >> 32);
|
high = ((ab->ab_csr & 0x0000ffff00000000) >> 32);
|
||||||
lo = (ab->ab_csr & 0x00000000ffffffff);
|
lo = (ab->ab_csr & 0x00000000ffffffff);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
switch (ab->ab_tcode) {
|
switch (ab->ab_tcode) {
|
||||||
case IEEE1394_TCODE_READ_REQ_QUAD:
|
case IEEE1394_TCODE_READ_REQ_QUAD:
|
||||||
case IEEE1394_TCODE_WRITE_REQ_QUAD:
|
case IEEE1394_TCODE_WRITE_REQ_QUAD:
|
||||||
rv = fwohci_handler_set(psc, ab->ab_tcode, high, lo,
|
if (ab->ab_cb)
|
||||||
fwohci_parse_input, ab);
|
rv = fwohci_handler_set(psc, ab->ab_tcode, high, lo,
|
||||||
|
fwohci_parse_input, ab);
|
||||||
|
else
|
||||||
|
fwohci_handler_set(psc, ab->ab_tcode, high, lo, NULL,
|
||||||
|
NULL);
|
||||||
break;
|
break;
|
||||||
case IEEE1394_TCODE_READ_REQ_BLOCK:
|
case IEEE1394_TCODE_READ_REQ_BLOCK:
|
||||||
case IEEE1394_TCODE_WRITE_REQ_BLOCK:
|
case IEEE1394_TCODE_WRITE_REQ_BLOCK:
|
||||||
if (allow) {
|
if (allow) {
|
||||||
for (i = 0; i < (ab->ab_length / 4); i++) {
|
for (i = 0; i < (ab->ab_length / 4); i++) {
|
||||||
rv = fwohci_handler_set(psc, ab->ab_tcode,
|
if (ab->ab_cb) {
|
||||||
high, lo + (i * 4),
|
rv = fwohci_handler_set(psc,
|
||||||
fwohci_parse_input, ab);
|
ab->ab_tcode, high, lo + (i * 4),
|
||||||
if (rv)
|
fwohci_parse_input, ab);
|
||||||
return rv;
|
if (rv)
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
fwohci_handler_set(psc, ab->ab_tcode,
|
||||||
|
high, lo + (i * 4), NULL, NULL);
|
||||||
}
|
}
|
||||||
ab->ab_data = (void *)1;
|
if (i != (ab->ab_length / 4)) {
|
||||||
} else
|
j = i + 1;
|
||||||
rv = fwohci_handler_set(psc, ab->ab_tcode, high, lo,
|
for (i = 0; i < j; i++)
|
||||||
fwohci_parse_input, ab);
|
fwohci_handler_set(psc, ab->ab_tcode,
|
||||||
|
high, lo + (i * 4), NULL, NULL);
|
||||||
|
} else
|
||||||
|
ab->ab_data = (void *)1;
|
||||||
|
} else {
|
||||||
|
if (ab->ab_cb)
|
||||||
|
rv = fwohci_handler_set(psc, ab->ab_tcode, high,
|
||||||
|
lo, fwohci_parse_input, ab);
|
||||||
|
else
|
||||||
|
fwohci_handler_set(psc, ab->ab_tcode, high, lo,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DPRINTF(("Invalid registration tcode: %d\n", ab->ab_tcode));
|
DPRINTF(("Invalid registration tcode: %d\n", ab->ab_tcode));
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: fwohcivar.h,v 1.13 2001/05/13 05:01:43 jmc Exp $ */
|
/* $NetBSD: fwohcivar.h,v 1.14 2001/05/15 06:52:31 jmc Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||||
@ -115,6 +115,19 @@ struct fwohci_uidtbl {
|
|||||||
u_int8_t fu_uid[8];
|
u_int8_t fu_uid[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Needed to keep track of outstanding packets during a read op. Since the
|
||||||
|
* packet stream is asynch it's possible to parse a response packet before the
|
||||||
|
* ack bits are processed. In this case something needs to track whether the
|
||||||
|
* abuf is still valid before possibly attempting to use items from within it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct fwohci_cb {
|
||||||
|
struct ieee1394_abuf *ab;
|
||||||
|
int count;
|
||||||
|
int abuf_valid;
|
||||||
|
};
|
||||||
|
|
||||||
struct fwohci_softc {
|
struct fwohci_softc {
|
||||||
struct ieee1394_softc sc_sc1394;
|
struct ieee1394_softc sc_sc1394;
|
||||||
struct evcnt sc_intrcnt;
|
struct evcnt sc_intrcnt;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: ieee1394var.h,v 1.11 2001/05/15 06:30:30 jmc Exp $ */
|
/* $NetBSD: ieee1394var.h,v 1.12 2001/05/15 06:52:30 jmc Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||||
@ -57,7 +57,6 @@ struct ieee1394_abuf {
|
|||||||
u_int16_t ab_retlen; /* length returned from read. */
|
u_int16_t ab_retlen; /* length returned from read. */
|
||||||
u_int32_t ab_retries;
|
u_int32_t ab_retries;
|
||||||
void (*ab_cb)(struct ieee1394_abuf *, int);
|
void (*ab_cb)(struct ieee1394_abuf *, int);
|
||||||
void (*ab_ackcb)(struct ieee1394_abuf *, int);
|
|
||||||
void *ab_cbarg;
|
void *ab_cbarg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user