MFp4(simokawa_firewire):

Many internal structure changes for the FireWire driver.

- Compute CRC in CROM parsing.
- Add support for configuration ROM build.
- Simplify dummy buffer handling.
- busdma conversion
- Use swi_taskqueue_giant for -current.  Mark the interrupt routine as MPSAFE.
- AR buffer handling.
	Don't reallocate AR buffer but just recycle it.
	Don't malloc and copy per packet in fwohci_arcv().
	Pass packet to fw_rcv() using iovec.
	Application must prepare receiving buffer in advance.
- Change fw_bind API so that application should pre-allocate xfer structure.
- Add fw_xfer_unload() for recycling struct fw_xfer.
- Add post_busreset hook
- Remove unused 'sub' and 'act_type' in struct fw_xfer.
- Remove npacket from struct fw_bulkxfer.
- Don't call back handlers in fwochi_arcv() if the packet has
	not drained in AT queue
- Make firewire works on big endian platform.
- Use native endian for packet header and remove unnecessary ntohX/htonX.
- Remove FWXFERQ_PACKET mode.  We don't use it anymore.
- Remove unnecessary restriction of FWSTMAXCHUNK.
- Don't set root node for phy config packet if the root node is
	not cycle master capable but set myself for root node.
	We should be the root node after next bus reset.

	Spotted by: Yoshihiro Tabira <tabira@scd.mei.co.jp>
- Improve self id handling

Tested on: i386, sparc64 and i386 with forced bounce buffer
This commit is contained in:
Hidetoshi Shimokawa 2003-04-17 03:38:03 +00:00
parent f770d2d3dd
commit 77ee030b5f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=113584
25 changed files with 2753 additions and 2154 deletions

View File

@ -1,4 +1,5 @@
/*
* Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
@ -44,13 +45,13 @@
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/conf.h>
#include <sys/uio.h>
#include <sys/sysctl.h>
#include <machine/cpufunc.h> /* for rdtsc proto for clock.h below */
#include <machine/clock.h>
#include <sys/bus.h> /* used by smbus and newbus */
#include <machine/bus.h>
#include <dev/firewire/firewire.h>
#include <dev/firewire/firewirereg.h>
@ -71,8 +72,6 @@ MALLOC_DEFINE(M_FWXFER, "fw_xfer", "XFER/FireWire");
#define FW_MAXASYRTY 4
#define FW_MAXDEVRCNT 4
#define XFER_TIMEOUT 0
devclass_t firewire_devclass;
static int firewire_match __P((device_t));
@ -202,9 +201,9 @@ fw_asyreq(struct firewire_comm *fc, int sub, struct fw_xfer *xfer)
xferq = fc->ats;
len = info->hdr_len;
if (info->flag & FWTI_BLOCK_STR)
len += ntohs(fp->mode.stream.len);
len += fp->mode.stream.len;
else if (info->flag & FWTI_BLOCK_ASY)
len += ntohs(fp->mode.rresb.len);
len += fp->mode.rresb.len;
if( len > xfer->send.len ){
printf("len(%d) > send.len(%d) (tcode=%d)\n",
len, xfer->send.len, tcode);
@ -230,11 +229,9 @@ fw_asyreq(struct firewire_comm *fc, int sub, struct fw_xfer *xfer)
}
xfer->tl = tl;
xfer->tcode = tcode;
xfer->resp = 0;
xfer->fc = fc;
xfer->q = xferq;
xfer->act_type = FWACT_XFER;
xfer->retry_req = fw_asybusy;
fw_asystart(xfer);
@ -252,12 +249,7 @@ fw_asy_callback(struct fw_xfer *xfer){
* Postpone to later retry.
*/
void fw_asybusy(struct fw_xfer *xfer){
#if 1
printf("fw_asybusy\n");
#endif
#if XFER_TIMEOUT
untimeout(fw_xfer_timeout, (void *)xfer, xfer->ch);
#endif
/*
xfer->ch = timeout((timeout_t *)fw_asystart, (void *)xfer, 20000);
*/
@ -265,24 +257,7 @@ void fw_asybusy(struct fw_xfer *xfer){
fw_asystart(xfer);
return;
}
#if XFER_TIMEOUT
/*
* Post timeout for async. request.
*/
void
fw_xfer_timeout(void *arg)
{
int s;
struct fw_xfer *xfer;
xfer = (struct fw_xfer *)arg;
printf("fw_xfer_timeout status=%d resp=%d\n", xfer->state, xfer->resp);
/* XXX set error code */
s = splfw();
xfer->act.hand(xfer);
splx(s);
}
#endif
/*
* Async. request with given xfer structure.
*/
@ -292,6 +267,7 @@ fw_asystart(struct fw_xfer *xfer)
struct firewire_comm *fc = xfer->fc;
int s;
if(xfer->retry++ >= fc->max_asyretry){
device_printf(fc->bdev, "max_asyretry exceeded\n");
xfer->resp = EBUSY;
xfer->state = FWXF_BUSY;
xfer->act.hand(xfer);
@ -314,10 +290,6 @@ fw_asystart(struct fw_xfer *xfer)
/* XXX just queue for mbuf */
if (xfer->mbuf == NULL)
xfer->q->start(fc);
#if XFER_TIMEOUT
if (xfer->act.hand != NULL)
xfer->ch = timeout(fw_xfer_timeout, (void *)xfer, hz);
#endif
return;
}
@ -355,15 +327,7 @@ firewire_xfer_timeout(struct firewire_comm *fc)
xfer->dst, i);
xfer->resp = ETIMEDOUT;
STAILQ_REMOVE_HEAD(&fc->tlabels[i], link);
switch (xfer->act_type) {
case FWACT_XFER:
fw_xfer_done(xfer);
break;
default:
/* ??? */
fw_xfer_free(xfer);
break;
}
fw_xfer_done(xfer);
}
}
splx(s);
@ -437,10 +401,8 @@ firewire_attach( device_t dev )
/* launch attachement of the added children */
bus_generic_attach(dev);
#if 1
/* bus_reset */
fc->ibr(fc);
#endif
return 0;
}
@ -524,15 +486,7 @@ fw_xferq_drain(struct fw_xferq *xferq)
STAILQ_REMOVE_HEAD(&xferq->q, link);
xferq->queued --;
xfer->resp = EAGAIN;
switch (xfer->act_type) {
case FWACT_XFER:
fw_xfer_done(xfer);
break;
default:
/* ??? */
fw_xfer_free(xfer);
break;
}
fw_xfer_done(xfer);
}
}
@ -553,6 +507,9 @@ fw_drain_txq(struct firewire_comm *fc)
void
fw_busreset(struct firewire_comm *fc)
{
struct firewire_dev_comm *fdc;
device_t *devlistp;
int devcnt;
int i;
switch(fc->status){
@ -601,6 +558,16 @@ fw_busreset(struct firewire_comm *fc)
CSRARC(fc, STATE_CLEAR) &= ~(1 << 23 | 1 << 15 | 1 << 14 );
CSRARC(fc, STATE_SET) = CSRARC(fc, STATE_CLEAR);
if (device_get_children(fc->bdev, &devlistp, &devcnt) == 0) {
for( i = 0 ; i < devcnt ; i++)
if (device_get_state(devlistp[i]) >= DS_ATTACHED) {
fdc = device_get_softc(devlistp[i]);
if (fdc->post_busreset != NULL)
fdc->post_busreset(fdc);
}
free(devlistp, M_TEMP);
}
}
/* Call once after reboot */
@ -620,21 +587,15 @@ void fw_init(struct firewire_comm *fc)
fc->atq->queued = 0;
fc->ats->queued = 0;
fc->arq->psize = PAGE_SIZE;
fc->ars->psize = PAGE_SIZE;
fc->atq->psize = 0;
fc->ats->psize = 0;
fc->arq->buf = NULL;
fc->ars->buf = NULL;
fc->atq->buf = NULL;
fc->ats->buf = NULL;
fc->arq->flag = FWXFERQ_PACKET;
fc->ars->flag = FWXFERQ_PACKET;
fc->atq->flag = FWXFERQ_PACKET;
fc->ats->flag = FWXFERQ_PACKET;
fc->arq->flag = 0;
fc->ars->flag = 0;
fc->atq->flag = 0;
fc->ats->flag = 0;
STAILQ_INIT(&fc->atq->q);
STAILQ_INIT(&fc->ats->q);
@ -723,7 +684,6 @@ void fw_init(struct firewire_comm *fc)
fw_xfer_free(xfer);
}
xfer->act.hand = fw_vmaccess;
xfer->act_type = FWACT_XFER;
xfer->fc = fc;
xfer->sc = NULL;
@ -744,7 +704,7 @@ fw_bindlookup(struct firewire_comm *fc, u_int32_t dest_hi, u_int32_t dest_lo)
struct fw_bind *tfw;
for(tfw = STAILQ_FIRST(&fc->binds) ; tfw != NULL ;
tfw = STAILQ_NEXT(tfw, fclist)){
if(tfw->xfer->act_type != FWACT_NULL &&
if (tfw->act_type != FWACT_NULL &&
tfw->start_hi == dest_hi &&
tfw->start_lo <= dest_lo &&
(tfw->start_lo + tfw->addrlen) > dest_lo){
@ -796,9 +756,8 @@ fw_bindadd(struct firewire_comm *fc, struct fw_bind *fwb)
STAILQ_INSERT_TAIL(&fc->binds, fwb, fclist);
}
out:
if(!err && fwb->xfer->act_type == FWACT_CH){
STAILQ_INSERT_HEAD(&fc->ir[fwb->xfer->sub]->binds, fwb, chlist);
}
if (!err && fwb->act_type == FWACT_CH)
STAILQ_INSERT_HEAD(&fc->ir[fwb->sub]->binds, fwb, chlist);
return err;
}
@ -809,14 +768,19 @@ int
fw_bindremove(struct firewire_comm *fc, struct fw_bind *fwb)
{
int s;
struct fw_xfer *xfer, *next;
s = splfw();
/* shall we check the existance? */
STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist);
splx(s);
if (fwb->xfer)
fw_xfer_free(fwb->xfer);
/* shall we do this? */
for (xfer = STAILQ_FIRST(&fwb->xferlist); xfer != NULL; xfer = next) {
next = STAILQ_NEXT(xfer, link);
fw_xfer_free(xfer);
}
STAILQ_INIT(&fwb->xferlist);
splx(s);
return 0;
}
@ -881,12 +845,40 @@ fw_xfer_alloc(struct malloc_type *type)
return xfer;
microtime(&xfer->tv);
xfer->sub = -1;
xfer->malloc = type;
return xfer;
}
struct fw_xfer *
fw_xfer_alloc_buf(struct malloc_type *type, int send_len, int recv_len)
{
struct fw_xfer *xfer;
xfer = fw_xfer_alloc(type);
xfer->send.len = send_len;
xfer->recv.len = recv_len;
if (xfer == NULL)
return(NULL);
if (send_len) {
xfer->send.buf = malloc(send_len, type, M_NOWAIT | M_ZERO);
if (xfer->send.buf == NULL) {
fw_xfer_free(xfer);
return(NULL);
}
}
if (recv_len) {
xfer->recv.buf = malloc(recv_len, type, M_NOWAIT);
if (xfer->recv.buf == NULL) {
if (xfer->send.buf != NULL)
free(xfer->send.buf, type);
fw_xfer_free(xfer);
return(NULL);
}
}
return(xfer);
}
/*
* IEEE1394 XFER post process.
*/
@ -896,10 +888,6 @@ fw_xfer_done(struct fw_xfer *xfer)
if (xfer->act.hand == NULL)
return;
#if XFER_TIMEOUT
untimeout(fw_xfer_timeout, (void *)xfer, xfer->ch);
#endif
if (xfer->fc->status != FWBUSRESET)
xfer->act.hand(xfer);
else {
@ -911,13 +899,11 @@ fw_xfer_done(struct fw_xfer *xfer)
}
}
/*
* To free IEEE1394 XFER structure.
*/
void
fw_xfer_free( struct fw_xfer* xfer)
fw_xfer_unload(struct fw_xfer* xfer)
{
int s;
if(xfer == NULL ) return;
if(xfer->state == FWXF_INQ){
printf("fw_xfer_free FWXF_INQ\n");
@ -926,24 +912,30 @@ fw_xfer_free( struct fw_xfer* xfer)
xfer->q->queued --;
splx(s);
}
if(xfer->fc != NULL){
if(xfer->state == FWXF_START){
#if 0 /* this could happen if we call fwohci_arcv() before fwohci_txd() */
printf("fw_xfer_free FWXF_START\n");
if (xfer->fc != NULL) {
#if 1 /* this could happen if we call fwohci_arcv() before fwohci_txd() */
if(xfer->state == FWXF_START)
panic("fw_xfer_free FWXF_START\n");
#endif
s = splfw();
xfer->q->drain(xfer->fc, xfer);
splx(s);
}
fw_tl_free(xfer->fc, xfer);
}
xfer->state = FWXF_INIT;
xfer->resp = 0;
xfer->retry = 0;
}
/*
* To free IEEE1394 XFER structure.
*/
void
fw_xfer_free( struct fw_xfer* xfer)
{
if(xfer == NULL ) return;
fw_xfer_unload(xfer);
if(xfer->send.buf != NULL){
free(xfer->send.buf, M_FW);
free(xfer->send.buf, xfer->malloc);
}
if(xfer->recv.buf != NULL){
free(xfer->recv.buf, M_FW);
}
if(xfer->fc != NULL){
fw_tl_free(xfer->fc, xfer);
free(xfer->recv.buf, xfer->malloc);
}
free(xfer, xfer->malloc);
}
@ -969,24 +961,19 @@ fw_phy_config(struct firewire_comm *fc, int root_node, int gap_count)
fc->status = FWBUSPHYCONF;
#if 0
DELAY(100000);
#endif
xfer = fw_xfer_alloc(M_FWXFER);
xfer->send.len = 12;
xfer->send.off = 0;
xfer = fw_xfer_alloc_buf(M_FWXFER, 12, 0);
if (xfer == NULL)
return;
xfer->fc = fc;
xfer->retry_req = fw_asybusy;
xfer->act.hand = fw_asy_callback_free;
xfer->send.buf = malloc(sizeof(u_int32_t),
M_FW, M_NOWAIT | M_ZERO);
fp = (struct fw_pkt *)xfer->send.buf;
fp->mode.ld[1] = 0;
if (root_node >= 0)
fp->mode.ld[1] |= htonl((root_node & 0x3f) << 24 | 1 << 23);
fp->mode.ld[1] |= (root_node & 0x3f) << 24 | 1 << 23;
if (gap_count >= 0)
fp->mode.ld[1] |= htonl(1 << 22 | (gap_count & 0x3f) << 16);
fp->mode.ld[1] |= 1 << 22 | (gap_count & 0x3f) << 16;
fp->mode.ld[2] = ~fp->mode.ld[1];
/* XXX Dangerous, how to pass PHY packet to device driver */
fp->mode.common.tcode |= FWTCODE_PHY;
@ -1018,9 +1005,9 @@ fw_print_sid(u_int32_t sid)
/*
* To receive self ID.
*/
void fw_sidrcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int off)
void fw_sidrcv(struct firewire_comm* fc, u_int32_t *sid, u_int len)
{
u_int32_t *p, *sid = (u_int32_t *)(buf + off);
u_int32_t *p;
union fw_self_id *self_id;
u_int i, j, node, c_port = 0, i_branch = 0;
@ -1103,9 +1090,7 @@ void fw_sidrcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int off)
bcopy(p, &CSRARC(fc, SPED_MAP + 8), (fc->speed_map->crc_len - 1)*4);
fc->max_hop = fc->max_node - i_branch;
#if 1
printf(", maxhop <= %d", fc->max_hop);
#endif
if(fc->irm == -1 ){
printf(", Not found IRM capable node");
@ -1132,7 +1117,6 @@ void fw_sidrcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int off)
CSRARC(fc, BUS_MGR_ID));
#endif
}
free(buf, M_FW);
if(fc->irm == ((CSRARC(fc, NODE_IDS) >> 16 ) & 0x3f)){
/* I am BMGR */
fw_bmr(fc);
@ -1240,12 +1224,7 @@ fw_bus_explore(struct firewire_comm *fc )
fwdev->dst = fc->ongonode;
fwdev->eui.hi = fc->ongoeui.hi; fwdev->eui.lo = fc->ongoeui.lo;
fwdev->status = FWDEVINIT;
#if 0
fwdev->speed = CSRARC(fc, SPED_MAP + 8 + fc->ongonode / 4)
>> ((3 - (fc->ongonode % 4)) * 8);
#else
fwdev->speed = fc->speed_map->speed[fc->nodeid][fc->ongonode];
#endif
pfwdev = NULL;
STAILQ_FOREACH(tfwdev, &fc->devices, link) {
@ -1276,28 +1255,20 @@ fw_bus_explore(struct firewire_comm *fc )
fw_bus_explore_callback);
if(xfer == NULL) goto done;
#else
xfer = fw_xfer_alloc(M_FWXFER);
xfer = fw_xfer_alloc_buf(M_FWXFER, 16, 16);
if(xfer == NULL){
goto done;
}
xfer->send.len = 16;
xfer->spd = 0;
xfer->send.buf = malloc(16, M_FW, M_NOWAIT);
if(xfer->send.buf == NULL){
fw_xfer_free( xfer);
return;
}
xfer->send.off = 0;
fp = (struct fw_pkt *)xfer->send.buf;
fp->mode.rreqq.dest_hi = htons(0xffff);
fp->mode.rreqq.dest_hi = 0xffff;
fp->mode.rreqq.tlrt = 0;
fp->mode.rreqq.tcode = FWTCODE_RREQQ;
fp->mode.rreqq.pri = 0;
fp->mode.rreqq.src = 0;
xfer->dst = FWLOCALBUS | fc->ongonode;
fp->mode.rreqq.dst = htons(xfer->dst);
fp->mode.rreqq.dest_lo = htonl(addr);
fp->mode.rreqq.dst = xfer->dst;
fp->mode.rreqq.dest_lo = addr;
xfer->act.hand = fw_bus_explore_callback;
if (firewire_debug)
@ -1330,21 +1301,13 @@ asyreqq(struct firewire_comm *fc, u_int8_t spd, u_int8_t tl, u_int8_t rt,
struct fw_pkt *fp;
int err;
xfer = fw_xfer_alloc(M_FWXFER);
if(xfer == NULL){
xfer = fw_xfer_alloc_buf(M_FWXFER, 16, 16);
if (xfer == NULL)
return NULL;
}
xfer->send.len = 16;
xfer->spd = spd; /* XXX:min(spd, fc->spd) */
xfer->send.buf = malloc(16, M_FW, M_NOWAIT);
if(xfer->send.buf == NULL){
fw_xfer_free( xfer);
return NULL;
}
xfer->send.off = 0;
xfer->spd = spd; /* XXX:min(spd, fc->spd) */
fp = (struct fw_pkt *)xfer->send.buf;
fp->mode.rreqq.dest_hi = htons(addr_hi & 0xffff);
fp->mode.rreqq.dest_hi = addr_hi & 0xffff;
if(tl & FWP_TL_VALID){
fp->mode.rreqq.tlrt = (tl & 0x3f) << 2;
}else{
@ -1355,8 +1318,8 @@ asyreqq(struct firewire_comm *fc, u_int8_t spd, u_int8_t tl, u_int8_t rt,
fp->mode.rreqq.pri = 0;
fp->mode.rreqq.src = 0;
xfer->dst = addr_hi >> 16;
fp->mode.rreqq.dst = htons(xfer->dst);
fp->mode.rreqq.dest_lo = htonl(addr_lo);
fp->mode.rreqq.dst = xfer->dst;
fp->mode.rreqq.dest_lo = addr_lo;
xfer->act.hand = hand;
err = fw_asyreq(fc, -1, xfer);
@ -1420,14 +1383,14 @@ fw_bus_explore_callback(struct fw_xfer *xfer)
qld = (u_int32_t *)xfer->recv.buf;
printf("len:%d\n", xfer->recv.len);
for( i = 0 ; i <= xfer->recv.len && i < 32; i+= 4){
printf("0x%08x ", ntohl(rfp->mode.ld[i/4]));
printf("0x%08x ", rfp->mode.ld[i/4]);
if((i % 16) == 15) printf("\n");
}
if((i % 16) != 15) printf("\n");
}
#endif
if(fc->ongodev == NULL){
if(sfp->mode.rreqq.dest_lo == htonl((0xf0000000 | CSRROMOFF))){
if(sfp->mode.rreqq.dest_lo == (0xf0000000 | CSRROMOFF)){
rfp->mode.rresq.data = ntohl(rfp->mode.rresq.data);
chdr = (struct csrhdr *)(&rfp->mode.rresq.data);
/* If CSR is minimal confinguration, more investgation is not needed. */
@ -1439,10 +1402,10 @@ fw_bus_explore_callback(struct fw_xfer *xfer)
}else{
fc->ongoaddr = CSRROMOFF + 0xc;
}
}else if(sfp->mode.rreqq.dest_lo == htonl((0xf0000000 |(CSRROMOFF + 0xc)))){
}else if(sfp->mode.rreqq.dest_lo == (0xf0000000 |(CSRROMOFF + 0xc))){
fc->ongoeui.hi = ntohl(rfp->mode.rresq.data);
fc->ongoaddr = CSRROMOFF + 0x10;
}else if(sfp->mode.rreqq.dest_lo == htonl((0xf0000000 |(CSRROMOFF + 0x10)))){
}else if(sfp->mode.rreqq.dest_lo == (0xf0000000 |(CSRROMOFF + 0x10))){
fc->ongoeui.lo = ntohl(rfp->mode.rresq.data);
if (fc->ongoeui.hi == 0 && fc->ongoeui.lo == 0) {
if (firewire_debug)
@ -1701,17 +1664,42 @@ fw_get_tlabel(struct firewire_comm *fc, struct fw_xfer *xfer)
return(-1);
}
static void
fw_rcv_copy(struct fw_xfer *xfer, struct iovec *vec, int nvec)
{
char *p;
int res, i, len;
p = xfer->recv.buf;
res = xfer->recv.len;
for (i = 0; i < nvec; i++, vec++) {
len = vec->iov_len;
if (res < len) {
printf("rcv buffer(%d) is %d bytes short.\n",
xfer->recv.len, len - res);
len = res;
}
bcopy(vec->iov_base, p, len);
p += len;
res -= len;
if (res <= 0)
break;
}
xfer->recv.len -= res;
}
/*
* Generic packet receving process.
*/
void
fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u_int spd)
fw_rcv(struct firewire_comm *fc, struct iovec *vec, int nvec, u_int sub, u_int spd)
{
struct fw_pkt *fp, *resfp;
struct fw_xfer *xfer;
struct fw_bind *bind;
struct firewire_softc *sc;
int s;
int tcode, s;
int i, len, oldstate;
#if 0
{
u_int32_t *qld;
@ -1725,25 +1713,37 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u
if((i % 16) != 15) printf("\n");
}
#endif
fp = (struct fw_pkt *)(buf + off);
switch(fp->mode.common.tcode){
fp = (struct fw_pkt *)vec[0].iov_base;
tcode = fp->mode.common.tcode;
#if 0 /* XXX this check is not valid for RRESQ and WREQQ */
if (vec[0].iov_len < fc->tcode[tcode].hdr_len) {
#if __FreeBSD_version >= 500000
printf("fw_rcv: iov_len(%zu) is less than"
#else
printf("fw_rcv: iov_len(%u) is less than"
#endif
" hdr_len(%d:tcode=%d)\n", vec[0].iov_len,
fc->tcode[tcode].hdr_len, tcode);
}
#endif
switch (tcode) {
case FWTCODE_WRES:
case FWTCODE_RRESQ:
case FWTCODE_RRESB:
case FWTCODE_LRES:
xfer = fw_tl2xfer(fc, ntohs(fp->mode.hdr.src),
xfer = fw_tl2xfer(fc, fp->mode.hdr.src,
fp->mode.hdr.tlrt >> 2);
if(xfer == NULL) {
printf("fw_rcv: unknown response "
"tcode=%d src=0x%x tl=0x%x rt=%d data=0x%x\n",
fp->mode.common.tcode,
ntohs(fp->mode.hdr.src),
tcode,
fp->mode.hdr.src,
fp->mode.hdr.tlrt >> 2,
fp->mode.hdr.tlrt & 3,
fp->mode.rresq.data);
#if 1
printf("try ad-hoc work around!!\n");
xfer = fw_tl2xfer(fc, ntohs(fp->mode.hdr.src),
xfer = fw_tl2xfer(fc, fp->mode.hdr.src,
(fp->mode.hdr.tlrt >> 2)^3);
if (xfer == NULL) {
printf("no use...\n");
@ -1753,56 +1753,48 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u
goto err;
#endif
}
switch(xfer->act_type){
case FWACT_XFER:
if((xfer->sub >= 0) &&
((fc->ir[xfer->sub]->flag & FWXFERQ_MODEMASK ) == 0)){
xfer->resp = EINVAL;
fw_xfer_done(xfer);
goto err;
}
xfer->recv.len = len;
xfer->recv.off = off;
xfer->recv.buf = buf;
xfer->resp = 0;
fw_rcv_copy(xfer, vec, nvec);
xfer->resp = 0;
/* make sure the packet is drained in AT queue */
oldstate = xfer->state;
xfer->state = FWXF_RCVD;
switch (oldstate) {
case FWXF_SENT:
fw_xfer_done(xfer);
return;
break;
case FWACT_CH:
case FWXF_START:
if (firewire_debug)
printf("not sent yet\n");
break;
default:
goto err;
break;
printf("unexpected state %d\n", xfer->state);
}
break;
return;
case FWTCODE_WREQQ:
case FWTCODE_WREQB:
case FWTCODE_RREQQ:
case FWTCODE_RREQB:
case FWTCODE_LREQ:
bind = fw_bindlookup(fc, ntohs(fp->mode.rreqq.dest_hi),
ntohl(fp->mode.rreqq.dest_lo));
bind = fw_bindlookup(fc, fp->mode.rreqq.dest_hi,
fp->mode.rreqq.dest_lo);
if(bind == NULL){
#if __FreeBSD_version >= 500000
printf("Unknown service addr 0x%08x:0x%08x tcode=%x\n src=0x%x",
#else
printf("Unknown service addr 0x%08x:0x%08lx tcode=%x src=0x%x\n",
#endif
ntohs(fp->mode.rreqq.dest_hi),
ntohl(fp->mode.rreqq.dest_lo),
fp->mode.common.tcode,
fp->mode.hdr.src);
printf("Unknown service addr 0x%08x:0x%08x tcode=%x src=0x%x data=%x\n",
fp->mode.wreqq.dest_hi,
fp->mode.wreqq.dest_lo,
tcode,
fp->mode.hdr.src,
ntohl(fp->mode.wreqq.data));
if (fc->status == FWBUSRESET) {
printf("fw_rcv: cannot respond(bus reset)!\n");
goto err;
}
xfer = fw_xfer_alloc(M_FWXFER);
xfer = fw_xfer_alloc_buf(M_FWXFER, 16, 0);
if(xfer == NULL){
return;
}
xfer->spd = spd;
xfer->send.buf = malloc(16, M_FW, M_NOWAIT);
resfp = (struct fw_pkt *)xfer->send.buf;
switch(fp->mode.common.tcode){
switch (tcode) {
case FWTCODE_WREQQ:
case FWTCODE_WREQB:
resfp->mode.hdr.tcode = FWTCODE_WRES;
@ -1837,17 +1829,20 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u
}
goto err;
}
switch(bind->xfer->act_type){
len = 0;
for (i = 0; i < nvec; i ++)
len += vec[i].iov_len;
switch(bind->act_type){
case FWACT_XFER:
xfer = fw_xfer_alloc(M_FWXFER);
if(xfer == NULL) goto err;
xfer->fc = bind->xfer->fc;
xfer->sc = bind->xfer->sc;
xfer->recv.buf = buf;
xfer->recv.len = len;
xfer->recv.off = off;
/* splfw()?? */
xfer = STAILQ_FIRST(&bind->xferlist);
if (xfer == NULL) {
printf("Discard a packet for this bind.\n");
goto err;
}
STAILQ_REMOVE_HEAD(&bind->xferlist, link);
fw_rcv_copy(xfer, vec, nvec);
xfer->spd = spd;
xfer->act.hand = bind->xfer->act.hand;
if (fc->status != FWBUSRESET)
xfer->act.hand(xfer);
else
@ -1855,26 +1850,28 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u
return;
break;
case FWACT_CH:
if(fc->ir[bind->xfer->sub]->queued >=
fc->ir[bind->xfer->sub]->maxq){
if(fc->ir[bind->sub]->queued >=
fc->ir[bind->sub]->maxq){
device_printf(fc->bdev,
"Discard a packet %x %d\n",
bind->xfer->sub,
fc->ir[bind->xfer->sub]->queued);
bind->sub,
fc->ir[bind->sub]->queued);
goto err;
}
xfer = fw_xfer_alloc(M_FWXFER);
if(xfer == NULL) goto err;
xfer->recv.buf = buf;
xfer->recv.len = len;
xfer->recv.off = off;
xfer = STAILQ_FIRST(&bind->xferlist);
if (xfer == NULL) {
printf("Discard packet for this bind\n");
goto err;
}
STAILQ_REMOVE_HEAD(&bind->xferlist, link);
fw_rcv_copy(xfer, vec, nvec);
xfer->spd = spd;
s = splfw();
fc->ir[bind->xfer->sub]->queued++;
STAILQ_INSERT_TAIL(&fc->ir[bind->xfer->sub]->q, xfer, link);
fc->ir[bind->sub]->queued++;
STAILQ_INSERT_TAIL(&fc->ir[bind->sub]->q, xfer, link);
splx(s);
wakeup((caddr_t)fc->ir[bind->xfer->sub]);
wakeup((caddr_t)fc->ir[bind->sub]);
return;
break;
@ -1896,11 +1893,12 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u
printf("receive queue is full\n");
goto err;
}
xfer = fw_xfer_alloc(M_FWXFER);
/* XXX get xfer from xfer queue, we don't need copy for
per packet mode */
xfer = fw_xfer_alloc_buf(M_FWXFER, 0, /* XXX */
vec[0].iov_len);
if(xfer == NULL) goto err;
xfer->recv.buf = buf;
xfer->recv.len = len;
xfer->recv.off = off;
fw_rcv_copy(xfer, vec, nvec);
xfer->spd = spd;
s = splfw();
xferq->queued++;
@ -1924,11 +1922,11 @@ fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u
break;
}
default:
printf("fw_rcv: unknow tcode\n");
printf("fw_rcv: unknow tcode %d\n", tcode);
break;
}
err:
free(buf, M_FW);
return;
}
/*
@ -1971,6 +1969,7 @@ fw_try_bmr_callback(struct fw_xfer *xfer)
fw_xfer_free(xfer);
}
/*
* To candidate Bus Manager election process.
*/
@ -1982,35 +1981,26 @@ fw_try_bmr(void *arg)
struct fw_pkt *fp;
int err = 0;
xfer = fw_xfer_alloc(M_FWXFER);
xfer = fw_xfer_alloc_buf(M_FWXFER, 24, 20);
if(xfer == NULL){
return;
}
xfer->send.len = 24;
xfer->spd = 0;
xfer->send.buf = malloc(24, M_FW, M_NOWAIT);
if(xfer->send.buf == NULL){
fw_xfer_free( xfer);
return;
}
fc->status = FWBUSMGRELECT;
xfer->send.off = 0;
fp = (struct fw_pkt *)xfer->send.buf;
fp->mode.lreq.dest_hi = htons(0xffff);
fp->mode.lreq.dest_hi = 0xffff;
fp->mode.lreq.tlrt = 0;
fp->mode.lreq.tcode = FWTCODE_LREQ;
fp->mode.lreq.pri = 0;
fp->mode.lreq.src = 0;
fp->mode.lreq.len = htons(8);
fp->mode.lreq.extcode = htons(FW_LREQ_CMPSWAP);
fp->mode.lreq.len = 8;
fp->mode.lreq.extcode = FW_LREQ_CMPSWAP;
xfer->dst = FWLOCALBUS | fc->irm;
fp->mode.lreq.dst = htons(xfer->dst);
fp->mode.lreq.dest_lo = htonl(0xf0000000 | BUS_MGR_ID);
fp->mode.lreq.dst = xfer->dst;
fp->mode.lreq.dest_lo = 0xf0000000 | BUS_MGR_ID;
fp->mode.lreq.payload[0] = htonl(0x3f);
fp->mode.lreq.payload[1] = htonl(fc->nodeid);
xfer->act_type = FWACT_XFER;
xfer->act.hand = fw_try_bmr_callback;
err = fw_asyreq(fc, -1, xfer);
@ -2029,10 +2019,10 @@ fw_try_bmr(void *arg)
static void
fw_vmaccess(struct fw_xfer *xfer){
struct fw_pkt *rfp, *sfp = NULL;
u_int32_t *ld = (u_int32_t *)(xfer->recv.buf + xfer->recv.off);
u_int32_t *ld = (u_int32_t *)xfer->recv.buf;
printf("vmaccess spd:%2x len:%03x %d data:%08x %08x %08x %08x\n",
xfer->spd, xfer->recv.len, xfer->recv.off, ntohl(ld[0]), ntohl(ld[1]), ntohl(ld[2]), ntohl(ld[3]));
printf("vmaccess spd:%2x len:%03x data:%08x %08x %08x %08x\n",
xfer->spd, xfer->recv.len, ntohl(ld[0]), ntohl(ld[1]), ntohl(ld[2]), ntohl(ld[3]));
printf("vmaccess data:%08x %08x %08x %08x\n", ntohl(ld[4]), ntohl(ld[5]), ntohl(ld[6]), ntohl(ld[7]));
if(xfer->resp != 0){
fw_xfer_free( xfer);
@ -2084,7 +2074,6 @@ fw_vmaccess(struct fw_xfer *xfer){
fw_xfer_free( xfer);
return;
}
xfer->send.off = 0;
sfp->mode.hdr.dst = rfp->mode.hdr.src;
xfer->dst = ntohs(rfp->mode.hdr.src);
xfer->act.hand = fw_xfer_free;
@ -2121,17 +2110,25 @@ static int
fw_bmr(struct firewire_comm *fc)
{
struct fw_device fwdev;
union fw_self_id *self_id;
int cmstr;
/* XXX Assume that the current root node is cycle master capable */
cmstr = fc->max_node;
/* Check to see if the current root node is cycle master capable */
self_id = &fc->topology_map->self_id[fc->max_node];
if (fc->max_node > 0) {
if (self_id->p0.contender)
cmstr = fc->max_node;
else
/* XXX shall we be cycle master? */
cmstr = fc->nodeid;
/* XXX bus reset? */
} else
cmstr = -1;
/* If I am the bus manager, optimize gapcount */
if(fc->max_hop <= MAX_GAPHOP ){
fw_phy_config(fc, (fc->max_node > 0)?cmstr:-1,
gap_cnt[fc->max_hop]);
}
if(fc->max_hop <= MAX_GAPHOP )
fw_phy_config(fc, cmstr, gap_cnt[fc->max_hop]);
/* If we are the cycle master, nothing to do */
if (cmstr == fc->nodeid)
if (cmstr == fc->nodeid || cmstr == -1)
return 0;
/* Bus probe has not finished, make dummy fwdev for cmstr */
bzero(&fwdev, sizeof(fwdev));

View File

@ -1,4 +1,5 @@
/*
* Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
@ -40,29 +41,6 @@
#define DEV_DEF 0
#define DEV_DV 2
#if 0
struct dv_data{
u_int32_t n_write;
u_int32_t a_write;
u_int32_t k_write;
u_int32_t write_done;
u_int32_t write_len[16];
u_int32_t write_off[16];
u_int32_t n_read;
u_int32_t a_read;
u_int32_t k_read;
u_int32_t read_done;
u_int32_t read_len[16];
u_int32_t read_off[16];
};
struct dv_data_req_t {
unsigned long index;
unsigned long len;
unsigned long off;
};
#endif
struct fw_isochreq {
unsigned char ch:6,
tag:2;
@ -93,7 +71,7 @@ struct fw_reg_req_t {
#define MAXREC(x) (2 << (x))
#define FWPMAX_S400 (2048 + 20) /* MAXREC plus space for control data */
#define FWMAXQUEUE 256
#define FWMAXQUEUE 64
#define FWLOCALBUS 0xffc0
@ -135,139 +113,83 @@ struct fw_asyhdr {
u_int32_t hdr[4];
};
#if 0
#define FWPHYSIDSUBS(SID) (((SID) >> 23) & 1)
#define FWPHYSIDNODE(SID) (((SID) >> 24) & 0x3f)
#define FWPHYSIDLINK(SID) (((SID) >> 22) & 1)
#define FWPHYSIDGAP(SID) (((SID) >> 16) & 0x3f)
#define FWPHYSIDSPD(SID) (((SID) >> 14) & 0x3)
#define FWPHYSIDDEL(SID) (((SID) >> 12) & 0x3)
#define FWPHYSIDCON(SID) (((SID) >> 11) & 1)
#define FWPHYSIDPWR(SID) (((SID) >> 8) & 0x7)
#define FWPHYSIDP0(SID) (((SID) >> 6) & 0x3)
#define FWPHYSIDP1(SID) (((SID) >> 4) & 0x3)
#define FWPHYSIDP2(SID) (((SID) >> 2) & 0x3)
#define FWPHYSIDIR(SID) (((SID) >> 1) & 1)
#define FWPHYSIDMORE(SID) ((SID) & 1)
#define FWPHYSIDSEQ(SID) (((SID) >> 20) & 0x7)
#define FWPHYSIDPA(SID) (((SID) >> 16) & 0x3)
#define FWPHYSIDPB(SID) (((SID) >> 14) & 0x3)
#define FWPHYSIDPC(SID) (((SID) >> 12) & 0x3)
#define FWPHYSIDPD(SID) (((SID) >> 10) & 0x3)
#define FWPHYSIDPE(SID) (((SID) >> 8) & 0x3)
#define FWPHYSIDPF(SID) (((SID) >> 6) & 0x3)
#define FWPHYSIDPG(SID) (((SID) >> 4) & 0x3)
#define FWPHYSIDPH(SID) (((SID) >> 2) & 0x3)
#if BYTE_ORDER == BIG_ENDIAN
#define BIT4x2(x,y) u_int8_t x:4, y:4
#define BIT16x2(x,y) u_int32_t x:16, y:16
#else
#define BIT4x2(x,y) u_int8_t y:4, x:4
#define BIT16x2(x,y) u_int32_t y:16, x:16
#endif
#if BYTE_ORDER == BIG_ENDIAN
#define COMMON_HDR(a,b,c,d) u_int32_t a:16,b:8,c:4,d:4
#define COMMON_RES(a,b,c,d) u_int32_t a:16,b:4,c:4,d:8
#else
#define COMMON_HDR(a,b,c,d) u_int32_t d:4,c:4,b:8,a:16
#define COMMON_RES(a,b,c,d) u_int32_t d:8,c:4,b:4,a:16
#endif
struct fw_pkt {
union {
u_int32_t ld[0];
struct {
u_int16_t :16;
u_int8_t :8;
u_int8_t :4,
tcode:4;
COMMON_HDR(, , tcode, );
} common;
struct {
u_int16_t len;
u_int8_t chtag;
u_int8_t sy:4,
tcode:4;
COMMON_HDR(len, chtag, tcode, sy);
u_int32_t payload[0];
} stream;
struct {
u_int16_t dst;
u_int8_t tlrt;
u_int8_t pri:4,
tcode:4;
u_int16_t src;
COMMON_HDR(dst, tlrt, tcode, pri);
BIT16x2(src, );
} hdr;
struct {
u_int16_t dst;
u_int8_t tlrt;
u_int8_t pri:4,
tcode:4;
u_int16_t src;
u_int16_t dest_hi;
COMMON_HDR(dst, tlrt, tcode, pri);
BIT16x2(src, dest_hi);
u_int32_t dest_lo;
} rreqq;
struct {
u_int16_t dst;
u_int8_t tlrt;
u_int8_t pri:4,
tcode:4;
u_int16_t src;
u_int8_t :4,
rtcode:4;
u_int8_t :8;
COMMON_HDR(dst, tlrt, tcode, pri);
COMMON_RES(src, rtcode, , );
u_int32_t :32;
} wres;
struct {
u_int16_t dst;
u_int8_t tlrt;
u_int8_t pri:4,
tcode:4;
u_int16_t src;
u_int16_t dest_hi;
COMMON_HDR(dst, tlrt, tcode, pri);
BIT16x2(src, dest_hi);
u_int32_t dest_lo;
u_int16_t len;
u_int16_t extcode:16;
BIT16x2(len, extcode);
} rreqb;
struct {
u_int16_t dst;
u_int8_t tlrt;
u_int8_t pri:4,
tcode:4;
u_int16_t src;
u_int16_t dest_hi;
COMMON_HDR(dst, tlrt, tcode, pri);
BIT16x2(src, dest_hi);
u_int32_t dest_lo;
u_int32_t data;
} wreqq;
struct {
u_int16_t dst;
u_int8_t tlrt;
u_int8_t pri:4,
tcode:4;
u_int16_t src;
u_int16_t dest_hi;
COMMON_HDR(dst, tlrt, tcode, pri);
BIT16x2(src, dest_hi);
u_int32_t dest_lo;
u_int32_t data;
} cyc;
struct {
u_int16_t dst;
u_int8_t tlrt;
u_int8_t pri:4,
tcode:4;
u_int16_t src;
u_int8_t :4,
rtcode:4;
u_int8_t :8;
COMMON_HDR(dst, tlrt, tcode, pri);
COMMON_RES(src, rtcode, , );
u_int32_t :32;
u_int32_t data;
} rresq;
struct {
u_int16_t dst;
u_int8_t tlrt;
u_int8_t pri:4,
tcode:4;
u_int16_t src;
u_int16_t dest_hi;
COMMON_HDR(dst, tlrt, tcode, pri);
BIT16x2(src, dest_hi);
u_int32_t dest_lo;
u_int16_t len;
u_int16_t extcode;
BIT16x2(len, extcode);
u_int32_t payload[0];
} wreqb;
struct {
u_int16_t dst;
u_int8_t tlrt;
u_int8_t pri:4,
tcode:4;
u_int16_t src;
u_int16_t dest_hi;
COMMON_HDR(dst, tlrt, tcode, pri);
BIT16x2(src, dest_hi);
u_int32_t dest_lo;
u_int16_t len;
u_int16_t extcode;
BIT16x2(len, extcode);
#define FW_LREQ_MSKSWAP 1
#define FW_LREQ_CMPSWAP 2
#define FW_LREQ_FTADD 3
@ -277,31 +199,17 @@ struct fw_pkt {
u_int32_t payload[0];
} lreq;
struct {
u_int16_t dst;
u_int8_t tlrt;
u_int8_t pri:4,
tcode:4;
u_int16_t src;
u_int8_t :4,
rtcode:4;
u_int8_t :8;
COMMON_HDR(dst, tlrt, tcode, pri);
COMMON_RES(src, rtcode, , );
u_int32_t :32;
u_int16_t len;
u_int16_t extcode;
BIT16x2(len, extcode);
u_int32_t payload[0];
} rresb;
struct {
u_int16_t dst;
u_int8_t tlrt;
u_int8_t pri:4,
tcode:4;
u_int16_t src;
u_int8_t :4,
rtcode:4;
u_int8_t :8;
COMMON_HDR(dst, tlrt, tcode, pri);
COMMON_RES(src, rtcode, , );
u_int32_t :32;
u_int16_t len;
u_int16_t extcode;
BIT16x2(len, extcode);
u_int32_t payload[0];
} lres;
} mode;
@ -352,7 +260,44 @@ struct fw_devlstreq {
#define FW_SELF_ID_PORT_CONNECTED_TO_PARENT 2
#define FW_SELF_ID_PORT_NOT_CONNECTED 1
#define FW_SELF_ID_PORT_NOT_EXISTS 0
#if 0
#if BYTE_ORDER == BIG_ENDIAN
union fw_self_id {
struct {
u_int32_t id:2,
phy_id:6,
sequel:1,
link_active:1,
gap_count:6,
phy_speed:2,
phy_delay:2,
contender:1,
power_class:3,
port0:2,
port1:2,
port2:2,
initiated_reset:1,
more_packets:1;
} p0;
struct {
u_int32_t
id:2,
phy_id:6,
sequel:1,
sequence_num:3,
:2,
porta:2,
portb:2,
portc:2,
portd:2,
porte:2,
portf:2,
portg:2,
porth:2,
:1,
more_packets:1;
} p1;
};
#else
union fw_self_id {
struct {
u_int32_t more_packets:1,
@ -388,42 +333,6 @@ union fw_self_id {
id:2;
} p1;
};
#else
union fw_self_id {
struct {
u_int8_t more_packets:1,
initiated_reset:1,
port2:2,
port1:2,
port0:2;
u_int8_t power_class:3,
contender:1,
phy_delay:2,
phy_speed:2;
u_int8_t gap_count:6,
link_active:1,
sequel:1;
u_int8_t phy_id:6,
id:2;
} p0;
struct {
u_int8_t more_packets:1,
reserved1:1,
porth:2,
portg:2,
portf:2;
u_int8_t porte:2,
portd:2,
portc:2,
portb:2;
u_int8_t porta:2,
reserved2:2,
sequence_num:3,
sequel:1;
u_int8_t phy_id:6,
id:2;
} p1;
};
#endif
@ -449,13 +358,9 @@ struct fw_crom_buf {
void *ptr;
};
#define FWSTMAXCHUNK 16
/*
* FireWire specific system requests.
*/
#if 0
#define FW_SSTDV _IOWR('S', 85, unsigned int)
#endif
#define FW_SSTBUF _IOWR('S', 86, struct fw_isobufreq)
#define FW_GSTBUF _IOWR('S', 87, struct fw_isobufreq)
#define FW_SRSTREAM _IOWR('S', 88, struct fw_isochreq)

View File

@ -83,5 +83,3 @@
#define FW_PHY_EDEL_REG 0x03
#define FW_PHY_EDEL 15<<0

View File

@ -1,4 +1,5 @@
/*
* Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
@ -42,15 +43,13 @@ typedef struct proc fw_proc;
#include <sys/select.h>
#endif
#include <sys/uio.h>
#define splfw splimp
struct fw_device{
u_int16_t dst;
struct fw_eui64 eui;
#if 0
u_int32_t spec;
u_int32_t ver;
#endif
u_int8_t speed;
u_int8_t maxrec;
u_int8_t nport;
@ -66,10 +65,6 @@ struct fw_device{
#define FWDEVATTACHED 2
#define FWDEVINVAL 3
STAILQ_ENTRY(fw_device) link;
#if 0
LIST_HEAD(, fw_xfer) txqueue;
LIST_HEAD(, fw_xfer) rxqueue;
#endif
};
struct firewire_softc {
@ -88,6 +83,7 @@ struct firewire_softc {
struct firewire_dev_comm {
device_t dev;
struct firewire_comm *fc;
void (*post_busreset) __P((void *));
void (*post_explore) __P((void *));
};
@ -136,14 +132,12 @@ struct firewire_comm{
#define FWBUSCOMPLETION 10
int nisodma;
struct fw_eui64 eui;
STAILQ_HEAD(fw_queue, fw_xfer);
struct fw_xferq
*arq, *atq, *ars, *ats, *it[FW_MAX_DMACH],*ir[FW_MAX_DMACH];
STAILQ_HEAD(, tlabel) tlabels[0x40];
STAILQ_HEAD(, fw_bind) binds;
STAILQ_HEAD(, fw_device) devices;
STAILQ_HEAD(, fw_xfer) pending;
volatile u_int32_t *sid_buf;
u_int sid_cnt;
#define CSRSIZE 0x4000
u_int32_t csr_arc[CSRSIZE/4];
@ -169,6 +163,7 @@ struct firewire_comm{
void (*irx_post) __P((struct firewire_comm *, u_int32_t *));
void (*itx_post) __P((struct firewire_comm *, u_int32_t *));
struct tcode_info *tcode;
bus_dma_tag_t dmat;
};
#define CSRARC(sc, offset) ((sc)->csr_arc[(offset)/4])
@ -184,11 +179,7 @@ struct fw_xferq {
#define FWXFERQ_RUNNING (1 << 8)
#define FWXFERQ_STREAM (1 << 9)
#define FWXFERQ_PACKET (1 << 10)
#define FWXFERQ_BULK (1 << 11)
#if 0 /* BROKEN */
#define FWXFERQ_DV (1 << 12)
#endif
#define FWXFERQ_MODEMASK (7 << 10)
#define FWXFERQ_EXTBUF (1 << 13)
@ -198,14 +189,12 @@ struct fw_xferq {
#define FWXFERQ_WAKEUP (1 << 17)
void (*start) __P((struct firewire_comm*));
void (*drain) __P((struct firewire_comm*, struct fw_xfer*));
struct fw_queue q;
STAILQ_HEAD(, fw_xfer) q;
u_int queued;
u_int maxq;
u_int psize;
u_int packets;
STAILQ_HEAD(, fw_bind) binds;
caddr_t buf;
struct fwdma_alloc_multi *buf;
u_int bnchunk;
u_int bnpacket;
struct fw_bulkxfer *bulkxfer;
@ -213,36 +202,20 @@ struct fw_xferq {
STAILQ_HEAD(, fw_bulkxfer) stfree;
STAILQ_HEAD(, fw_bulkxfer) stdma;
struct fw_bulkxfer *stproc;
#ifdef FWXFERQ_DV
int dvdbc, dvdiff, dvsync, dvoffset;
struct fw_dvbuf *dvbuf;
STAILQ_HEAD(, fw_dvbuf) dvvalid;
STAILQ_HEAD(, fw_dvbuf) dvfree;
struct fw_dvbuf *dvdma;
struct fw_dvbuf *dvproc;
u_int dvptr;
u_int dvpacket;
#endif
struct selinfo rsel;
caddr_t sc;
void (*hand) __P((struct fw_xferq *));
};
struct fw_bulkxfer{
caddr_t buf;
int poffset;
struct mbuf *mbuf;
STAILQ_ENTRY(fw_bulkxfer) link;
caddr_t start;
caddr_t end;
u_int npacket;
int resp;
};
struct fw_dvbuf{
caddr_t buf;
STAILQ_ENTRY(fw_dvbuf) link;
};
struct tlabel{
struct fw_xfer *xfer;
STAILQ_ENTRY(tlabel) link;
@ -250,23 +223,25 @@ struct tlabel{
struct fw_bind{
u_int32_t start_hi, start_lo, addrlen;
struct fw_xfer* xfer;
STAILQ_HEAD(, fw_xfer) xferlist;
STAILQ_ENTRY(fw_bind) fclist;
STAILQ_ENTRY(fw_bind) chlist;
#define FWACT_NULL 0
#define FWACT_XFER 2
#define FWACT_CH 3
u_int8_t act_type;
u_int8_t sub;
};
struct fw_xfer{
caddr_t sc;
struct firewire_comm *fc;
struct fw_xferq *q;
#ifdef XFER_TIMEOUT
struct callout_handle ch;
#endif
struct timeval tv;
struct fw_tlabel *tlabel;
/* XXX should be removed */
u_int32_t dst; /* XXX for if_fwe */
u_int8_t spd;
u_int8_t tcode;
int resp;
int8_t resp;
#define FWXF_INIT 0
#define FWXF_INQ 1
#define FWXF_START 2
@ -274,48 +249,30 @@ struct fw_xfer{
#define FWXF_SENTERR 4
#define FWXF_BUSY 8
#define FWXF_RCVD 10
int state;
u_int8_t state;
u_int8_t retry;
u_int8_t tl;
int sub;
int32_t dst;
u_int8_t act_type;
#define FWACT_NULL 0
#define FWACT_XFER 2
#define FWACT_CH 3
void (*retry_req) __P((struct fw_xfer *));
union{
void (*hand) __P((struct fw_xfer *));
} act;
#if 0
union{
struct {
struct fw_device *device;
} req;
struct {
struct stch *channel;
} stream;
} mode;
#endif
struct {
u_int16_t len, off;
int len;
caddr_t buf;
} send, recv;
struct mbuf *mbuf;
STAILQ_ENTRY(fw_xfer) link;
struct malloc_type *malloc;
};
void fw_sidrcv __P((struct firewire_comm *, caddr_t, u_int, u_int));
void fw_rcv __P((struct firewire_comm *, caddr_t, u_int, u_int, u_int, u_int));
void fw_sidrcv __P((struct firewire_comm *, u_int32_t *, u_int));
void fw_rcv __P((struct firewire_comm *, struct iovec *, int, u_int, u_int));
void fw_xfer_unload __P(( struct fw_xfer*));
void fw_xfer_free __P(( struct fw_xfer*));
struct fw_xfer *fw_xfer_alloc __P((struct malloc_type *));
struct fw_xfer *fw_xfer_alloc_buf __P((struct malloc_type *, int, int));
void fw_init __P((struct firewire_comm *));
int fw_tbuf_update __P((struct firewire_comm *, int, int));
int fw_rbuf_update __P((struct firewire_comm *, int, int));
int fw_readreqq __P((struct firewire_comm *, u_int32_t, u_int32_t, u_int32_t *));
int fw_writereqb __P((struct firewire_comm *, u_int32_t, u_int32_t, u_int32_t, u_int32_t *));
int fw_readresb __P((struct firewire_comm *, u_int32_t, u_int32_t, u_int32_t, u_int32_t*));
int fw_writeres __P((struct firewire_comm *, u_int32_t, u_int32_t));
u_int32_t getcsrdata __P((struct fw_device *, u_int8_t));
void fw_asybusy __P((struct fw_xfer *));
int fw_bindadd __P((struct firewire_comm *, struct fw_bind *));
@ -365,11 +322,6 @@ extern devclass_t firewire_devclass;
#define FWPRI ((PZERO+8)|PCATCH)
#ifdef __alpha__
#undef vtophys
#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va))
#endif /* __alpha__ */
#if __FreeBSD_version >= 500000
#define CALLOUT_INIT(x) callout_init(x, 0 /* mpsafe */)
#else

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2002
* Copyright (c) 2002-2003
* Hidetoshi Shimokawa. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -35,8 +35,9 @@
*/
#include <sys/param.h>
#include <dev/firewire/firewire.h>
#include <dev/firewire/iec13213.h>
#if defined(_KERNEL) || defined(TEST)
#include <sys/queue.h>
#endif
#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/kernel.h>
@ -48,6 +49,8 @@
#include <stdlib.h>
#include <string.h>
#endif
#include <dev/firewire/firewire.h>
#include <dev/firewire/iec13213.h>
void
crom_init_context(struct crom_context *cc, u_int32_t *p)
@ -179,20 +182,28 @@ crom_desc(struct crom_context *cc, char *buf, int len)
struct csrreg *reg;
struct csrdirectory *dir;
char *desc;
u_int16_t crc;
reg = crom_get(cc);
switch (reg->key & CSRTYPE_MASK) {
case CSRTYPE_I:
snprintf(buf, len, "%d", reg->val);
break;
case CSRTYPE_L:
case CSRTYPE_C:
snprintf(buf, len, "offset=0x%04x(%d)", reg->val, reg->val);
break;
case CSRTYPE_L:
/* XXX fall through */
case CSRTYPE_D:
dir = (struct csrdirectory *) (reg + reg->val);
snprintf(buf, len, "len=0x%04x(%d) crc=0x%04x",
dir->crc_len, dir->crc_len, dir->crc);
crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len);
len -= snprintf(buf, len, "len=%d crc=0x%04x",
dir->crc_len, dir->crc);
if (crc == dir->crc)
strncat(buf, "(OK) ", len);
else
strncat(buf, "(NG) ", len);
len -= 5;
}
switch (reg->key) {
case 0x03:
@ -239,7 +250,7 @@ crom_desc(struct crom_context *cc, char *buf, int len)
break;
case 0x81:
desc = "text_leaf";
crom_parse_text(cc, buf, len);
crom_parse_text(cc, buf + strlen(buf), len);
break;
case 0xd1:
desc = "unit_directory";
@ -253,3 +264,243 @@ crom_desc(struct crom_context *cc, char *buf, int len)
return desc;
}
#endif
#if defined(_KERNEL) || defined(TEST)
int
crom_add_quad(struct crom_chunk *chunk, u_int32_t entry)
{
int index;
index = chunk->data.crc_len;
if (index >= CROM_MAX_CHUNK_LEN - 1) {
printf("too large chunk %d\n", index);
return(-1);
}
chunk->data.buf[index] = entry;
chunk->data.crc_len++;
return(index);
}
int
crom_add_entry(struct crom_chunk *chunk, int key, int val)
{
struct csrreg *reg;
u_int32_t i;
reg = (struct csrreg *)&i;
reg->key = key;
reg->val = val;
return(crom_add_quad(chunk, (u_int32_t) i));
}
int
crom_add_chunk(struct crom_src *src, struct crom_chunk *parent,
struct crom_chunk *child, int key)
{
int index;
if (parent == NULL) {
STAILQ_INSERT_TAIL(&src->chunk_list, child, link);
return(0);
}
index = crom_add_entry(parent, key, 0);
if (index < 0) {
return(-1);
}
child->ref_chunk = parent;
child->ref_index = index;
STAILQ_INSERT_TAIL(&src->chunk_list, child, link);
return(index);
}
int
crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent,
struct crom_chunk *chunk, char *buf)
{
struct csrtext *tl;
u_int32_t *p;
int len, i;
len = strlen(buf);
#define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext))
if (len > MAX_TEXT) {
#if __FreeBSD_version < 500000
printf("text(%d) trancated to %d.\n", len, MAX_TEXT);
#else
printf("text(%d) trancated to %td.\n", len, MAX_TEXT);
#endif
len = MAX_TEXT;
}
tl = (struct csrtext *) &chunk->data;
tl->crc_len = howmany(sizeof(struct csrtext) + len, sizeof(u_int32_t));
tl->spec_id = 0;
tl->spec_type = 0;
tl->lang_id = 0;
p = (u_int32_t *) buf;
for (i = 0; i < howmany(len, sizeof(u_int32_t)) / 4; i ++)
tl->text[i] = ntohl(*p++);
return (crom_add_chunk(src, parent, chunk, CROM_TEXTLEAF));
}
static int
crom_copy(u_int32_t *src, u_int32_t *dst, int *offset, int len, int maxlen)
{
if (*offset + len > maxlen) {
printf("Config. ROM is too large for the buffer\n");
return(-1);
}
bcopy(src, (char *)(dst + *offset), len * sizeof(u_int32_t));
*offset += len;
return(0);
}
int
crom_load(struct crom_src *src, u_int32_t *buf, int maxlen)
{
struct crom_chunk *chunk, *parent;
struct csrhdr *hdr;
#if 0
u_int32_t *ptr;
#endif
int count, offset;
int len;
offset = 0;
/* Determine offset */
STAILQ_FOREACH(chunk, &src->chunk_list, link) {
chunk->offset = offset;
/* Assume the offset of the parent is already known */
parent = chunk->ref_chunk;
if (parent != NULL) {
struct csrreg *reg;
reg = (struct csrreg *)
&parent->data.buf[chunk->ref_index];
reg->val = offset -
(parent->offset + 1 + chunk->ref_index);
}
offset += 1 + chunk->data.crc_len;
}
/* Calculate CRC and dump to the buffer */
len = 1 + src->hdr.info_len;
count = 0;
if (crom_copy((u_int32_t *)&src->hdr, buf, &count, len, maxlen) < 0)
return(-1);
STAILQ_FOREACH(chunk, &src->chunk_list, link) {
chunk->data.crc =
crom_crc(&chunk->data.buf[0], chunk->data.crc_len);
len = 1 + chunk->data.crc_len;
if (crom_copy((u_int32_t *)&chunk->data, buf,
&count, len, maxlen) < 0)
return(-1);
}
hdr = (struct csrhdr *)buf;
hdr->crc_len = count - 1;
hdr->crc = crom_crc(buf + 1, hdr->crc_len);
#if 0
/* byte swap */
ptr = buf;
for (i = 0; i < count; i ++) {
*ptr = htonl(*ptr);
ptr++;
}
#endif
return(count);
}
#endif
#ifdef TEST
int
main () {
struct crom_src src;
struct crom_chunk root,unit1,unit2,unit3;
struct crom_chunk text1,text2,text3,text4,text5,text6,text7;
u_int32_t buf[256], *p;
int i;
bzero(&src, sizeof(src));
bzero(&root, sizeof(root));
bzero(&unit1, sizeof(unit1));
bzero(&unit2, sizeof(unit2));
bzero(&unit3, sizeof(unit3));
bzero(&text1, sizeof(text1));
bzero(&text2, sizeof(text2));
bzero(&text3, sizeof(text3));
bzero(&text3, sizeof(text4));
bzero(&text3, sizeof(text5));
bzero(&text3, sizeof(text6));
bzero(&text3, sizeof(text7));
bzero(buf, sizeof(buf));
/* BUS info sample */
src.hdr.info_len = 4;
src.businfo.bus_name = CSR_BUS_NAME_IEEE1394;
src.businfo.eui64.hi = 0x11223344;
src.businfo.eui64.lo = 0x55667788;
src.businfo.link_spd = FWSPD_S400;
src.businfo.generation = 0;
src.businfo.max_rom = MAXROM_4;
src.businfo.max_rec = 10;
src.businfo.cyc_clk_acc = 100;
src.businfo.pmc = 0;
src.businfo.bmc = 1;
src.businfo.isc = 1;
src.businfo.cmc = 1;
src.businfo.irmc = 1;
STAILQ_INIT(&src.chunk_list);
/* Root directory */
crom_add_chunk(&src, NULL, &root, 0);
crom_add_entry(&root, CSRKEY_NCAP, 0x123456);
/* private company_id */
crom_add_entry(&root, CSRKEY_VENDOR, 0xacde48);
crom_add_simple_text(&src, &root, &text1, "FreeBSD");
crom_add_entry(&root, CSRKEY_HW, __FreeBSD_version);
crom_add_simple_text(&src, &root, &text2, "FreeBSD-5");
/* SBP unit directory */
crom_add_chunk(&src, &root, &unit1, CROM_UDIR);
crom_add_entry(&unit1, CSRKEY_SPEC, CSRVAL_ANSIT10);
crom_add_entry(&unit1, CSRKEY_VER, CSRVAL_T10SBP2);
crom_add_entry(&unit1, CSRKEY_COM_SPEC, CSRVAL_ANSIT10);
crom_add_entry(&unit1, CSRKEY_COM_SET, CSRVAL_SCSI);
/* management_agent */
crom_add_entry(&unit1, CROM_MGM, 0x1000);
crom_add_entry(&unit1, CSRKEY_UNIT_CH, (10<<8) | 8);
/* Device type and LUN */
crom_add_entry(&unit1, CROM_LUN, 0);
crom_add_entry(&unit1, CSRKEY_MODEL, 1);
crom_add_simple_text(&src, &unit1, &text3, "scsi_target");
/* RFC2734 IPv4 over IEEE1394 */
crom_add_chunk(&src, &root, &unit2, CROM_UDIR);
crom_add_entry(&unit2, CSRKEY_SPEC, CSRVAL_IETF);
crom_add_simple_text(&src, &unit2, &text4, "IANA");
crom_add_entry(&unit2, CSRKEY_VER, 1);
crom_add_simple_text(&src, &unit2, &text5, "IPv4");
/* RFC3146 IPv6 over IEEE1394 */
crom_add_chunk(&src, &root, &unit3, CROM_UDIR);
crom_add_entry(&unit3, CSRKEY_SPEC, CSRVAL_IETF);
crom_add_simple_text(&src, &unit3, &text6, "IANA");
crom_add_entry(&unit3, CSRKEY_VER, 2);
crom_add_simple_text(&src, &unit3, &text7, "IPv6");
crom_load(&src, buf, 256);
p = buf;
#define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n"
for (i = 0; i < 256/8; i ++) {
printf(DUMP_FORMAT,
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
p += 8;
}
return(0);
}
#endif

View File

@ -1,4 +1,5 @@
/*
* Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
@ -42,15 +43,16 @@
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/conf.h>
#include <sys/uio.h>
#include <sys/poll.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <sys/ioccom.h>
#include <dev/firewire/firewire.h>
#include <dev/firewire/firewirereg.h>
#include <dev/firewire/fwdma.h>
#include <dev/firewire/fwmem.h>
#include <dev/firewire/iec68113.h>
@ -112,7 +114,6 @@ fw_open (dev_t dev, int flags, int fmt, fw_proc *td)
/* Default is per packet mode */
sc->fc->ir[sub]->flag |= FWXFERQ_OPEN;
sc->fc->it[sub]->flag |= FWXFERQ_OPEN;
sc->fc->ir[sub]->flag |= FWXFERQ_PACKET;
return err;
}
@ -148,32 +149,9 @@ fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
sc->fc->it[sub]->flag &= ~FWXFERQ_RUNNING;
sc->fc->itx_disable(sc->fc, sub);
}
#ifdef FWXFERQ_DV
if(sc->fc->it[sub]->flag & FWXFERQ_DV){
struct fw_dvbuf *dvbuf;
if((dvbuf = sc->fc->it[sub]->dvproc) != NULL){
free(dvbuf->buf, M_FW);
sc->fc->it[sub]->dvproc = NULL;
}
if((dvbuf = sc->fc->it[sub]->dvdma) != NULL){
free(dvbuf->buf, M_FW);
sc->fc->it[sub]->dvdma = NULL;
}
while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvvalid)) != NULL){
STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvvalid, link);
free(dvbuf->buf, M_FW);
}
while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvfree)) != NULL){
STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvfree, link);
free(dvbuf->buf, M_FW);
}
free(sc->fc->it[sub]->dvbuf, M_FW);
sc->fc->it[sub]->dvbuf = NULL;
}
#endif
if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){
free(sc->fc->ir[sub]->buf, M_FW);
if (sc->fc->ir[sub]->buf != NULL)
fwdma_free_multiseg(sc->fc->ir[sub]->buf);
sc->fc->ir[sub]->buf = NULL;
free(sc->fc->ir[sub]->bulkxfer, M_FW);
sc->fc->ir[sub]->bulkxfer = NULL;
@ -182,13 +160,11 @@ fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
sc->fc->ir[sub]->maxq = FWMAXQUEUE;
}
if(sc->fc->it[sub]->flag & FWXFERQ_EXTBUF){
free(sc->fc->it[sub]->buf, M_FW);
if (sc->fc->it[sub]->buf != NULL)
fwdma_free_multiseg(sc->fc->it[sub]->buf);
sc->fc->it[sub]->buf = NULL;
free(sc->fc->it[sub]->bulkxfer, M_FW);
sc->fc->it[sub]->bulkxfer = NULL;
#ifdef FWXFERQ_DV
sc->fc->it[sub]->dvbuf = NULL;
#endif
sc->fc->it[sub]->flag &= ~FWXFERQ_EXTBUF;
sc->fc->it[sub]->psize = 0;
sc->fc->it[sub]->maxq = FWMAXQUEUE;
@ -199,14 +175,7 @@ fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->q, link);
xfer->resp = 0;
switch(xfer->act_type){
case FWACT_XFER:
fw_xfer_done(xfer);
break;
default:
break;
}
fw_xfer_free(xfer);
fw_xfer_done(xfer);
}
for(fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds); fwb != NULL;
fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds)){
@ -214,8 +183,8 @@ fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->binds, chlist);
free(fwb, M_FW);
}
sc->fc->ir[sub]->flag &= ~FWXFERQ_MODEMASK;
sc->fc->it[sub]->flag &= ~FWXFERQ_MODEMASK;
sc->fc->ir[sub]->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
sc->fc->it[sub]->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
return err;
}
@ -240,12 +209,9 @@ fw_read (dev_t dev, struct uio *uio, int ioflag)
ir = sc->fc->ir[sub];
if (ir->flag & FWXFERQ_PACKET) {
ir->stproc = NULL;
}
readloop:
xfer = STAILQ_FIRST(&ir->q);
if ((ir->flag & FWXFERQ_PACKET) == 0 && ir->stproc == NULL) {
if (ir->stproc == NULL) {
/* iso bulkxfer */
ir->stproc = STAILQ_FIRST(&ir->stvalid);
if (ir->stproc != NULL) {
@ -259,12 +225,6 @@ fw_read (dev_t dev, struct uio *uio, int ioflag)
/* no data avaliable */
if (slept == 0) {
slept = 1;
if ((ir->flag & FWXFERQ_RUNNING) == 0
&& (ir->flag & FWXFERQ_PACKET)) {
err = sc->fc->irx_enable(sc->fc, sub);
if (err)
return err;
}
ir->flag |= FWXFERQ_WAKEUP;
err = tsleep(ir, FWPRI, "fw_read", hz);
ir->flag &= ~FWXFERQ_WAKEUP;
@ -274,30 +234,29 @@ fw_read (dev_t dev, struct uio *uio, int ioflag)
err = EIO;
return err;
} else if(xfer != NULL) {
/* per packet mode */
/* per packet mode or FWACT_CH bind?*/
s = splfw();
ir->queued --;
STAILQ_REMOVE_HEAD(&ir->q, link);
splx(s);
fp = (struct fw_pkt *)(xfer->recv.buf + xfer->recv.off);
fp = (struct fw_pkt *)xfer->recv.buf;
if(sc->fc->irx_post != NULL)
sc->fc->irx_post(sc->fc, fp->mode.ld);
err = uiomove(xfer->recv.buf + xfer->recv.off, xfer->recv.len, uio);
err = uiomove(xfer->recv.buf, xfer->recv.len, uio);
/* XXX we should recycle this xfer */
fw_xfer_free( xfer);
} else if(ir->stproc != NULL) {
/* iso bulkxfer */
fp = (struct fw_pkt *)(ir->stproc->buf + ir->queued * ir->psize);
fp = (struct fw_pkt *)fwdma_v_addr(ir->buf,
ir->stproc->poffset + ir->queued);
if(sc->fc->irx_post != NULL)
sc->fc->irx_post(sc->fc, fp->mode.ld);
if(ntohs(fp->mode.stream.len) == 0){
if(fp->mode.stream.len == 0){
err = EIO;
return err;
}
err = uiomove((caddr_t)fp,
ntohs(fp->mode.stream.len) + sizeof(u_int32_t), uio);
#if 0
fp->mode.stream.len = 0;
#endif
fp->mode.stream.len + sizeof(u_int32_t), uio);
ir->queued ++;
if(ir->queued >= ir->bnpacket){
s = splfw();
@ -335,34 +294,7 @@ fw_write (dev_t dev, struct uio *uio, int ioflag)
fc = sc->fc;
it = sc->fc->it[sub];
fp = (struct fw_pkt *)uio->uio_iov->iov_base;
switch(fp->mode.common.tcode){
case FWTCODE_RREQQ:
case FWTCODE_RREQB:
case FWTCODE_LREQ:
err = EINVAL;
return err;
case FWTCODE_WREQQ:
case FWTCODE_WREQB:
xferq = fc->atq;
break;
case FWTCODE_STREAM:
if(it->flag & FWXFERQ_PACKET){
xferq = fc->atq;
}else{
xferq = NULL;
}
break;
case FWTCODE_WRES:
case FWTCODE_RRESQ:
case FWTCODE_RRESB:
case FWTCODE_LRES:
xferq = fc->ats;
break;
default:
err = EINVAL;
return err;
}
xferq = NULL;
/* Discard unsent buffered stream packet, when sending Asyrequrst */
if(xferq != NULL && it->stproc != NULL){
s = splfw();
@ -370,11 +302,7 @@ fw_write (dev_t dev, struct uio *uio, int ioflag)
splx(s);
it->stproc = NULL;
}
#ifdef FWXFERQ_DV
if(xferq == NULL && !(it->flag & FWXFERQ_DV)){
#else
if (xferq == NULL) {
#endif
isoloop:
if (it->stproc == NULL) {
it->stproc = STAILQ_FIRST(&it->stfree);
@ -398,11 +326,11 @@ fw_write (dev_t dev, struct uio *uio, int ioflag)
return err;
}
}
fp = (struct fw_pkt *)
(it->stproc->buf + it->queued * it->psize);
fp = (struct fw_pkt *)fwdma_v_addr(it->buf,
it->stproc->poffset + it->queued);
err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio);
err = uiomove((caddr_t)fp->mode.stream.payload,
ntohs(fp->mode.stream.len), uio);
fp->mode.stream.len, uio);
it->queued ++;
if (it->queued >= it->bnpacket) {
s = splfw();
@ -417,92 +345,14 @@ fw_write (dev_t dev, struct uio *uio, int ioflag)
}
return err;
}
#ifdef FWXFERQ_DV
if(xferq == NULL && it->flag & FWXFERQ_DV){
dvloop:
if(it->dvproc == NULL){
it->dvproc = STAILQ_FIRST(&it->dvfree);
if(it->dvproc != NULL){
s = splfw();
STAILQ_REMOVE_HEAD(&it->dvfree, link);
splx(s);
it->dvptr = 0;
}else if(slept == 0){
slept = 1;
err = sc->fc->itx_enable(sc->fc, sub);
if(err){
return err;
}
err = tsleep(it, FWPRI, "fw_write", hz);
if(err){
return err;
}
goto dvloop;
}else{
err = EIO;
return err;
}
}
#if 0 /* What's this for? (it->dvptr? overwritten by the following uiomove)*/
fp = (struct fw_pkt *)(it->dvproc->buf + it->queued * it->psize);
fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t));
#endif
err = uiomove(it->dvproc->buf + it->dvptr,
uio->uio_resid, uio);
it->dvptr += it->psize;
if(err){
return err;
}
if(it->dvptr >= it->psize * it->dvpacket){
s = splfw();
STAILQ_INSERT_TAIL(&it->dvvalid, it->dvproc, link);
splx(s);
it->dvproc = NULL;
err = fw_tbuf_update(sc->fc, sub, 0);
if(err){
return err;
}
err = sc->fc->itx_enable(sc->fc, sub);
}
return err;
}
#endif
if(xferq != NULL){
xfer = fw_xfer_alloc(M_FWXFER);
if (xferq != NULL) {
xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid, 12);
if(xfer == NULL){
err = ENOMEM;
return err;
}
xfer->send.buf = malloc(uio->uio_resid, M_FW, M_NOWAIT);
if(xfer->send.buf == NULL){
fw_xfer_free( xfer);
err = ENOBUFS;
return err;
}
xfer->dst = ntohs(fp->mode.hdr.dst);
#if 0
switch(fp->mode.common.tcode){
case FWTCODE_WREQQ:
case FWTCODE_WREQB:
if((tl = fw_get_tlabel(fc, xfer)) == -1 ){
fw_xfer_free( xfer);
err = EAGAIN;
return err;
}
fp->mode.hdr.tlrt = tl << 2;
default:
break;
}
xfer->tl = fp->mode.hdr.tlrt >> 2;
xfer->tcode = fp->mode.common.tcode;
xfer->fc = fc;
xfer->q = xferq;
xfer->act_type = FWACT_XFER;
xfer->retry_req = fw_asybusy;
#endif
xfer->dst = fp->mode.hdr.dst;
xfer->send.len = uio->uio_resid;
xfer->send.off = 0;
xfer->spd = 0;/* XXX: how to setup it */
xfer->act.hand = fw_asy_callback;
@ -511,11 +361,7 @@ fw_write (dev_t dev, struct uio *uio, int ioflag)
fw_xfer_free( xfer);
return err;
}
#if 0
fw_asystart(xfer);
#else
fw_asyreq(fc, -1, xfer);
#endif
err = tsleep(xfer, FWPRI, "fw_write", hz);
if(xfer->resp == EBUSY)
return EBUSY;
@ -534,7 +380,7 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
struct firewire_softc *sc;
int unit = DEV2UNIT(dev);
int sub = DEV2DMACH(dev);
int i, len, err = 0;
int s, i, len, err = 0;
struct fw_device *fwdev;
struct fw_bind *fwb;
struct fw_xferq *ir, *it;
@ -579,50 +425,6 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3;
err = 0;
break;
#ifdef FWXFERQ_DV
case FW_SSTDV:
ibufreq = (struct fw_isobufreq *)
malloc(sizeof(struct fw_isobufreq), M_FW, M_NOWAIT);
if(ibufreq == NULL){
err = ENOMEM;
break;
}
#if DV_PAL
#define FWDVPACKET 300
#else
#define FWDVPACKET 250
#endif
#define FWDVPMAX 512
ibufreq->rx.nchunk = 8;
ibufreq->rx.npacket = 50;
ibufreq->rx.psize = FWDVPMAX;
ibufreq->tx.nchunk = 5;
ibufreq->tx.npacket = FWDVPACKET + 30; /* > 320 or 267 */
ibufreq->tx.psize = FWDVPMAX;
err = fw_ioctl(dev, FW_SSTBUF, (caddr_t)ibufreq, flag, td);
sc->fc->it[sub]->dvpacket = FWDVPACKET;
free(ibufreq, M_FW);
/* reserve a buffer space */
#define NDVCHUNK 8
sc->fc->it[sub]->dvproc = NULL;
sc->fc->it[sub]->dvdma = NULL;
sc->fc->it[sub]->flag |= FWXFERQ_DV;
/* XXX check malloc failure */
sc->fc->it[sub]->dvbuf
= (struct fw_dvbuf *)malloc(sizeof(struct fw_dvbuf) * NDVCHUNK, M_FW, M_NOWAIT);
STAILQ_INIT(&sc->fc->it[sub]->dvvalid);
STAILQ_INIT(&sc->fc->it[sub]->dvfree);
for( i = 0 ; i < NDVCHUNK ; i++){
/* XXX check malloc failure */
sc->fc->it[sub]->dvbuf[i].buf
= malloc(FWDVPMAX * sc->fc->it[sub]->dvpacket, M_FW, M_NOWAIT);
STAILQ_INSERT_TAIL(&sc->fc->it[sub]->dvfree,
&sc->fc->it[sub]->dvbuf[i], link);
}
break;
#endif
case FW_SSTBUF:
ir = sc->fc->ir[sub];
it = sc->fc->it[sub];
@ -639,48 +441,52 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){
return(EINVAL);
}
if(ibufreq->rx.nchunk > FWSTMAXCHUNK ||
ibufreq->tx.nchunk > FWSTMAXCHUNK){
return(EINVAL);
}
ir->bulkxfer
= (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_FW, 0);
= (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_FW, M_WAITOK);
if(ir->bulkxfer == NULL){
return(ENOMEM);
}
it->bulkxfer
= (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_FW, 0);
= (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_FW, M_WAITOK);
if(it->bulkxfer == NULL){
return(ENOMEM);
}
ir->buf = malloc(
ibufreq->rx.nchunk * ibufreq->rx.npacket
/* XXX psize must be 2^n and less or
equal to PAGE_SIZE */
* ((ibufreq->rx.psize + 3) &~3),
M_FW, 0);
if(ir->buf == NULL){
free(ir->bulkxfer, M_FW);
free(it->bulkxfer, M_FW);
ir->bulkxfer = NULL;
it->bulkxfer = NULL;
it->buf = NULL;
return(ENOMEM);
if (ibufreq->rx.psize > 0) {
ibufreq->rx.psize = roundup2(ibufreq->rx.psize,
sizeof(u_int32_t));
ir->buf = fwdma_malloc_multiseg(
sc->fc, sizeof(u_int32_t),
ibufreq->rx.psize,
ibufreq->rx.nchunk * ibufreq->rx.npacket,
BUS_DMA_WAITOK);
if(ir->buf == NULL){
free(ir->bulkxfer, M_FW);
free(it->bulkxfer, M_FW);
ir->bulkxfer = NULL;
it->bulkxfer = NULL;
it->buf = NULL;
return(ENOMEM);
}
}
it->buf = malloc(
ibufreq->tx.nchunk * ibufreq->tx.npacket
/* XXX psize must be 2^n and less or
equal to PAGE_SIZE */
* ((ibufreq->tx.psize + 3) &~3),
M_FW, 0);
if(it->buf == NULL){
free(ir->bulkxfer, M_FW);
free(it->bulkxfer, M_FW);
free(ir->buf, M_FW);
ir->bulkxfer = NULL;
it->bulkxfer = NULL;
it->buf = NULL;
return(ENOMEM);
if (ibufreq->tx.psize > 0) {
ibufreq->tx.psize = roundup2(ibufreq->tx.psize,
sizeof(u_int32_t));
it->buf = fwdma_malloc_multiseg(
sc->fc, sizeof(u_int32_t),
ibufreq->tx.psize,
ibufreq->tx.nchunk * ibufreq->tx.npacket,
BUS_DMA_WAITOK);
if(it->buf == NULL){
free(ir->bulkxfer, M_FW);
free(it->bulkxfer, M_FW);
fwdma_free_multiseg(ir->buf);
ir->bulkxfer = NULL;
it->bulkxfer = NULL;
it->buf = NULL;
return(ENOMEM);
}
}
ir->bnchunk = ibufreq->rx.nchunk;
@ -693,13 +499,6 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
it->psize = (ibufreq->tx.psize + 3) & ~3;
it->queued = 0;
#ifdef FWXFERQ_DV
it->dvdbc = 0;
it->dvdiff = 0;
it->dvsync = 0;
it->dvoffset = 0;
#endif
STAILQ_INIT(&ir->stvalid);
STAILQ_INIT(&ir->stfree);
STAILQ_INIT(&ir->stdma);
@ -711,18 +510,16 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
it->stproc = NULL;
for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){
ir->bulkxfer[i].buf =
ir->buf + i * ir->bnpacket * ir->psize;
ir->bulkxfer[i].poffset = i * ir->bnpacket;
ir->bulkxfer[i].mbuf = NULL;
STAILQ_INSERT_TAIL(&ir->stfree,
&ir->bulkxfer[i], link);
ir->bulkxfer[i].npacket = ir->bnpacket;
}
for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){
it->bulkxfer[i].buf =
it->buf + i * it->bnpacket * it->psize;
it->bulkxfer[i].poffset = i * it->bnpacket;
it->bulkxfer[i].mbuf = NULL;
STAILQ_INSERT_TAIL(&it->stfree,
&it->bulkxfer[i], link);
it->bulkxfer[i].npacket = it->bnpacket;
}
ir->flag &= ~FWXFERQ_MODEMASK;
ir->flag |= FWXFERQ_STREAM;
@ -743,7 +540,8 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
ibufreq->tx.psize = sc->fc->it[sub]->psize;
break;
case FW_ASYREQ:
xfer = fw_xfer_alloc(M_FWXFER);
xfer = fw_xfer_alloc_buf(M_FWXFER, asyreq->req.len,
PAGE_SIZE /* XXX */);
if(xfer == NULL){
err = ENOMEM;
return err;
@ -751,7 +549,7 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
fp = &asyreq->pkt;
switch (asyreq->req.type) {
case FWASREQNODE:
xfer->dst = ntohs(fp->mode.hdr.dst);
xfer->dst = fp->mode.hdr.dst;
break;
case FWASREQEUI:
fwdev = fw_noderesolve_eui64(sc->fc,
@ -763,7 +561,7 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
goto error;
}
xfer->dst = fwdev->dst;
fp->mode.hdr.dst = htons(FWLOCALBUS | xfer->dst);
fp->mode.hdr.dst = FWLOCALBUS | xfer->dst;
break;
case FWASRESTL:
/* XXX what's this? */
@ -773,12 +571,6 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
break;
}
xfer->spd = asyreq->req.sped;
xfer->send.len = asyreq->req.len;
xfer->send.buf = malloc(xfer->send.len, M_FW, M_NOWAIT);
if(xfer->send.buf == NULL){
return ENOMEM;
}
xfer->send.off = 0;
bcopy(fp, xfer->send.buf, xfer->send.len);
xfer->act.hand = fw_asy_callback;
err = fw_asyreq(sc->fc, sub, xfer);
@ -793,7 +585,7 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
}else{
err = EINVAL;
}
bcopy(xfer->recv.buf + xfer->recv.off, fp, asyreq->req.len);
bcopy(xfer->recv.buf, fp, asyreq->req.len);
}
error:
fw_xfer_free( xfer);
@ -829,17 +621,21 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
fwb->start_hi = bindreq->start.hi;
fwb->start_lo = bindreq->start.lo;
fwb->addrlen = bindreq->len;
fwb->sub = sub;
fwb->act_type = FWACT_CH;
xfer = fw_xfer_alloc(M_FWXFER);
if(xfer == NULL){
err = ENOMEM;
return err;
}
xfer->act_type = FWACT_CH;
xfer->sub = sub;
xfer->fc = sc->fc;
fwb->xfer = xfer;
s = splfw();
/* XXX broken. need multiple xfer */
STAILQ_INIT(&fwb->xferlist);
STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link);
splx(s);
err = fw_bindadd(sc->fc, fwb);
break;
case FW_GDEVLST:
@ -876,17 +672,10 @@ fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
err = FWNODE_INVAL;
break;
}
#if 0
if (fwdev->csrrom[0] >> 24 == 1)
len = 4;
else
len = (1 + ((fwdev->csrrom[0] >> 16) & 0xff)) * 4;
#else
if (fwdev->rommax < CSRROMOFF)
len = 0;
else
len = fwdev->rommax - CSRROMOFF + 4;
#endif
if (crom_buf->len < len)
len = crom_buf->len;
else
@ -930,17 +719,17 @@ fw_poll(dev_t dev, int events, fw_proc *td)
}
static int
#if __FreeBSD_version < 500000
#if __FreeBSD_version < 500102
fw_mmap (dev_t dev, vm_offset_t offset, int nproto)
#else
fw_mmap (dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nproto)
fw_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto)
#endif
{
struct firewire_softc *fc;
int unit = DEV2UNIT(dev);
if (DEV_FWMEM(dev))
#if __FreeBSD_version < 500000
#if __FreeBSD_version < 500102
return fwmem_mmap(dev, offset, nproto);
#else
return fwmem_mmap(dev, offset, paddr, nproto);

208
sys/dev/firewire/fwdma.c Normal file
View File

@ -0,0 +1,208 @@
/*
* Copyright (c) 2003
* Hidetoshi Shimokawa. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by Hidetoshi Shimokawa.
*
* 4. Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/types.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <dev/firewire/firewire.h>
#include <dev/firewire/firewirereg.h>
#include <dev/firewire/fwdma.h>
static void
fwdma_map_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
bus_addr_t *baddr;
if (error)
printf("fwdma_map_cb: error=%d\n", error);
baddr = (bus_addr_t *)arg;
*baddr = segs->ds_addr;
}
void *
fwdma_malloc(struct firewire_comm *fc, int alignment, bus_size_t size,
struct fwdma_alloc *dma, int flag)
{
int err;
dma->v_addr = NULL;
err = bus_dma_tag_create(
/*parent*/ fc->dmat,
/*alignment*/ alignment,
/*boundary*/ 0,
/*lowaddr*/ BUS_SPACE_MAXADDR_32BIT,
/*highaddr*/ BUS_SPACE_MAXADDR,
/*filter*/NULL, /*filterarg*/NULL,
/*maxsize*/ size,
/*nsegments*/ 1,
/*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT,
/*flags*/ BUS_DMA_ALLOCNOW, &dma->dma_tag);
if (err) {
printf("fwdma_malloc: failed(1)\n");
return(NULL);
}
err = bus_dmamem_alloc(dma->dma_tag, &dma->v_addr,
flag, &dma->dma_map);
if (err) {
printf("fwdma_malloc: failed(2)\n");
/* XXX destory tag */
return(NULL);
}
bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->v_addr,
size, fwdma_map_cb, &dma->bus_addr, /*flags*/0);
return(dma->v_addr);
}
void
fwdma_free(struct firewire_comm *fc, struct fwdma_alloc *dma)
{
bus_dmamap_unload(dma->dma_tag, dma->dma_map);
bus_dmamem_free(dma->dma_tag, dma->v_addr, dma->dma_map);
bus_dma_tag_destroy(dma->dma_tag);
}
void *
fwdma_malloc_size(bus_dma_tag_t dmat, bus_dmamap_t *dmamap,
bus_size_t size, bus_addr_t *bus_addr, int flag)
{
void *v_addr;
if (bus_dmamem_alloc(dmat, &v_addr, flag, dmamap)) {
printf("fwdma_malloc_size: failed(1)\n");
return(NULL);
}
bus_dmamap_load(dmat, *dmamap, v_addr, size,
fwdma_map_cb, bus_addr, /*flags*/0);
return(v_addr);
}
void
fwdma_free_size(bus_dma_tag_t dmat, bus_dmamap_t dmamap,
void *vaddr, bus_size_t size)
{
bus_dmamap_unload(dmat, dmamap);
bus_dmamem_free(dmat, vaddr, dmamap);
}
/*
* Allocate multisegment dma buffers
* each segment size is eqaul to ssize except last segment.
*/
struct fwdma_alloc_multi *
fwdma_malloc_multiseg(struct firewire_comm *fc, int alignment,
int esize, int n, int flag)
{
struct fwdma_alloc_multi *am;
struct fwdma_seg *seg;
bus_size_t ssize;
int nseg;
if (esize > PAGE_SIZE) {
/* round up to PAGE_SIZE */
esize = ssize = roundup2(esize, PAGE_SIZE);
nseg = n;
} else {
/* allocate PAGE_SIZE segment for small elements */
ssize = rounddown(PAGE_SIZE, esize);
nseg = howmany(n, ssize / esize);
}
am = (struct fwdma_alloc_multi *)malloc(sizeof(struct fwdma_alloc_multi)
+ sizeof(struct fwdma_seg)*nseg, M_FW, M_WAITOK);
if (am == NULL) {
printf("fwdma_malloc_multiseg: malloc failed\n");
return(NULL);
}
am->ssize = ssize;
am->esize = esize;
am->nseg = 0;
if (bus_dma_tag_create(
/*parent*/ fc->dmat,
/*alignment*/ alignment,
/*boundary*/ 0,
/*lowaddr*/ BUS_SPACE_MAXADDR_32BIT,
/*highaddr*/ BUS_SPACE_MAXADDR,
/*filter*/NULL, /*filterarg*/NULL,
/*maxsize*/ ssize,
/*nsegments*/ 1,
/*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT,
/*flags*/ BUS_DMA_ALLOCNOW, &am->dma_tag)) {
printf("fwdma_malloc_multiseg: tag_create failed\n");
free(am, M_FW);
return(NULL);
}
#if 0
#if __FreeBSD_version < 500000
printf("malloc_multi: ssize=%d nseg=%d\n", ssize, nseg);
#else
printf("malloc_multi: ssize=%td nseg=%d\n", ssize, nseg);
#endif
#endif
for (seg = &am->seg[0]; nseg --; seg ++) {
seg->v_addr = fwdma_malloc_size(am->dma_tag, &seg->dma_map,
ssize, &seg->bus_addr, flag);
if (seg->v_addr == NULL) {
printf("fwdma_malloc_multi: malloc_size failed %d\n",
am->nseg);
fwdma_free_multiseg(am);
return(NULL);
}
am->nseg++;
}
return(am);
}
void
fwdma_free_multiseg(struct fwdma_alloc_multi *am)
{
struct fwdma_seg *seg;
for (seg = &am->seg[0]; am->nseg --; seg ++) {
fwdma_free_size(am->dma_tag, seg->dma_map,
seg->v_addr, am->ssize);
}
bus_dma_tag_destroy(am->dma_tag);
free(am, M_FW);
}

116
sys/dev/firewire/fwdma.h Normal file
View File

@ -0,0 +1,116 @@
/*
* Copyright (C) 2003
* Hidetoshi Shimokawa. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by Hidetoshi Shimokawa.
*
* 4. Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#if __FreeBSD_version >= 500111
typedef int bus_dmasync_op_t;
#endif
struct fwdma_alloc {
bus_dma_tag_t dma_tag;
bus_dmamap_t dma_map;
void * v_addr;
bus_addr_t bus_addr;
};
struct fwdma_seg {
bus_dmamap_t dma_map;
void * v_addr;
bus_addr_t bus_addr;
};
struct fwdma_alloc_multi {
bus_size_t ssize;
bus_size_t esize;
int nseg;
bus_dma_tag_t dma_tag;
struct fwdma_seg seg[0];
};
static __inline void *
fwdma_v_addr(struct fwdma_alloc_multi *am, int index)
{
bus_size_t ssize = am->ssize;
int offset = am->esize * index;
return ((caddr_t)am->seg[offset / ssize].v_addr + (offset % ssize));
}
static __inline bus_addr_t
fwdma_bus_addr(struct fwdma_alloc_multi *am, int index)
{
bus_size_t ssize = am->ssize;
int offset = am->esize * index;
return (am->seg[offset / ssize].bus_addr + (offset % ssize));
}
static __inline void
fwdma_sync(struct fwdma_alloc *dma, bus_dmasync_op_t op)
{
bus_dmamap_sync(dma->dma_tag, dma->dma_map, op);
}
static __inline void
fwdma_sync_multiseg(struct fwdma_alloc_multi *am,
int start, int end, bus_dmasync_op_t op)
{
struct fwdma_seg *seg, *eseg;
seg = &am->seg[am->esize * start / am->ssize];
eseg = &am->seg[am->esize * end / am->ssize];
for (; seg <= eseg; seg ++)
bus_dmamap_sync(am->dma_tag, seg->dma_map, op);
}
static __inline void
fwdma_sync_multiseg_all(struct fwdma_alloc_multi *am, bus_dmasync_op_t op)
{
struct fwdma_seg *seg;
int i;
seg = &am->seg[0];
for (i = 0; i < am->nseg; i++, seg++)
bus_dmamap_sync(am->dma_tag, seg->dma_map, op);
}
void *fwdma_malloc(struct firewire_comm *, int, bus_size_t, struct fwdma_alloc *, int);
void fwdma_free(struct firewire_comm *, struct fwdma_alloc *);
void *fwdma_malloc_size(bus_dma_tag_t, bus_dmamap_t *, bus_size_t, bus_addr_t *, int);
void fwdma_free_size(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t);
struct fwdma_alloc_multi *fwdma_malloc_multiseg(struct firewire_comm *,
int, int, int, int);
void fwdma_free_multiseg(struct fwdma_alloc_multi *);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2002
* Copyright (c) 2002-2003
* Hidetoshi Shimokawa. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -41,10 +41,10 @@
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/conf.h>
#include <sys/uio.h>
#include <sys/sysctl.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <sys/signal.h>
#include <sys/mman.h>
@ -68,20 +68,18 @@ SYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
SYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
"Fwmem driver debug flag");
static struct fw_xfer *fwmem_xfer_req(struct fw_device *, caddr_t,
int, int, void *);
static struct fw_xfer *
fwmem_xfer_req(
struct fw_device *fwdev,
caddr_t sc,
int spd,
int len,
int slen,
int rlen,
void *hand)
{
struct fw_xfer *xfer;
xfer = fw_xfer_alloc(M_FWXFER);
xfer = fw_xfer_alloc_buf(M_FWXFER, slen, rlen);
if (xfer == NULL)
return NULL;
@ -91,15 +89,6 @@ fwmem_xfer_req(
xfer->spd = fwdev->speed;
else
xfer->spd = min(spd, fwdev->speed);
xfer->send.len = len;
xfer->send.buf = malloc(len, M_FW, M_NOWAIT | M_ZERO);
if (xfer->send.buf == NULL) {
fw_xfer_free(xfer);
return NULL;
}
xfer->send.off = 0;
xfer->act.hand = hand;
xfer->retry_req = fw_asybusy;
xfer->sc = sc;
@ -119,15 +108,15 @@ fwmem_read_quad(
struct fw_xfer *xfer;
struct fw_pkt *fp;
xfer = fwmem_xfer_req(fwdev, sc, spd, 12, hand);
xfer = fwmem_xfer_req(fwdev, sc, spd, 12, 16, hand);
if (xfer == NULL)
return NULL;
fp = (struct fw_pkt *)xfer->send.buf;
fp->mode.rreqq.tcode = FWTCODE_RREQQ;
fp->mode.rreqq.dst = htons(xfer->dst);
fp->mode.rreqq.dest_hi = htons(dst_hi);
fp->mode.rreqq.dest_lo = htonl(dst_lo);
fp->mode.rreqq.dst = xfer->dst;
fp->mode.rreqq.dest_hi = dst_hi;
fp->mode.rreqq.dest_lo = dst_lo;
if (fwmem_debug)
printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst,
@ -153,15 +142,15 @@ fwmem_write_quad(
struct fw_xfer *xfer;
struct fw_pkt *fp;
xfer = fwmem_xfer_req(fwdev, sc, spd, 16, hand);
xfer = fwmem_xfer_req(fwdev, sc, spd, 16, 12, hand);
if (xfer == NULL)
return NULL;
fp = (struct fw_pkt *)xfer->send.buf;
fp->mode.wreqq.tcode = FWTCODE_WREQQ;
fp->mode.wreqq.dst = htons(xfer->dst);
fp->mode.wreqq.dest_hi = htons(dst_hi);
fp->mode.wreqq.dest_lo = htonl(dst_lo);
fp->mode.wreqq.dst = xfer->dst;
fp->mode.wreqq.dest_hi = dst_hi;
fp->mode.wreqq.dest_lo = dst_lo;
fp->mode.wreqq.data = data;
@ -189,16 +178,16 @@ fwmem_read_block(
struct fw_xfer *xfer;
struct fw_pkt *fp;
xfer = fwmem_xfer_req(fwdev, sc, spd, 16, hand);
xfer = fwmem_xfer_req(fwdev, sc, spd, 16, roundup2(16+len,4), hand);
if (xfer == NULL)
return NULL;
fp = (struct fw_pkt *)xfer->send.buf;
fp->mode.rreqb.tcode = FWTCODE_RREQB;
fp->mode.rreqb.dst = htons(xfer->dst);
fp->mode.rreqb.dest_hi = htons(dst_hi);
fp->mode.rreqb.dest_lo = htonl(dst_lo);
fp->mode.rreqb.len = htons(len);
fp->mode.rreqb.dst = xfer->dst;
fp->mode.rreqb.dest_hi = dst_hi;
fp->mode.rreqb.dest_lo = dst_lo;
fp->mode.rreqb.len = len;
if (fwmem_debug)
printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst,
@ -224,16 +213,16 @@ fwmem_write_block(
struct fw_xfer *xfer;
struct fw_pkt *fp;
xfer = fwmem_xfer_req(fwdev, sc, spd, 16 + roundup(len, 4), hand);
xfer = fwmem_xfer_req(fwdev, sc, spd, roundup(16+len, 4), 12, hand);
if (xfer == NULL)
return NULL;
fp = (struct fw_pkt *)xfer->send.buf;
fp->mode.wreqb.tcode = FWTCODE_WREQB;
fp->mode.wreqb.dst = htons(xfer->dst);
fp->mode.wreqb.dest_hi = htons(dst_hi);
fp->mode.wreqb.dest_lo = htonl(dst_lo);
fp->mode.wreqb.len = htons(len);
fp->mode.wreqb.dst = xfer->dst;
fp->mode.wreqb.dest_hi = dst_hi;
fp->mode.wreqb.dest_lo = dst_lo;
fp->mode.wreqb.len = len;
bcopy(data, &fp->mode.wreqb.payload[0], len);
if (fwmem_debug)
@ -252,7 +241,8 @@ fwmem_open (dev_t dev, int flags, int fmt, fw_proc *td)
{
struct fw_eui64 *eui;
eui = (struct fw_eui64 *)malloc(sizeof(struct fw_eui64), M_FW, 0);
eui = (struct fw_eui64 *)malloc(sizeof(struct fw_eui64),
M_FW, M_WAITOK);
if (eui == NULL)
return ENOMEM;
bcopy(&fwmem_eui64, eui, sizeof(struct fw_eui64));
@ -310,8 +300,7 @@ fwmem_read (dev_t dev, struct uio *uio, int ioflag)
else if (xfer->resp != 0)
err = xfer->resp;
else if (err == 0)
err = uiomove(xfer->recv.buf
+ xfer->recv.off + 4*3, 4, uio);
err = uiomove(xfer->recv.buf + 4*3, 4, uio);
} else {
if (len > MAXLEN)
len = MAXLEN;
@ -327,8 +316,7 @@ fwmem_read (dev_t dev, struct uio *uio, int ioflag)
else if (xfer->resp != 0)
err = xfer->resp;
else if (err == 0)
err = uiomove(xfer->recv.buf
+ xfer->recv.off + 4*4, len, uio);
err = uiomove(xfer->recv.buf + 4*4, len, uio);
}
fw_xfer_free(xfer);
}
@ -357,7 +345,7 @@ fwmem_write (dev_t dev, struct uio *uio, int ioflag)
return EINVAL;
}
data = malloc(MAXLEN, M_FW, 0);
data = malloc(MAXLEN, M_FW, M_WAITOK);
if (data == NULL)
return ENOMEM;
@ -421,10 +409,10 @@ fwmem_poll (dev_t dev, int events, fw_proc *td)
return EINVAL;
}
int
#if __FreeBSD_version < 500000
#if __FreeBSD_version < 500102
fwmem_mmap (dev_t dev, vm_offset_t offset, int nproto)
#else
fwmem_mmap (dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nproto)
fwmem_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto)
#endif
{
return EINVAL;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2002
* Copyright (C) 2002-2003
* Hidetoshi Shimokawa. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
/*
* Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
@ -33,6 +34,8 @@
* $FreeBSD$
*/
#define BOUNCE_BUFFER_TEST 0
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@ -50,6 +53,7 @@
#include <dev/firewire/firewire.h>
#include <dev/firewire/firewirereg.h>
#include <dev/firewire/fwdma.h>
#include <dev/firewire/fwohcireg.h>
#include <dev/firewire/fwohcivar.h>
@ -103,7 +107,7 @@ fwohci_pci_probe( device_t dev )
return 0;
}
if (id == (FW_VENDORID_SONY | FW_DEVICE_CX3022)) {
device_set_desc(dev, "SONY CX3022");
device_set_desc(dev, "Sony CX3022");
return 0;
}
if (id == (FW_VENDORID_VIA | FW_DEVICE_VT6306)) {
@ -150,7 +154,7 @@ fwohci_dummy_intr(void *arg)
static int
fwohci_pci_init(device_t self)
{
int latency, cache_line;
int olatency, latency, ocache_line, cache_line;
u_int16_t cmd;
cmd = pci_read_config(self, PCIR_COMMAND, 2);
@ -161,25 +165,26 @@ fwohci_pci_init(device_t self)
#endif
pci_write_config(self, PCIR_COMMAND, cmd, 2);
latency = pci_read_config(self, PCIR_LATTIMER, 1);
latency = olatency = pci_read_config(self, PCIR_LATTIMER, 1);
#define DEF_LATENCY 0x20
if( latency < DEF_LATENCY ) {
if (olatency < DEF_LATENCY) {
latency = DEF_LATENCY;
device_printf(self, "PCI bus latency was changing to");
pci_write_config(self, PCIR_LATTIMER,latency, 1);
} else
{
device_printf(self, "PCI bus latency is");
pci_write_config(self, PCIR_LATTIMER, latency, 1);
}
cache_line = ocache_line = pci_read_config(self, PCIR_CACHELNSZ, 1);
#define DEF_CACHE_LINE 8
if (ocache_line < DEF_CACHE_LINE) {
cache_line = DEF_CACHE_LINE;
pci_write_config(self, PCIR_CACHELNSZ, cache_line, 1);
}
if (firewire_debug) {
device_printf(self, "latency timer %d -> %d.\n",
olatency, latency);
device_printf(self, "cache size %d -> %d.\n",
ocache_line, cache_line);
}
printf(" %d.\n", (int) latency);
cache_line = pci_read_config(self, PCIR_CACHELNSZ, 1);
#if 0
#define DEF_CACHE_LINE 0xc
cache_line = DEF_CACHE_LINE;
pci_write_config(self, PCIR_CACHELNSZ, cache_line, 1);
#endif
if (bootverbose)
device_printf(self, "cache size %d.\n", (int) cache_line);
return 0;
}
@ -198,13 +203,13 @@ fwohci_pci_attach(device_t self)
device_printf(self, "Invalid irq %d\n", intr);
#ifdef __i386__
device_printf(self, "Please switch PNP-OS to 'No' in BIOS\n");
#endif
#if 0
return ENXIO;
#endif
}
#endif
if (bootverbose)
firewire_debug = bootverbose;
fwohci_pci_init(self);
rid = PCI_CBMEM;
@ -235,7 +240,12 @@ fwohci_pci_attach(device_t self)
}
device_set_ivars(sc->fc.bdev, sc);
err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_NET,
err = bus_setup_intr(self, sc->irq_res,
#if FWOHCI_TASKQUEUE
INTR_TYPE_NET | INTR_MPSAFE,
#else
INTR_TYPE_NET,
#endif
(driver_intr_t *) fwohci_intr, sc, &sc->ih);
#if __FreeBSD_version < 500000
/* XXX splcam() should mask this irq for sbp.c*/
@ -248,6 +258,26 @@ fwohci_pci_attach(device_t self)
return ENXIO;
}
err = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1,
/*boundary*/0,
#if BOUNCE_BUFFER_TEST
/*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
#else
/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
#endif
/*highaddr*/BUS_SPACE_MAXADDR,
/*filter*/NULL, /*filterarg*/NULL,
/*maxsize*/0x100000,
/*nsegments*/0x20,
/*maxsegsz*/0x8000,
/*flags*/BUS_DMA_ALLOCNOW,
&sc->fc.dmat);
if (err != 0) {
printf("fwohci_pci_attach: Could not allocate DMA tag "
"- error %d\n", err);
return (ENOMEM);
}
err = fwohci_init(sc, self);
if (!err)
@ -263,9 +293,6 @@ fwohci_pci_attach(device_t self)
* Clear the bus reset event flag to start transactions even when
* interrupt is disabled during the boot process.
*/
#if 0
DELAY(100);
#endif
s = splfw();
fwohci_intr((void *)sc);
splx(s);

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 1998-2001 Katsushi Kobayashi and Hidetoshi Shimokawa
* Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -71,55 +72,68 @@
typedef volatile u_int32_t fwohcireg_t;
/* for PCI */
#if BYTE_ORDER == BIG_ENDIAN
#define FWOHCI_DMA_WRITE(x, y) ((x) = htole32(y))
#define FWOHCI_DMA_READ(x) le32toh(x)
#define FWOHCI_DMA_SET(x, y) ((x) |= htole32(y))
#define FWOHCI_DMA_CLEAR(x, y) ((x) &= htole32(~(y)))
#else
#define FWOHCI_DMA_WRITE(x, y) ((x) = (y))
#define FWOHCI_DMA_READ(x) (x)
#define FWOHCI_DMA_SET(x, y) ((x) |= (y))
#define FWOHCI_DMA_CLEAR(x, y) ((x) &= ~(y))
#endif
struct fwohcidb {
union {
struct {
volatile u_int32_t reqcount:16,
control:16;
volatile u_int32_t cmd;
volatile u_int32_t addr;
volatile u_int32_t depend;
volatile u_int32_t count:16,
status:16;
volatile u_int32_t res;
} desc;
volatile u_int32_t immed[4];
} db;
#define OHCI_OUTPUT_MORE (0 << 12)
#define OHCI_OUTPUT_LAST (1 << 12)
#define OHCI_INPUT_MORE (2 << 12)
#define OHCI_INPUT_LAST (3 << 12)
#define OHCI_STORE_QUAD (4 << 12)
#define OHCI_LOAD_QUAD (5 << 12)
#define OHCI_NOP (6 << 12)
#define OHCI_STOP (7 << 12)
#define OHCI_STORE (8 << 12)
#define OHCI_CMD_MASK (0xf << 12)
#define OHCI_STATUS_SHIFT 16
#define OHCI_COUNT_MASK 0xffff
#define OHCI_OUTPUT_MORE (0 << 28)
#define OHCI_OUTPUT_LAST (1 << 28)
#define OHCI_INPUT_MORE (2 << 28)
#define OHCI_INPUT_LAST (3 << 28)
#define OHCI_STORE_QUAD (4 << 28)
#define OHCI_LOAD_QUAD (5 << 28)
#define OHCI_NOP (6 << 28)
#define OHCI_STOP (7 << 28)
#define OHCI_STORE (8 << 28)
#define OHCI_CMD_MASK (0xf << 28)
#define OHCI_UPDATE (1 << 11)
#define OHCI_UPDATE (1 << 27)
#define OHCI_KEY_ST0 (0 << 8)
#define OHCI_KEY_ST1 (1 << 8)
#define OHCI_KEY_ST2 (2 << 8)
#define OHCI_KEY_ST3 (3 << 8)
#define OHCI_KEY_REGS (5 << 8)
#define OHCI_KEY_SYS (6 << 8)
#define OHCI_KEY_DEVICE (7 << 8)
#define OHCI_KEY_MASK (7 << 8)
#define OHCI_KEY_ST0 (0 << 24)
#define OHCI_KEY_ST1 (1 << 24)
#define OHCI_KEY_ST2 (2 << 24)
#define OHCI_KEY_ST3 (3 << 24)
#define OHCI_KEY_REGS (5 << 24)
#define OHCI_KEY_SYS (6 << 24)
#define OHCI_KEY_DEVICE (7 << 24)
#define OHCI_KEY_MASK (7 << 24)
#define OHCI_INTERRUPT_NEVER (0 << 4)
#define OHCI_INTERRUPT_TRUE (1 << 4)
#define OHCI_INTERRUPT_FALSE (2 << 4)
#define OHCI_INTERRUPT_ALWAYS (3 << 4)
#define OHCI_INTERRUPT_NEVER (0 << 20)
#define OHCI_INTERRUPT_TRUE (1 << 20)
#define OHCI_INTERRUPT_FALSE (2 << 20)
#define OHCI_INTERRUPT_ALWAYS (3 << 20)
#define OHCI_BRANCH_NEVER (0 << 2)
#define OHCI_BRANCH_TRUE (1 << 2)
#define OHCI_BRANCH_FALSE (2 << 2)
#define OHCI_BRANCH_ALWAYS (3 << 2)
#define OHCI_BRANCH_MASK (3 << 2)
#define OHCI_BRANCH_NEVER (0 << 18)
#define OHCI_BRANCH_TRUE (1 << 18)
#define OHCI_BRANCH_FALSE (2 << 18)
#define OHCI_BRANCH_ALWAYS (3 << 18)
#define OHCI_BRANCH_MASK (3 << 18)
#define OHCI_WAIT_NEVER (0)
#define OHCI_WAIT_TRUE (1)
#define OHCI_WAIT_FALSE (2)
#define OHCI_WAIT_ALWAYS (3)
#define OHCI_WAIT_NEVER (0 << 16)
#define OHCI_WAIT_TRUE (1 << 16)
#define OHCI_WAIT_FALSE (2 << 16)
#define OHCI_WAIT_ALWAYS (3 << 16)
};
#define OHCI_SPD_S100 0x4
@ -298,8 +312,9 @@ struct fwohcidb_tr{
STAILQ_ENTRY(fwohcidb_tr) link;
struct fw_xfer *xfer;
volatile struct fwohcidb *db;
bus_dmamap_t dma_map;
caddr_t buf;
caddr_t dummy;
bus_addr_t bus_addr;
int dbcnt;
};
@ -310,31 +325,55 @@ struct fwohci_txpkthdr{
union{
u_int32_t ld[4];
struct {
u_int32_t res3:4,
tcode:4,
res2:8,
#if BYTE_ORDER == BIG_ENDIAN
u_int32_t :13,
spd:3,
res1:13;
:8,
tcode:4,
:4;
#else
u_int32_t :4,
tcode:4,
:8,
spd:3,
:13;
#endif
}common;
struct {
u_int32_t res3:4,
tcode:4,
tlrt:8,
spd:3,
res2:4,
srcbus:1,
res1:8;
u_int32_t res4:16,
dst:16;
#if BYTE_ORDER == BIG_ENDIAN
u_int32_t :8,
srcbus:1,
:4,
spd:3,
tlrt:8,
tcode:4,
:4;
#else
u_int32_t :4,
tcode:4,
tlrt:8,
spd:3,
:4,
srcbus:1,
:8;
#endif
BIT16x2(dst, );
}asycomm;
struct {
#if BYTE_ORDER == BIG_ENDIAN
u_int32_t :13,
spd:3,
chtag:8,
tcode:4,
sy:4;
#else
u_int32_t sy:4,
tcode:4,
chtag:8,
spd:3,
res1:13;
u_int32_t res2:16,
len:16;
:13;
#endif
BIT16x2(len, );
}stream;
}mode;
};

View File

@ -1,4 +1,5 @@
/*
* Copyright (c) 2003 Hidetoshi SHimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi SHimokawa
* All rights reserved.
*
@ -33,6 +34,16 @@
* $FreeBSD$
*
*/
#if __FreeBSD_version >= 500000
#define FWOHCI_TASKQUEUE 1
#else
#define FWOHCI_TASKQUEUE 0
#endif
#if FWOHCI_TASKQUEUE
#include <sys/taskqueue.h>
#endif
typedef struct fwohci_softc {
struct firewire_comm fc;
bus_space_tag_t bst;
@ -41,34 +52,36 @@ typedef struct fwohci_softc {
#if __FreeBSD_version < 500000
void *ih_cam;
#endif
struct resource *bsr;
struct resource *irq_res;
struct fwohci_dbch{
u_int ndb;
u_int ndesc;
caddr_t dummy;
STAILQ_HEAD(, fwohcidb_tr) db_trq;
struct fwohcidb_tr *top, *bottom, *pdb_tr;
struct fw_xferq xferq;
struct {
int len;
int hlen;
int plen;
caddr_t buf;
} frag;
int flags;
#define FWOHCI_DBCH_INIT (1<<0)
#define FWOHCI_DBCH_FULL (1<<1)
int buf_offset;
/* used only in receive context */
int buf_offset; /* signed */
#define FWOHCI_DBCH_MAX_PAGES 32
int npages;
void *pages[FWOHCI_DBCH_MAX_PAGES];
/* Context programs buffer */
struct fwdma_alloc_multi *am;
bus_dma_tag_t dmat;
} arrq, arrs, atrq, atrs, it[OHCI_DMA_ITCH], ir[OHCI_DMA_IRCH];
u_int maxrec;
u_int32_t *cromptr;
u_int32_t intmask;
u_int32_t *sid_buf;
struct fwdma_alloc sid_dma;
struct fwdma_alloc crom_dma;
struct fwdma_alloc dummy_dma;
u_int32_t intmask, irstat, itstat;
#if FWOHCI_TASKQUEUE
u_int32_t intstat;
struct task fwohci_task_complete;
#endif
} fwohci_softc_t;
void fwohci_intr __P((void *arg));
int fwohci_init __P((struct fwohci_softc *, device_t));
void fwohci_reset __P((struct fwohci_softc *, device_t));

View File

@ -1,4 +1,5 @@
/*
* Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
@ -66,65 +67,90 @@
#define CSRKEY_DID 0x20 /* Directory_ID */
#define CSRKEY_REV 0x21 /* Revision */
#define CROM_TEXTLEAF (CSRTYPE_L | CSRKEY_DESC) /* 0x81 */
#define CROM_LUN (CSRTYPE_I | CSRKEY_DINFO) /* 0x14 */
#define CSRKEY_FIRM_VER 0x3c /* Firemware version */
#define CSRKEY_UNIT_CH 0x3a /* Unit characteristics */
#define CSRKEY_COM_SPEC 0x38 /* Command set revision */
#define CSRKEY_COM_SET 0x39 /* Command set */
/* ???
#define CSRKEY_MVID 0x3
#define CSRKEY_NUNQ 0x8d
#define CSRKEY_NPWR 0x30
*/
#define CROM_UDIR (CSRTYPE_D | CSRKEY_UNIT) /* 0x81 Unit directory */
#define CROM_TEXTLEAF (CSRTYPE_L | CSRKEY_DESC) /* 0x81 Text leaf */
#define CROM_LUN (CSRTYPE_I | CSRKEY_DINFO) /* 0x14 Logical unit num. */
#define CROM_MGM (CSRTYPE_C | CSRKEY_DINFO) /* 0x54 Management agent */
#define CSRVAL_1394TA 0x00a02d
#define CSRVAL_ANSIT10 0x00609e
#define CSR_PROTAVC 0x010001
#define CSR_PROTCAL 0x010002
#define CSR_PROTEHS 0x010004
#define CSR_PROTHAVI 0x010008
#define CSR_PROTCAM104 0x000100
#define CSR_PROTCAM120 0x000101
#define CSR_PROTCAM130 0x000102
#define CSR_PROTDPP 0x0a6be2
#define CSR_PROTIICP 0x4b661f
#define CSRVAL_1394TA 0x00a02d
#define CSRVAL_ANSIT10 0x00609e
#define CSRVAL_IETF 0x00005e
#define CSRVAL_T10SBP2 0x010483
#define CSR_PROTAVC 0x010001
#define CSR_PROTCAL 0x010002
#define CSR_PROTEHS 0x010004
#define CSR_PROTHAVI 0x010008
#define CSR_PROTCAM104 0x000100
#define CSR_PROTCAM120 0x000101
#define CSR_PROTCAM130 0x000102
#define CSR_PROTDPP 0x0a6be2
#define CSR_PROTIICP 0x4b661f
#define CSRVAL_T10SBP2 0x010483
#define CSRVAL_SCSI 0x0104d8
struct csrreg {
#if BYTE_ORDER == BIG_ENDIAN
u_int32_t key:8,
val:24;
#else
u_int32_t val:24,
key:8;
#endif
};
struct csrhdr {
#if BYTE_ORDER == BIG_ENDIAN
u_int32_t info_len:8,
crc_len:8,
crc:16;
#else
u_int32_t crc:16,
crc_len:8,
info_len:8;
#endif
};
struct csrdirectory {
u_int32_t crc:16,
crc_len:16;
BIT16x2(crc_len, crc);
struct csrreg entry[0];
};
struct csrtext {
u_int32_t crc:16,
crc_len:16;
BIT16x2(crc_len, crc);
#if BYTE_ORDER == BIG_ENDIAN
u_int32_t spec_type:8,
spec_id:24;
#else
u_int32_t spec_id:24,
spec_type:8;
#endif
u_int32_t lang_id;
u_int32_t text[0];
};
struct businfo {
u_int32_t crc:16,
crc_len:8,
:12,
max_rec:4,
clk_acc:8,
:4,
bmc:1,
isc:1,
cmc:1,
irmc:1;
u_int32_t c_id_hi:8,
v_id:24;
u_int32_t c_id_lo;
struct bus_info {
#define CSR_BUS_NAME_IEEE1394 0x31333934
u_int32_t bus_name;
u_int32_t link_spd:3,
:1,
generation:4,
#define MAXROM_4 0
#define MAXROM_64 1
#define MAXROM_1024 2
max_rom:2,
:2,
max_rec:4, /* (2 << max_rec) bytes */
cyc_clk_acc:8, /* 0 <= ppm <= 100 */
:3,
pmc:1, /* power manager capable */
bmc:1, /* bus manager capable */
isc:1, /* iso. operation support */
cmc:1, /* cycle master capable */
irmc:1; /* iso. resource manager capable */
struct fw_eui64 eui64;
};
#define CROM_MAX_DEPTH 10
@ -147,3 +173,33 @@ struct csrreg *crom_search_key(struct crom_context *, u_int8_t);
#ifndef _KERNEL
char *crom_desc(struct crom_context *, char *, int);
#endif
/* For CROM build */
#if defined(_KERNEL) || defined(TEST)
#define CROM_MAX_CHUNK_LEN 20
struct crom_src {
struct csrhdr hdr;
struct bus_info businfo;
STAILQ_HEAD(, crom_chunk) chunk_list;
};
struct crom_chunk {
STAILQ_ENTRY(crom_chunk) link;
struct crom_chunk *ref_chunk;
int ref_index;
int offset;
struct {
u_int32_t crc:16,
crc_len:16;
u_int32_t buf[CROM_MAX_CHUNK_LEN];
} data;
};
extern int crom_add_quad(struct crom_chunk *, u_int32_t);
extern int crom_add_entry(struct crom_chunk *, int, int);
extern int crom_add_chunk(struct crom_src *src, struct crom_chunk *,
struct crom_chunk *, int);
extern int crom_add_simple_text(struct crom_src *src, struct crom_chunk *,
struct crom_chunk *, char *);
extern int crom_load(struct crom_src *, u_int32_t *, int);
#endif

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 1998-2001 Katsushi Kobayashi and Hidetoshi Shimokawa
* Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -34,29 +35,55 @@
*
*/
struct ciphdr {
#if BYTE_ORDER == BIG_ENDIAN
u_int8_t eoh0:1, /* 0 */
form0:1, /* 0 */
src:6;
#else
u_int8_t src:6,
form0:1, /* 0 */
eoh0:1; /* 0 */
#endif
u_int8_t len;
#if BYTE_ORDER == BIG_ENDIAN
u_int8_t fn:2,
qpc:3,
sph:1,
:2;
#else
u_int8_t :2,
sph:1,
qpc:3,
fn:2;
#endif
u_int8_t dbc;
#if BYTE_ORDER == BIG_ENDIAN
u_int8_t eoh1:1, /* 1 */
form1:1, /* 0 */
fmt:6;
#else
u_int8_t fmt:6,
#define CIP_FMT_DVCR 0
#define CIP_FMT_MPEG (1<<5)
form1:1, /* 0 */
eoh1:1; /* 1 */
#endif
#define CIP_FMT_DVCR 0
#define CIP_FMT_MPEG (1<<5)
union {
struct {
u_int8_t :2,
stype:5,
#if BYTE_ORDER == BIG_ENDIAN
u_int8_t fs:1, /* 50/60 field system
NTSC/PAL */
stype:5,
:2;
#else
u_int8_t :2,
stype:5,
fs:1; /* 50/60 field system
NTSC/PAL */
#endif
#define CIP_STYPE_SD 0
#define CIP_STYPE_SDL 1
#define CIP_STYPE_HD 2
fs:1; /* 50/60 field system
NTSC/PAL */
u_int16_t cyc:16; /* take care of byte order! */
} __attribute__ ((packed)) dv;
u_int8_t bytes[3];
@ -64,17 +91,29 @@ struct ciphdr {
};
struct dvdbc{
#if BYTE_ORDER == BIG_ENDIAN
u_int8_t sct:3, /* Section type */
:1, /* Reserved */
arb:4; /* Arbitrary bit */
#else
u_int8_t arb:4, /* Arbitrary bit */
:1, /* Reserved */
sct:3; /* Section type */
#endif
#define DV_SCT_HEADER 0
#define DV_SCT_SUBCODE 1
#define DV_SCT_VAUX 2
#define DV_SCT_AUDIO 3
#define DV_SCT_VIDEO 4
#if BYTE_ORDER == BIG_ENDIAN
u_int8_t dseq:4, /* DIF sequence number */
fsc:1, /* ID of a DIF block in each channel */
:3;
#else
u_int8_t :3,
fsc:1, /* ID of a DIF block in each channel */
dseq:4; /* DIF sequence number */
#endif
u_int8_t dbn; /* DIF block number */
u_int8_t payload[77];
#define DV_DSF_12 0x80 /* PAL: payload[0] in Header DIF */

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2002
* Copyright (c) 2002-2003
* Hidetoshi Shimokawa. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -47,6 +47,7 @@
#include <sys/systm.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <net/bpf.h>
#include <net/ethernet.h>
@ -234,8 +235,8 @@ fwe_stop(struct fwe_softc *fwe)
if (xferq->flag & FWXFERQ_RUNNING)
fc->irx_disable(fc, fwe->dma_ch);
xferq->flag &=
~(FWXFERQ_MODEMASK | FWXFERQ_OPEN |
FWXFERQ_EXTBUF | FWXFERQ_HANDLER);
~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
FWXFERQ_EXTBUF | FWXFERQ_HANDLER | FWXFERQ_CHTAGMASK);
xferq->hand = NULL;
for (i = 0; i < xferq->bnchunk; i ++)
@ -284,6 +285,7 @@ fwe_init(void *arg)
struct ifnet *ifp = &fwe->fwe_if;
struct fw_xferq *xferq;
struct fw_xfer *xfer;
struct mbuf *m;
int i;
FWEDEBUG("initializing %s%d\n", ifp->if_name, ifp->if_unit);
@ -309,19 +311,21 @@ fwe_init(void *arg)
fwe->stream_ch = stream_ch;
fwe->pkt_hdr.mode.stream.chtag = fwe->stream_ch;
/* allocate DMA channel and init packet mode */
xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF;
xferq->flag |= FWXFERQ_OPEN | FWXFERQ_EXTBUF |
FWXFERQ_HANDLER | FWXFERQ_STREAM;
xferq->flag &= ~0xff;
xferq->flag |= fwe->stream_ch & 0xff;
/* register fwe_input handler */
xferq->sc = (caddr_t) fwe;
xferq->hand = fwe_as_input;
xferq->flag |= FWXFERQ_HANDLER;
xferq->bnchunk = RX_MAX_QUEUE;
xferq->bnpacket = 1;
xferq->psize = MCLBYTES;
xferq->queued = 0;
xferq->buf = NULL;
xferq->bulkxfer = (struct fw_bulkxfer *) malloc(
sizeof(struct fw_bulkxfer) * xferq->bnchunk, M_FWE, 0);
sizeof(struct fw_bulkxfer) * xferq->bnchunk,
M_FWE, M_WAITOK);
if (xferq->bulkxfer == NULL) {
printf("if_fwe: malloc failed\n");
return;
@ -331,23 +335,25 @@ fwe_init(void *arg)
STAILQ_INIT(&xferq->stdma);
xferq->stproc = NULL;
for (i = 0; i < xferq->bnchunk; i ++) {
xferq->bulkxfer[i].mbuf =
m =
#if __FreeBSD_version >= 500000
m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR);
#else
m_getcl(M_WAIT, MT_DATA, M_PKTHDR);
#endif
xferq->bulkxfer[i].buf =
mtod(xferq->bulkxfer[i].mbuf, char *);
STAILQ_INSERT_TAIL(&xferq->stfree,
&xferq->bulkxfer[i], link);
xferq->bulkxfer[i].mbuf = m;
if (m != NULL) {
m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
STAILQ_INSERT_TAIL(&xferq->stfree,
&xferq->bulkxfer[i], link);
} else
printf("fwe_as_input: m_getcl failed\n");
}
STAILQ_INIT(&fwe->xferlist);
for (i = 0; i < TX_MAX_QUEUE; i++) {
xfer = fw_xfer_alloc(M_FWE);
if (xfer == NULL)
break;
xfer->send.off = 0;
xfer->spd = 2;
xfer->fc = fwe->fd.fc;
xfer->retry_req = fw_asybusy;
@ -446,21 +452,15 @@ fwe_output_callback(struct fw_xfer *xfer)
m_freem(xfer->mbuf);
xfer->send.buf = NULL;
#if 0
fw_xfer_unload(xfer);
#else
xfer->state = FWXF_INIT;
xfer->resp = 0;
xfer->retry = 0;
#endif
s = splimp();
STAILQ_INSERT_TAIL(&fwe->xferlist, xfer, link);
splx(s);
#if 1
/* XXX for queue full */
/* for queue full */
if (ifp->if_snd.ifq_head != NULL)
fwe_start(ifp);
#endif
}
static void
@ -469,7 +469,6 @@ fwe_start(struct ifnet *ifp)
struct fwe_softc *fwe = ((struct fwe_eth_softc *)ifp->if_softc)->fwe;
int s;
#if 1
FWEDEBUG("%s%d starting\n", ifp->if_name, ifp->if_unit);
if (fwe->dma_ch < 0) {
@ -489,7 +488,6 @@ fwe_start(struct ifnet *ifp)
return;
}
#endif
s = splimp();
ifp->if_flags |= IFF_OACTIVE;
@ -537,7 +535,7 @@ fwe_as_output(struct fwe_softc *fwe, struct ifnet *ifp)
M_PREPEND(m, ETHER_ALIGN, M_DONTWAIT);
fp = (struct fw_pkt *)&xfer->dst; /* XXX */
xfer->dst = *((int32_t *)&fwe->pkt_hdr);
fp->mode.stream.len = htons(m->m_pkthdr.len);
fp->mode.stream.len = m->m_pkthdr.len;
xfer->send.buf = (caddr_t) fp;
xfer->mbuf = m;
xfer->send.len = m->m_pkthdr.len + HDR_LEN;
@ -560,44 +558,11 @@ fwe_as_output(struct fwe_softc *fwe, struct ifnet *ifp)
xferq->start(fwe->fd.fc);
}
#if 0
#if __FreeBSD_version >= 500000
static void
fwe_free(void *buf, void *args)
{
FWEDEBUG("fwe_free:\n");
free(buf, M_FW);
}
#else
static void
fwe_free(caddr_t buf, u_int size)
{
int *p;
FWEDEBUG("fwe_free:\n");
p = (int *)buf;
(*p) --;
if (*p < 1)
free(buf, M_FW);
}
static void
fwe_ref(caddr_t buf, u_int size)
{
int *p;
FWEDEBUG("fwe_ref: called\n");
p = (int *)buf;
(*p) ++;
}
#endif
#endif
/* Async. stream output */
static void
fwe_as_input(struct fw_xferq *xferq)
{
struct mbuf *m;
struct mbuf *m, *m0;
struct ifnet *ifp;
struct fwe_softc *fwe;
struct fw_bulkxfer *sxfer;
@ -614,21 +579,21 @@ fwe_as_input(struct fw_xferq *xferq)
#endif
while ((sxfer = STAILQ_FIRST(&xferq->stvalid)) != NULL) {
STAILQ_REMOVE_HEAD(&xferq->stvalid, link);
#if 0
xferq->queued --;
#endif
if (sxfer->resp != 0)
ifp->if_ierrors ++;
fp = (struct fw_pkt *)sxfer->buf;
fp = mtod(sxfer->mbuf, struct fw_pkt *);
/* XXX */
if (fwe->fd.fc->irx_post != NULL)
fwe->fd.fc->irx_post(fwe->fd.fc, fp->mode.ld);
m = sxfer->mbuf;
/* insert rbuf */
sxfer->mbuf = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
sxfer->buf = mtod(sxfer->mbuf, char *);
STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link);
sxfer->mbuf = m0 = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
if (m0 != NULL) {
m0->m_len = m0->m_pkthdr.len = m0->m_ext.ext_size;
STAILQ_INSERT_TAIL(&xferq->stfree, sxfer, link);
} else
printf("fwe_as_input: m_getcl failed\n");
m->m_data += HDR_LEN + ETHER_ALIGN;
c = mtod(m, char *);
@ -637,7 +602,7 @@ fwe_as_input(struct fw_xferq *xferq)
m->m_data += sizeof(struct ether_header);
#endif
m->m_len = m->m_pkthdr.len =
ntohs(fp->mode.stream.len) - ETHER_ALIGN;
fp->mode.stream.len - ETHER_ALIGN;
m->m_pkthdr.rcvif = ifp;
#if 0
FWEDEBUG("%02x %02x %02x %02x %02x %02x\n"

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2002
* Copyright (c) 2002-2003
* Hidetoshi Shimokawa. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,4 @@
# $FreeBSD$
#CFLAGS+=-g
.include "../Makefile.inc"

View File

@ -9,7 +9,7 @@ SRCS = bus_if.h device_if.h pci_if.h \
firewire.c firewire.h firewire_phy.h firewirereg.h \
fwohci.c fwohci_pci.c fwohcireg.h fwohcivar.h \
iec13213.h iec68113.h \
fwcrom.c fwdev.c fwmem.c fwmem.h
fwcrom.c fwdev.c fwmem.c fwmem.h fwdma.c fwdma.h
.include <bsd.kmod.mk>

View File

@ -9,6 +9,7 @@ SRCS = bus_if.h device_if.h \
opt_inet.h \
if_fwe.c if_fwevar.h \
firewire.h firewirereg.h
#CFLAGS += -DDEVICE_POLLING
.include <bsd.kmod.mk>

View File

@ -127,8 +127,8 @@ read_write_quad(int fd, struct fw_eui64 eui, u_int32_t addr_lo, int read, u_int3
else
asyreq->pkt.mode.rreqq.tcode = FWTCODE_WREQQ;
asyreq->pkt.mode.rreqq.dest_hi = htons(0xffff);
asyreq->pkt.mode.rreqq.dest_lo = htonl(addr_lo);
asyreq->pkt.mode.rreqq.dest_hi = 0xffff;
asyreq->pkt.mode.rreqq.dest_lo = addr_lo;
qld = (u_int32_t *)&asyreq->pkt;
if (!read)
@ -157,9 +157,9 @@ send_phy_config(int fd, int root_node, int gap_count)
asyreq->pkt.mode.ld[1] = 0;
asyreq->pkt.mode.common.tcode = FWTCODE_PHY;
if (root_node >= 0)
asyreq->pkt.mode.ld[1] |= htonl((root_node & 0x3f) << 24 | 1 << 23);
asyreq->pkt.mode.ld[1] |= (root_node & 0x3f) << 24 | 1 << 23;
if (gap_count >= 0)
asyreq->pkt.mode.ld[1] |= htonl(1 << 22 | (gap_count & 0x3f) << 16);
asyreq->pkt.mode.ld[1] |= 1 << 22 | (gap_count & 0x3f) << 16;
asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1];
printf("send phy_config root_node=%d gap_count=%d\n",
@ -251,8 +251,9 @@ show_crom(u_int32_t *crom_buf)
struct csrreg *reg;
struct csrdirectory *dir;
struct csrhdr *hdr;
u_int16_t crc;
printf("first quad: 0x%08x\n", *crom_buf);
printf("first quad: 0x%08x ", *crom_buf);
hdr = (struct csrhdr *)crom_buf;
if (hdr->info_len == 1) {
/* minimum ROM */
@ -261,13 +262,24 @@ show_crom(u_int32_t *crom_buf)
printf("verndor ID: 0x%06x\n", reg->val);
return;
}
printf("len: %d\n", hdr->crc_len);
printf("info_len=%d crc_len=%d crc=0x%04x",
hdr->info_len, hdr->crc_len, hdr->crc);
crc = crom_crc(crom_buf+1, hdr->crc_len);
if (crc == hdr->crc)
printf("(OK)\n");
else
printf("(NG)\n");
parse_bus_info_block(crom_buf+1, hdr->info_len);
crom_init_context(&cc, crom_buf);
dir = cc.stack[0].dir;
printf("root_directory: len=0x%04x(%d) crc=0x%04x\n",
printf("root_directory: len=0x%04x(%d) crc=0x%04x",
dir->crc_len, dir->crc_len, dir->crc);
crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len);
if (crc == dir->crc)
printf("(OK)\n");
else
printf("(NG)\n");
if (dir->crc_len < 1)
return;
while (cc.depth >= 0) {

View File

@ -35,8 +35,9 @@
*/
#include <sys/param.h>
#include <dev/firewire/firewire.h>
#include <dev/firewire/iec13213.h>
#if defined(_KERNEL) || defined(TEST)
#include <sys/queue.h>
#endif
#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/kernel.h>
@ -48,6 +49,8 @@
#include <stdlib.h>
#include <string.h>
#endif
#include <dev/firewire/firewire.h>
#include <dev/firewire/iec13213.h>
void
crom_init_context(struct crom_context *cc, u_int32_t *p)
@ -179,20 +182,28 @@ crom_desc(struct crom_context *cc, char *buf, int len)
struct csrreg *reg;
struct csrdirectory *dir;
char *desc;
u_int16_t crc;
reg = crom_get(cc);
switch (reg->key & CSRTYPE_MASK) {
case CSRTYPE_I:
snprintf(buf, len, "%d", reg->val);
break;
case CSRTYPE_L:
case CSRTYPE_C:
snprintf(buf, len, "offset=0x%04x(%d)", reg->val, reg->val);
break;
case CSRTYPE_L:
/* XXX fall through */
case CSRTYPE_D:
dir = (struct csrdirectory *) (reg + reg->val);
snprintf(buf, len, "len=0x%04x(%d) crc=0x%04x",
dir->crc_len, dir->crc_len, dir->crc);
crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len);
len -= snprintf(buf, len, "len=%d crc=0x%04x",
dir->crc_len, dir->crc);
if (crc == dir->crc)
strncat(buf, "(OK) ", len);
else
strncat(buf, "(NG) ", len);
len -= 5;
}
switch (reg->key) {
case 0x03:
@ -239,7 +250,7 @@ crom_desc(struct crom_context *cc, char *buf, int len)
break;
case 0x81:
desc = "text_leaf";
crom_parse_text(cc, buf, len);
crom_parse_text(cc, buf + strlen(buf), len);
break;
case 0xd1:
desc = "unit_directory";
@ -253,3 +264,239 @@ crom_desc(struct crom_context *cc, char *buf, int len)
return desc;
}
#endif
#if defined(_KERNEL) || defined(TEST)
int
crom_add_quad(struct crom_chunk *chunk, u_int32_t entry)
{
int index;
index = chunk->data.crc_len;
if (index >= CROM_MAX_CHUNK_LEN - 1) {
printf("too large chunk %d\n", index);
return(-1);
}
chunk->data.buf[index] = entry;
chunk->data.crc_len++;
return(index);
}
int
crom_add_entry(struct crom_chunk *chunk, int key, int val)
{
struct csrreg *reg;
u_int32_t i;
reg = (struct csrreg *)&i;
reg->key = key;
reg->val = val;
return(crom_add_quad(chunk, (u_int32_t) i));
}
int
crom_add_chunk(struct crom_src *src, struct crom_chunk *parent,
struct crom_chunk *child, int key)
{
int index;
if (parent == NULL) {
STAILQ_INSERT_TAIL(&src->chunk_list, child, link);
return(0);
}
index = crom_add_entry(parent, key, 0);
if (index < 0) {
return(-1);
}
child->ref_chunk = parent;
child->ref_index = index;
STAILQ_INSERT_TAIL(&src->chunk_list, child, link);
return(index);
}
int
crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent,
struct crom_chunk *chunk, char *buf)
{
struct csrtext *tl;
u_int32_t *p;
int len, i;
len = strlen(buf);
#define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext))
if (len > MAX_TEXT) {
printf("text(%d) trancated to %d.\n", len, MAX_TEXT);
len = MAX_TEXT;
}
tl = (struct csrtext *) &chunk->data;
tl->crc_len = roundup2(sizeof(struct csrtext) + len, 4) / 4;
tl->spec_id = 0;
tl->spec_type = 0;
tl->lang_id = 0;
p = (u_int32_t *) buf;
for (i = 0; i < roundup2(len, 4) / 4; i ++)
tl->text[i] = ntohl(*p++);
return (crom_add_chunk(src, parent, chunk, CROM_TEXTLEAF));
}
static int
crom_copy(u_int32_t *src, u_int32_t *dst, int *offset, int len, int maxlen)
{
if (*offset + len > maxlen) {
printf("Config. ROM is too large for the buffer\n");
return(-1);
}
bcopy(src, (char *)(dst + *offset), len * sizeof(u_int32_t));
*offset += len;
return(0);
}
int
crom_load(struct crom_src *src, u_int32_t *buf, int maxlen)
{
struct crom_chunk *chunk, *parent;
struct csrhdr *hdr;
#if 0
u_int32_t *ptr;
#endif
int count, offset;
int len;
offset = 0;
/* Determine offset */
STAILQ_FOREACH(chunk, &src->chunk_list, link) {
chunk->offset = offset;
/* Assume the offset of the parent is already known */
parent = chunk->ref_chunk;
if (parent != NULL) {
struct csrreg *reg;
reg = (struct csrreg *)
&parent->data.buf[chunk->ref_index];
reg->val = offset -
(parent->offset + 1 + chunk->ref_index);
}
offset += 1 + chunk->data.crc_len;
}
/* Calculate CRC and dump to the buffer */
len = 1 + src->hdr.info_len;
count = 0;
if (crom_copy((u_int32_t *)&src->hdr, buf, &count, len, maxlen) < 0)
return(-1);
STAILQ_FOREACH(chunk, &src->chunk_list, link) {
chunk->data.crc =
crom_crc(&chunk->data.buf[0], chunk->data.crc_len);
len = 1 + chunk->data.crc_len;
if (crom_copy((u_int32_t *)&chunk->data, buf,
&count, len, maxlen) < 0)
return(-1);
}
hdr = (struct csrhdr *)buf;
hdr->crc_len = count - 1;
hdr->crc = crom_crc(buf + 1, hdr->crc_len);
#if 0
/* byte swap */
ptr = buf;
for (i = 0; i < count; i ++) {
*ptr = htonl(*ptr);
ptr++;
}
#endif
return(count);
}
#endif
#ifdef TEST
int
main () {
struct crom_src src;
struct crom_chunk root,unit1,unit2,unit3;
struct crom_chunk text1,text2,text3,text4,text5,text6,text7;
u_int32_t buf[256], *p;
int i;
bzero(&src, sizeof(src));
bzero(&root, sizeof(root));
bzero(&unit1, sizeof(unit1));
bzero(&unit2, sizeof(unit2));
bzero(&unit3, sizeof(unit3));
bzero(&text1, sizeof(text1));
bzero(&text2, sizeof(text2));
bzero(&text3, sizeof(text3));
bzero(&text3, sizeof(text4));
bzero(&text3, sizeof(text5));
bzero(&text3, sizeof(text6));
bzero(&text3, sizeof(text7));
bzero(buf, sizeof(buf));
/* BUS info sample */
src.hdr.info_len = 4;
src.businfo.bus_name = CSR_BUS_NAME_IEEE1394;
src.businfo.eui64.hi = 0x11223344;
src.businfo.eui64.lo = 0x55667788;
src.businfo.link_spd = FWSPD_S400;
src.businfo.generation = 0;
src.businfo.max_rom = MAXROM_4;
src.businfo.max_rec = 10;
src.businfo.cyc_clk_acc = 100;
src.businfo.pmc = 0;
src.businfo.bmc = 1;
src.businfo.isc = 1;
src.businfo.cmc = 1;
src.businfo.irmc = 1;
STAILQ_INIT(&src.chunk_list);
/* Root directory */
crom_add_chunk(&src, NULL, &root, 0);
crom_add_entry(&root, CSRKEY_NCAP, 0x123456);
/* private company_id */
crom_add_entry(&root, CSRKEY_VENDOR, 0xacde48);
crom_add_simple_text(&src, &root, &text1, "FreeBSD");
crom_add_entry(&root, CSRKEY_HW, __FreeBSD_version);
crom_add_simple_text(&src, &root, &text2, "FreeBSD-5");
/* SBP unit directory */
crom_add_chunk(&src, &root, &unit1, CROM_UDIR);
crom_add_entry(&unit1, CSRKEY_SPEC, CSRVAL_ANSIT10);
crom_add_entry(&unit1, CSRKEY_VER, CSRVAL_T10SBP2);
crom_add_entry(&unit1, CSRKEY_COM_SPEC, CSRVAL_ANSIT10);
crom_add_entry(&unit1, CSRKEY_COM_SET, CSRVAL_SCSI);
/* management_agent */
crom_add_entry(&unit1, CROM_MGM, 0x1000);
crom_add_entry(&unit1, CSRKEY_UNIT_CH, (10<<8) | 8);
/* Device type and LUN */
crom_add_entry(&unit1, CROM_LUN, 0);
crom_add_entry(&unit1, CSRKEY_MODEL, 1);
crom_add_simple_text(&src, &unit1, &text3, "scsi_target");
/* RFC2734 IPv4 over IEEE1394 */
crom_add_chunk(&src, &root, &unit2, CROM_UDIR);
crom_add_entry(&unit2, CSRKEY_SPEC, CSRVAL_IETF);
crom_add_simple_text(&src, &unit2, &text4, "IANA");
crom_add_entry(&unit2, CSRKEY_VER, 1);
crom_add_simple_text(&src, &unit2, &text5, "IPv4");
/* RFC3146 IPv6 over IEEE1394 */
crom_add_chunk(&src, &root, &unit3, CROM_UDIR);
crom_add_entry(&unit3, CSRKEY_SPEC, CSRVAL_IETF);
crom_add_simple_text(&src, &unit3, &text6, "IANA");
crom_add_entry(&unit3, CSRKEY_VER, 2);
crom_add_simple_text(&src, &unit3, &text7, "IPv6");
crom_load(&src, buf, 256);
p = buf;
#define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n"
for (i = 0; i < 256/8; i ++) {
printf(DUMP_FORMAT,
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
p += 8;
}
return(0);
}
#endif

View File

@ -173,7 +173,7 @@ dvrecv(int d, char *filename, char ich, int count)
fprintf(stderr, "0x%04x\n", ntohs(ciph->fdf.dv.cyc));
}
#endif
if (ntohs(pkt->mode.stream.len) <= sizeof(struct ciphdr))
if (pkt->mode.stream.len <= sizeof(struct ciphdr))
/* no payload */
goto next;
for (dv = (struct dvdbc *)ptr;
@ -281,13 +281,13 @@ dvsend(int d, char *filename, char ich, int count)
iso_data = 0;
pkt = (struct fw_pkt *) &iso_data;
pkt->mode.stream.len = htons(DSIZE + sizeof(struct ciphdr));
pkt->mode.stream.len = DSIZE + sizeof(struct ciphdr);
pkt->mode.stream.sy = 0;
pkt->mode.stream.tcode = FWTCODE_STREAM;
pkt->mode.stream.chtag = ich;
iso_empty = iso_data;
pkt = (struct fw_pkt *) &iso_empty;
pkt->mode.stream.len = htons(sizeof(struct ciphdr));
pkt->mode.stream.len = sizeof(struct ciphdr);
bzero(hdr[0], sizeof(hdr[0]));
hdr[0][0] = iso_data;