firewire.c revision 106810
1155228Smjacob/*
2321870Smav * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
3196008Smjacob * All rights reserved.
4167403Smjacob *
5196008Smjacob * Redistribution and use in source and binary forms, with or without
6167403Smjacob * modification, are permitted provided that the following conditions
7167403Smjacob * are met:
8167403Smjacob * 1. Redistributions of source code must retain the above copyright
9196008Smjacob *    notice, this list of conditions and the following disclaimer.
10167403Smjacob * 2. Redistributions in binary form must reproduce the above copyright
11167403Smjacob *    notice, this list of conditions and the following disclaimer in the
12167403Smjacob *    documentation and/or other materials provided with the distribution.
13167403Smjacob * 3. All advertising materials mentioning features or use of this software
14167403Smjacob *    must display the acknowledgement as bellow:
15196008Smjacob *
16167403Smjacob *    This product includes software developed by K. Kobayashi and H. Shimokawa
17167403Smjacob *
18167403Smjacob * 4. The name of the author may not be used to endorse or promote products
19167403Smjacob *    derived from this software without specific prior written permission.
20167403Smjacob *
21167403Smjacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22167403Smjacob * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23167403Smjacob * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24167403Smjacob * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25167403Smjacob * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26167403Smjacob * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27196008Smjacob * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28155228Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29160410Smjacob * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30160410Smjacob * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31160410Smjacob * POSSIBILITY OF SUCH DAMAGE.
32155704Smjacob *
33167403Smjacob * $FreeBSD: head/sys/dev/firewire/firewire.c 106810 2002-11-12 13:49:17Z simokawa $
34167403Smjacob *
35155704Smjacob */
36155704Smjacob
37155704Smjacob#include <sys/param.h>
38160410Smjacob#include <sys/systm.h>
39160410Smjacob#include <sys/types.h>
40155228Smjacob#include <sys/mbuf.h>
41155704Smjacob#include <sys/socket.h>
42155704Smjacob#include <sys/socketvar.h>
43155704Smjacob
44155704Smjacob#include <sys/kernel.h>
45155704Smjacob#include <sys/malloc.h>
46155704Smjacob#include <sys/conf.h>
47155704Smjacob#include <sys/uio.h>
48155704Smjacob#include <sys/sysctl.h>
49155704Smjacob#include <sys/poll.h>
50155704Smjacob
51155228Smjacob#include <machine/cpufunc.h>    /* for rdtsc proto for clock.h below */
52196008Smjacob#include <machine/clock.h>
53196008Smjacob#include <pci/pcivar.h>
54196008Smjacob#include <pci/pcireg.h>
55196008Smjacob
56196008Smjacob#include <vm/vm.h>
57196008Smjacob#include <vm/pmap.h>            /* for vtophys proto */
58196008Smjacob#include <vm/vm_extern.h>
59196008Smjacob
60196008Smjacob#include <sys/bus.h>		/* used by smbus and newbus */
61155228Smjacob
62238869Smjacob#include <machine/bus.h>	/* used by newbus */
63196008Smjacob#include <sys/rman.h>		/* used by newbus */
64196008Smjacob#include <machine/resource.h>	/* used by newbus */
65317360Smav
66317360Smav#include <sys/signal.h>
67196008Smjacob#include <sys/mman.h>
68196008Smjacob#include <sys/ioccom.h>
69196008Smjacob
70196008Smjacob#include <dev/firewire/firewire.h>
71196008Smjacob#include <dev/firewire/firewirereg.h>
72196008Smjacob#include <dev/firewire/fwmem.h>
73196008Smjacob#include <dev/firewire/iec13213.h>
74196008Smjacob#include <dev/firewire/iec68113.h>
75196008Smjacob
76196008Smjacobint firewire_debug=0;
77196008SmjacobSYSCTL_NODE(_hw, OID_AUTO, firewire, CTLFLAG_RD, 0, "Firewire Subsystem");
78196008SmjacobSYSCTL_INT(_debug, OID_AUTO, firewire_debug, CTLFLAG_RW, &firewire_debug, 0,
79196008Smjacob	"Firewire driver debug flag");
80196008Smjacob
81196008Smjacob#define CDEV_MAJOR 127
82196008Smjacob#define FW_MAXASYRTY 4
83196008Smjacob#define FW_MAXDEVRCNT 4
84196008Smjacob#define	FWNODE_INVAL 0xffff
85196008Smjacob
86196008Smjacob#define XFER_TIMEOUT 0
87196008Smjacob
88196008Smjacobstatic	d_open_t	fw_open;
89196008Smjacobstatic	d_close_t	fw_close;
90196008Smjacobstatic	d_ioctl_t	fw_ioctl;
91196008Smjacobstatic	d_poll_t	fw_poll;
92317360Smavstatic	d_read_t	fw_read;	/* for Isochronous packet */
93317360Smavstatic	d_write_t	fw_write;
94317360Smavstatic	d_mmap_t	fw_mmap;
95317360Smav
96317360Smavdevclass_t firewire_devclass;
97317360Smav
98317360Smav
99317360Smavstatic int firewire_match      __P((device_t));
100317360Smavstatic int firewire_attach      __P((device_t));
101317360Smavstatic int firewire_detach      __P((device_t));
102317360Smav#if 0
103317360Smavstatic int firewire_shutdown    __P((device_t));
104196008Smjacob#endif
105317360Smavstatic device_t firewire_add_child   __P((device_t, int, const char *, int));
106317360Smavstatic struct fw_bind *fw_bindlookup __P((struct firewire_comm *, u_int32_t, u_int32_t));
107196008Smjacobstatic void fw_try_bmr __P((void *));
108196008Smjacobstatic void fw_try_bmr_callback __P((struct fw_xfer *));
109196008Smjacobstatic void fw_asystart __P((struct fw_xfer *));
110196008Smjacobstatic int fw_get_tlabel __P((struct firewire_comm *, struct fw_xfer *));
111196008Smjacobstatic void fw_bus_probe __P((struct firewire_comm *));
112196008Smjacobstatic void fw_bus_explore __P((struct firewire_comm *));
113196008Smjacobstatic void fw_bus_explore_callback __P((struct fw_xfer *));
114196008Smjacobstatic void fw_attach_dev __P((struct firewire_comm *));
115196008Smjacob#ifdef FW_VMACCESS
116196008Smjacobstatic void fw_vmaccess __P((struct fw_xfer *));
117196008Smjacob#endif
118196008Smjacobstruct fw_xfer *asyreqq __P((struct firewire_comm *, u_int8_t, u_int8_t, u_int8_t,
119196008Smjacob	u_int32_t, u_int32_t, void (*)__P((struct fw_xfer *))));
120196008Smjacob
121196008Smjacobstatic device_method_t firewire_methods[] = {
122196008Smjacob	/* Device interface */
123196008Smjacob	DEVMETHOD(device_probe,		firewire_match),
124196008Smjacob	DEVMETHOD(device_attach,	firewire_attach),
125196008Smjacob	DEVMETHOD(device_detach,	firewire_detach),
126196008Smjacob	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
127196008Smjacob
128196008Smjacob	/* Bus interface */
129196008Smjacob	DEVMETHOD(bus_add_child,	firewire_add_child),
130196008Smjacob	DEVMETHOD(bus_print_child,	bus_generic_print_child),
131196008Smjacob
132196008Smjacob	{ 0, 0 }
133196008Smjacob};
134196008Smjacobchar linkspeed[7][0x10]={"S100","S200","S400","S800","S1600","S3200","Unknown"};
135196008Smjacobu_int maxrec[6]={512,1024,2048,4096,8192,0};
136196008Smjacob
137196008Smjacob#define MAX_GAPHOP  16
138317360Smavu_int gap_cnt[] = {1, 1, 4, 6, 9, 12, 14, 17,
139317360Smav			20, 23, 25, 28, 31, 33, 36, 39, 42};
140317360Smav/*
141317360Smav * The probe routine.
142317360Smav */
143317360Smavstruct cdevsw firewire_cdevsw =
144317360Smav{
145317360Smav	fw_open, fw_close, fw_read, fw_write, fw_ioctl,
146317360Smav	fw_poll, fw_mmap, nostrategy, "fw", CDEV_MAJOR, nodump, nopsize, D_MEM
147317360Smav};
148317360Smavstatic driver_t firewire_driver = {
149317360Smav	"firewire",
150317360Smav	firewire_methods,
151317360Smav	sizeof(struct firewire_softc),
152196008Smjacob};
153196008Smjacob
154196008Smjacobstatic int
155317360Smavfw_open (dev_t dev, int flags, int fmt, fw_proc *td)
156196008Smjacob{
157317360Smav	struct firewire_softc *sc;
158317360Smav	int unit = DEV2UNIT(dev);
159196008Smjacob	int sub = DEV2DMACH(dev);
160196008Smjacob
161196008Smjacob	int err = 0;
162196008Smjacob
163196008Smjacob	if (DEV_FWMEM(dev))
164196008Smjacob		return fwmem_open(dev, flags, fmt, td);
165196008Smjacob
166196008Smjacob	sc = devclass_get_softc(firewire_devclass, unit);
167196008Smjacob	if(sc->fc->ir[sub]->flag & FWXFERQ_OPEN){
168196008Smjacob		err = EBUSY;
169196008Smjacob		return err;
170196008Smjacob	}
171196008Smjacob	if(sc->fc->it[sub]->flag & FWXFERQ_OPEN){
172261515Smav		err = EBUSY;
173261515Smav		return err;
174261515Smav	}
175196008Smjacob	if(sc->fc->ir[sub]->flag & FWXFERQ_MODEMASK){
176196008Smjacob		err = EBUSY;
177196008Smjacob		return err;
178196008Smjacob	}
179196008Smjacob/* Default is per packet mode */
180196008Smjacob	sc->fc->ir[sub]->flag |= FWXFERQ_OPEN;
181196008Smjacob	sc->fc->it[sub]->flag |= FWXFERQ_OPEN;
182196008Smjacob	sc->fc->ir[sub]->flag |= FWXFERQ_PACKET;
183196008Smjacob	return err;
184196008Smjacob}
185196008Smjacobstatic int
186196008Smjacobfw_close (dev_t dev, int flags, int fmt, fw_proc *td)
187196008Smjacob{
188196008Smjacob	struct firewire_softc *sc;
189196008Smjacob	int unit = DEV2UNIT(dev);
190196008Smjacob	int sub = DEV2DMACH(dev);
191196008Smjacob	struct fw_xfer *xfer;
192317360Smav	struct fw_dvbuf *dvbuf;
193317360Smav	struct fw_bind *fwb;
194317360Smav	int err = 0;
195317360Smav
196196008Smjacob	if (DEV_FWMEM(dev))
197196008Smjacob		return fwmem_close(dev, flags, fmt, td);
198196008Smjacob
199196008Smjacob	sc = devclass_get_softc(firewire_devclass, unit);
200196008Smjacob	if(!(sc->fc->ir[sub]->flag & FWXFERQ_OPEN)){
201196008Smjacob		err = EINVAL;
202196008Smjacob		return err;
203196008Smjacob	}
204196008Smjacob	sc->fc->ir[sub]->flag &= ~FWXFERQ_OPEN;
205196008Smjacob	if(!(sc->fc->it[sub]->flag & FWXFERQ_OPEN)){
206196008Smjacob		err = EINVAL;
207196008Smjacob		return err;
208297817Smav	}
209297817Smav	sc->fc->it[sub]->flag &= ~FWXFERQ_OPEN;
210196008Smjacob
211196008Smjacob	if(sc->fc->ir[sub]->flag & FWXFERQ_RUNNING){
212196008Smjacob		sc->fc->irx_disable(sc->fc, sub);
213196008Smjacob	}
214196008Smjacob	if(sc->fc->it[sub]->flag & FWXFERQ_RUNNING){
215196008Smjacob		sc->fc->it[sub]->flag &= ~FWXFERQ_RUNNING;
216196008Smjacob		sc->fc->itx_disable(sc->fc, sub);
217196008Smjacob	}
218196008Smjacob	if(sc->fc->it[sub]->flag & FWXFERQ_DV){
219317360Smav		if((dvbuf = sc->fc->it[sub]->dvproc) != NULL){
220317360Smav			free(dvbuf->buf, M_DEVBUF);
221196008Smjacob			sc->fc->it[sub]->dvproc = NULL;
222196008Smjacob		}
223196008Smjacob		if((dvbuf = sc->fc->it[sub]->dvdma) != NULL){
224196008Smjacob			free(dvbuf->buf, M_DEVBUF);
225196008Smjacob			sc->fc->it[sub]->dvdma = NULL;
226196008Smjacob		}
227317360Smav		while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvvalid)) != NULL){
228317360Smav			STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvvalid, link);
229196008Smjacob			free(dvbuf->buf, M_DEVBUF);
230196008Smjacob		}
231196008Smjacob		while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvfree)) != NULL){
232196008Smjacob			STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvfree, link);
233196008Smjacob			free(dvbuf->buf, M_DEVBUF);
234196008Smjacob		}
235196008Smjacob		free(sc->fc->it[sub]->dvbuf, M_DEVBUF);
236196008Smjacob		sc->fc->it[sub]->dvbuf = NULL;
237196008Smjacob	}
238196008Smjacob	if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){
239196008Smjacob		free(sc->fc->ir[sub]->buf, M_DEVBUF);
240196008Smjacob		sc->fc->ir[sub]->buf = NULL;
241196008Smjacob		free(sc->fc->ir[sub]->bulkxfer, M_DEVBUF);
242196008Smjacob		sc->fc->ir[sub]->bulkxfer = NULL;
243196008Smjacob		sc->fc->ir[sub]->flag &= ~FWXFERQ_EXTBUF;
244196008Smjacob		sc->fc->ir[sub]->psize = FWPMAX_S400;
245196008Smjacob		sc->fc->ir[sub]->maxq = FWMAXQUEUE;
246196008Smjacob	}
247196008Smjacob	if(sc->fc->it[sub]->flag & FWXFERQ_EXTBUF){
248196008Smjacob		free(sc->fc->it[sub]->buf, M_DEVBUF);
249196008Smjacob		sc->fc->it[sub]->buf = NULL;
250196008Smjacob		free(sc->fc->it[sub]->bulkxfer, M_DEVBUF);
251196008Smjacob		sc->fc->it[sub]->bulkxfer = NULL;
252196008Smjacob		sc->fc->it[sub]->dvbuf = NULL;
253196008Smjacob		sc->fc->it[sub]->flag &= ~FWXFERQ_EXTBUF;
254196008Smjacob		sc->fc->it[sub]->psize = FWPMAX_S400;
255317360Smav		sc->fc->it[sub]->maxq = FWMAXQUEUE;
256196008Smjacob	}
257196008Smjacob	for(xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q);
258196008Smjacob		xfer != NULL; xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q)){
259196008Smjacob		sc->fc->ir[sub]->queued--;
260317360Smav		STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->q, link);
261317360Smav
262317360Smav		xfer->resp = 0;
263317360Smav		switch(xfer->act_type){
264317360Smav		case FWACT_XFER:
265317360Smav			fw_xfer_done(xfer);
266317360Smav			break;
267317360Smav		default:
268317360Smav			break;
269317360Smav		}
270317360Smav		fw_xfer_free(xfer);
271317360Smav	}
272317360Smav	for(fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds); fwb != NULL;
273317360Smav		fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds)){
274317360Smav		STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
275317360Smav		STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->binds, chlist);
276317360Smav		free(fwb, M_DEVBUF);
277317360Smav	}
278317360Smav	sc->fc->ir[sub]->flag &= ~FWXFERQ_MODEMASK;
279317360Smav	sc->fc->it[sub]->flag &= ~FWXFERQ_MODEMASK;
280317360Smav	return err;
281317360Smav}
282317360Smav/*
283196008Smjacob * read request.
284196008Smjacob */
285196008Smjacobstatic int
286196008Smjacobfw_read (dev_t dev, struct uio *uio, int ioflag)
287297817Smav{
288196008Smjacob	struct firewire_softc *sc;
289196008Smjacob	struct fw_xferq *ir;
290196008Smjacob	struct fw_xfer *xfer;
291196008Smjacob	int err = 0, s, slept = 0;
292196008Smjacob	int unit = DEV2UNIT(dev);
293292725Smav	int sub = DEV2DMACH(dev);
294292725Smav	struct fw_pkt *fp;
295155228Smjacob
296203444Smjacob	if (DEV_FWMEM(dev))
297155228Smjacob		return fwmem_read(dev, uio, ioflag);
298203444Smjacob
299292725Smav	sc = devclass_get_softc(firewire_devclass, unit);
300292725Smav
301203444Smjacob	ir = sc->fc->ir[sub];
302203444Smjacob
303203444Smjacob	if(ir->flag & FWXFERQ_PACKET){
304292725Smav		ir->stproc = NULL;
305203444Smjacob	}
306292725Smavreadloop:
307155228Smjacob	xfer = STAILQ_FIRST(&ir->q);
308155228Smjacob	if(!(ir->flag & FWXFERQ_PACKET) && ir->stproc == NULL){
309292725Smav		ir->stproc = STAILQ_FIRST(&ir->stvalid);
310163899Smjacob		if(ir->stproc != NULL){
311155228Smjacob			s = splfw();
312292725Smav			STAILQ_REMOVE_HEAD(&ir->stvalid, link);
313203444Smjacob			splx(s);
314155228Smjacob			ir->queued = 0;
315155228Smjacob		}
316203444Smjacob	}
317155228Smjacob
318155228Smjacob	if(xfer == NULL && ir->stproc == NULL){
319163899Smjacob		if(slept == 0){
320292725Smav			slept = 1;
321155228Smjacob			if(!(ir->flag & FWXFERQ_RUNNING)
322203444Smjacob				&& (ir->flag & FWXFERQ_PACKET)){
323203444Smjacob				err = sc->fc->irx_enable(sc->fc, sub);
324155228Smjacob			}
325155228Smjacob			if(err){
326203444Smjacob				return err;
327203444Smjacob			}
328155228Smjacob			ir->flag |= FWXFERQ_WAKEUP;
329203444Smjacob			err = tsleep((caddr_t)ir, FWPRI, "fw_read", hz);
330203444Smjacob			if(err){
331155228Smjacob				ir->flag &= ~FWXFERQ_WAKEUP;
332155228Smjacob				return err;
333203444Smjacob			}
334155228Smjacob			goto readloop;
335155228Smjacob		}else{
336155228Smjacob			err = EIO;
337163899Smjacob			return err;
338155228Smjacob		}
339292725Smav	}else if(xfer != NULL){
340203444Smjacob		s = splfw();
341203444Smjacob		ir->queued --;
342203444Smjacob		STAILQ_REMOVE_HEAD(&ir->q, link);
343203444Smjacob		splx(s);
344203444Smjacob		fp = (struct fw_pkt *)(xfer->recv.buf + xfer->recv.off);
345155228Smjacob		if(sc->fc->irx_post != NULL)
346155228Smjacob			sc->fc->irx_post(sc->fc, fp->mode.ld);
347155228Smjacob		err = uiomove(xfer->recv.buf + xfer->recv.off, xfer->recv.len, uio);
348196008Smjacob		fw_xfer_free( xfer);
349196008Smjacob	}else if(ir->stproc != NULL){
350196008Smjacob		fp = (struct fw_pkt *)(ir->stproc->buf + ir->queued * ir->psize);
351196008Smjacob		if(sc->fc->irx_post != NULL)
352196008Smjacob			sc->fc->irx_post(sc->fc, fp->mode.ld);
353196008Smjacob		if(ntohs(fp->mode.stream.len) == 0){
354196008Smjacob			err = EIO;
355196008Smjacob			return err;
356155228Smjacob		}
357257916Smav		err = uiomove((caddr_t)fp, ntohs(fp->mode.stream.len) + sizeof(u_int32_t), uio);
358257916Smav		fp->mode.stream.len = 0;
359257916Smav		ir->queued ++;
360257916Smav		if(ir->queued >= ir->bnpacket){
361257916Smav			s = splfw();
362257916Smav			ir->stproc->flag = 0;
363257916Smav			STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
364155228Smjacob			splx(s);
365196008Smjacob			ir->stproc = NULL;
366155228Smjacob		}
367155228Smjacob	}
368155228Smjacob#if 0
369155228Smjacob	if(STAILQ_FIRST(&ir->q) == NULL &&
370196008Smjacob		(ir->flag & FWXFERQ_RUNNING) && (ir->flag & FWXFERQ_PACKET)){
371155228Smjacob		err = sc->fc->irx_enable(sc->fc, sub);
372155228Smjacob	}
373155228Smjacob#endif
374155704Smjacob#if 0
375155228Smjacob	if(STAILQ_FIRST(&ir->stvalid) == NULL &&
376155228Smjacob		(ir->flag & FWXFERQ_RUNNING) && !(ir->flag & FWXFERQ_PACKET)){
377155228Smjacob		err = sc->fc->irx_enable(sc->fc, sub);
378155228Smjacob	}
379196008Smjacob#endif
380155228Smjacob	return err;
381196008Smjacob}
382155228Smjacobstatic int
383208997Smjacobfw_write (dev_t dev, struct uio *uio, int ioflag)
384155228Smjacob{
385155228Smjacob	int err = 0;
386155228Smjacob	struct firewire_softc *sc;
387155228Smjacob	int unit = DEV2UNIT(dev);
388167821Smjacob	int sub = DEV2DMACH(dev);
389155228Smjacob	int tl, s, slept = 0;
390155228Smjacob	struct fw_pkt *fp;
391155704Smjacob	struct fw_xfer *xfer;
392155228Smjacob	struct fw_xferq *xferq;
393155228Smjacob	struct firewire_comm *fc;
394155228Smjacob	struct fw_xferq *it;
395155228Smjacob
396155228Smjacob	if (DEV_FWMEM(dev))
397155228Smjacob		return fwmem_write(dev, uio, ioflag);
398155228Smjacob
399155228Smjacob	sc = devclass_get_softc(firewire_devclass, unit);
400155228Smjacob	fc = sc->fc;
401155228Smjacob	it = sc->fc->it[sub];
402196008Smjacob
403196008Smjacob	fp = (struct fw_pkt *)uio->uio_iov->iov_base;
404155228Smjacob	switch(fp->mode.common.tcode){
405196008Smjacob	case FWTCODE_RREQQ:
406155228Smjacob	case FWTCODE_RREQB:
407155228Smjacob	case FWTCODE_LREQ:
408155228Smjacob		err = EINVAL;
409155228Smjacob		return err;
410155228Smjacob	case FWTCODE_WREQQ:
411155228Smjacob	case FWTCODE_WREQB:
412155228Smjacob		xferq = fc->atq;
413155228Smjacob		break;
414155228Smjacob	case FWTCODE_STREAM:
415155228Smjacob		if(it->flag & FWXFERQ_PACKET){
416155228Smjacob			xferq = fc->atq;
417155228Smjacob		}else{
418155228Smjacob			xferq = NULL;
419155228Smjacob		}
420155228Smjacob		break;
421155228Smjacob	case FWTCODE_WRES:
422155228Smjacob	case FWTCODE_RRESQ:
423155228Smjacob	case FWTCODE_RRESB:
424155228Smjacob	case FWTCODE_LRES:
425196008Smjacob		xferq = fc->ats;
426155228Smjacob		break;
427291365Smav	default:
428291365Smav		err = EINVAL;
429155228Smjacob		return err;
430291365Smav	}
431291365Smav	/* Discard unsent buffered stream packet, when sending Asyrequrst */
432290993Smav	if(xferq != NULL && it->stproc != NULL){
433291365Smav		s = splfw();
434291365Smav		it->stproc->flag = 0;
435291365Smav		STAILQ_INSERT_TAIL(&it->stfree, it->stproc, link);
436291365Smav		splx(s);
437291365Smav		it->stproc = NULL;
438291365Smav	}
439291365Smav	if(xferq == NULL && !(it->flag & FWXFERQ_DV)){
440291365Smavisoloop:
441291365Smav		if(it->stproc == NULL){
442291365Smav			it->stproc = STAILQ_FIRST(&it->stfree);
443291365Smav			if(it->stproc != NULL){
444291365Smav				s = splfw();
445291365Smav				STAILQ_REMOVE_HEAD(&it->stfree, link);
446291365Smav				splx(s);
447291365Smav				it->queued = 0;
448291365Smav			}else if(slept == 0){
449291365Smav				slept = 1;
450291365Smav				err = sc->fc->itx_enable(sc->fc, sub);
451291365Smav				if(err){
452155228Smjacob					return err;
453155228Smjacob				}
454164272Smjacob				err = tsleep((caddr_t)it, FWPRI, "fw_write", hz);
455196008Smjacob				if(err){
456164272Smjacob					return err;
457163899Smjacob				}
458196008Smjacob				goto isoloop;
459164272Smjacob			}else{
460196008Smjacob				err = EIO;
461164272Smjacob				return err;
462164272Smjacob			}
463164272Smjacob		}
464285459Smav		fp = (struct fw_pkt *)(it->stproc->buf + it->queued * it->psize);
465164272Smjacob		fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t));
466164272Smjacob		err = uiomove(it->stproc->buf + it->queued * it->psize,
467164272Smjacob							uio->uio_resid, uio);
468164272Smjacob		it->queued ++;
469164272Smjacob		if(it->queued >= it->btpacket){
470164272Smjacob			s = splfw();
471164272Smjacob			STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
472164272Smjacob			splx(s);
473164272Smjacob			it->stproc = NULL;
474164272Smjacob			fw_tbuf_update(sc->fc, sub, 0);
475164272Smjacob			err = sc->fc->itx_enable(sc->fc, sub);
476164272Smjacob		}
477285459Smav		return err;
478164272Smjacob	} if(xferq == NULL && it->flag & FWXFERQ_DV){
479164272Smjacobdvloop:
480238869Smjacob		if(it->dvproc == NULL){
481238869Smjacob			it->dvproc = STAILQ_FIRST(&it->dvfree);
482300052Smav			if(it->dvproc != NULL){
483300052Smav				s = splfw();
484196008Smjacob				STAILQ_REMOVE_HEAD(&it->dvfree, link);
485164272Smjacob				splx(s);
486164272Smjacob				it->dvptr = 0;
487164272Smjacob			}else if(slept == 0){
488238869Smjacob				slept = 1;
489238869Smjacob				err = sc->fc->itx_enable(sc->fc, sub);
490238869Smjacob				if(err){
491238869Smjacob					return err;
492238869Smjacob				}
493238869Smjacob				err = tsleep((caddr_t)it, FWPRI, "fw_write", hz);
494238869Smjacob				if(err){
495238869Smjacob					return err;
496238869Smjacob				}
497238869Smjacob				goto dvloop;
498238869Smjacob			}else{
499238869Smjacob				err = EIO;
500238869Smjacob				return err;
501238869Smjacob			}
502238869Smjacob		}
503238869Smjacob		fp = (struct fw_pkt *)(it->dvproc->buf + it->queued * it->psize);
504238869Smjacob		fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t));
505238869Smjacob		err = uiomove(it->dvproc->buf + it->dvptr,
506238869Smjacob							uio->uio_resid, uio);
507238869Smjacob		it->dvptr += it->psize;
508238869Smjacob		if(err){
509238869Smjacob			return err;
510238869Smjacob		}
511238869Smjacob		if(it->dvptr >= it->psize * it->dvpacket){
512238869Smjacob			s = splfw();
513238869Smjacob			STAILQ_INSERT_TAIL(&it->dvvalid, it->dvproc, link);
514238869Smjacob			splx(s);
515238869Smjacob			it->dvproc = NULL;
516238869Smjacob			err = fw_tbuf_update(sc->fc, sub, 0);
517238869Smjacob			if(err){
518238869Smjacob				return err;
519238869Smjacob			}
520238869Smjacob			err = sc->fc->itx_enable(sc->fc, sub);
521238869Smjacob		}
522238869Smjacob		return err;
523238869Smjacob	}
524238869Smjacob	if(xferq != NULL){
525238869Smjacob		xfer = fw_xfer_alloc();
526238869Smjacob		if(xfer == NULL){
527238869Smjacob			err = ENOMEM;
528238869Smjacob			return err;
529238869Smjacob		}
530238869Smjacob		xfer->send.buf = malloc(uio->uio_resid, M_DEVBUF, M_NOWAIT);
531238869Smjacob		if(xfer->send.buf == NULL){
532238869Smjacob			fw_xfer_free( xfer);
533238869Smjacob			err = ENOBUFS;
534238869Smjacob			return err;
535238869Smjacob		}
536238869Smjacob		xfer->dst = ntohs(fp->mode.hdr.dst);
537238869Smjacob
538238869Smjacob		switch(fp->mode.common.tcode){
539238869Smjacob		case FWTCODE_WREQQ:
540238869Smjacob		case FWTCODE_WREQB:
541238869Smjacob			if((tl = fw_get_tlabel(fc, xfer)) == -1 ){
542238869Smjacob				fw_xfer_free( xfer);
543238869Smjacob				err = EAGAIN;
544238869Smjacob				return err;
545238869Smjacob			}
546238869Smjacob			fp->mode.hdr.tlrt = tl << 2;
547238869Smjacob		default:
548238869Smjacob			break;
549238869Smjacob		}
550238869Smjacob
551238869Smjacob		xfer->tl = fp->mode.hdr.tlrt >> 2;
552238869Smjacob		xfer->send.len = uio->uio_resid;
553238869Smjacob		xfer->send.off = 0;
554238869Smjacob		xfer->tcode = fp->mode.common.tcode;
555196008Smjacob		xfer->spd = 0;/* XXX: how to setup it */
556196008Smjacob		xfer->fc = fc;
557196008Smjacob		xfer->q = xferq;
558196008Smjacob		xfer->act_type = FWACT_XFER;
559196008Smjacob		xfer->act.hand = fw_asy_callback;
560290993Smav		xfer->retry_req = fw_asybusy;
561196008Smjacob
562196008Smjacob		err = uiomove(xfer->send.buf, uio->uio_resid, uio);
563196008Smjacob		if(err){
564196008Smjacob			return err;
565196008Smjacob		}
566196008Smjacob		fw_asystart(xfer);
567196008Smjacob		err = tsleep((caddr_t)xfer, FWPRI, "fw_write", hz);
568196008Smjacob		if(xfer->resp == EBUSY)
569196008Smjacob			return EBUSY;
570196008Smjacob		fw_xfer_free( xfer);
571196008Smjacob		return err;
572196008Smjacob	}
573196008Smjacob	return EINVAL;
574196008Smjacob}
575196008Smjacob/*
576291365Smav * transmitter buffer update.
577297991Smav */
578290993Smavint
579290993Smavfw_tbuf_update(struct firewire_comm *fc, int sub, int flag){
580290993Smav	struct fw_bulkxfer *bulkxfer, *bulkxfer2 = NULL;
581196008Smjacob	struct fw_dvbuf *dvbuf = NULL;
582196008Smjacob	struct fw_xferq *it;
583196008Smjacob	int s, err = 0, i, j, chtag;
584196008Smjacob	struct fw_pkt *fp;
585196008Smjacob	u_int64_t tmpsync, dvsync;
586196008Smjacob
587196008Smjacob	it = fc->it[sub];
588196008Smjacob
589196008Smjacob	s = splfw();
590196008Smjacob	if(it->stdma == NULL){
591196008Smjacob		bulkxfer = STAILQ_FIRST(&it->stvalid);
592196008Smjacob	}else if(flag != 0){
593196008Smjacob		bulkxfer = STAILQ_FIRST(&it->stvalid);
594297991Smav		if(bulkxfer == it->stdma){
595196008Smjacob			STAILQ_REMOVE_HEAD(&it->stvalid, link);
596196008Smjacob			it->stdma->flag = 0;
597196008Smjacob			STAILQ_INSERT_TAIL(&it->stfree, it->stdma, link);
598291080Smav			if(!(it->flag & FWXFERQ_DV))
599291080Smav				wakeup(it);
600291080Smav		}
601291080Smav		bulkxfer = STAILQ_FIRST(&it->stvalid);
602291080Smav	}else{
603196008Smjacob		bulkxfer = it->stdma;
604196008Smjacob	}
605196008Smjacob	splx(s);
606196008Smjacob	if(bulkxfer != NULL){
607164272Smjacob		s = splfw();
608196008Smjacob		bulkxfer2 = STAILQ_NEXT(bulkxfer, link);
609196008Smjacob#if 0
610203444Smjacob		if(it->flag & FWXFERQ_DV && bulkxfer2 == NULL){
611203444Smjacob			bulkxfer2 = STAILQ_FIRST(&it->stfree);
612196008Smjacob			STAILQ_REMOVE_HEAD(&it->stfree, link);
613196008Smjacob			splx(s);
614196008Smjacob			bcopy(bulkxfer->buf, bulkxfer2->buf,
615196008Smjacob					it->psize * it->btpacket);
616196008Smjacob			s = splfw();
617203444Smjacob			STAILQ_INSERT_TAIL(&it->stvalid, bulkxfer2, link);
618203444Smjacob		}
619292739Smav#endif
620292739Smav		splx(s);
621292725Smav	}
622292725Smav	it->stdma = bulkxfer;
623292725Smav	it->stdma2 = bulkxfer2;
624292725Smav
625292725Smav	if(it->flag & FWXFERQ_DV){
626292725Smav		chtag = it->flag & 0xff;
627292725Smavdvloop:
628292739Smav		if(it->dvdma == NULL){
629292725Smav			dvbuf = STAILQ_FIRST(&it->dvvalid);
630292725Smav			if(dvbuf != NULL){
631292739Smav				s = splfw();
632292739Smav				STAILQ_REMOVE_HEAD(&it->dvvalid, link);
633292725Smav				it->dvdma = dvbuf;
634292739Smav				splx(s);
635292725Smav				it->queued = 0;
636292725Smav			}
637292725Smav		}
638292725Smav		if(it->dvdma == NULL)
639292725Smav			return err;
640292725Smav
641292725Smav		it->stproc = STAILQ_FIRST(&it->stfree);
642292725Smav		if(it->stproc != NULL){
643292725Smav			s = splfw();
644292725Smav			STAILQ_REMOVE_HEAD(&it->stfree, link);
645292725Smav			splx(s);
646292725Smav		}else{
647292725Smav			return err;
648292725Smav		}
649292725Smav/*
650292739Smav * Insert least significant 12 bits timestamp value by computation.
651292739Smav * Highest significant 4 bits is insert at just before packet sending.
652292725Smav */
653292739Smav		fp = (struct fw_pkt *)(it->stproc->buf);
654292739Smav/* XXX: Parameter relies on NTSC type DV video */
655292739Smav		tmpsync = (u_int64_t)3072 * 8000 * 100 / 2997;
656292739Smav		tmpsync *= it->dvsync;
657196008Smjacob		dvsync = tmpsync;
658196008Smjacob		dvsync %= 0xc00;
659196008Smjacob		fp->mode.ld[2] = htonl(0x80000000 | (dvsync % 0xc00));
660196008Smjacob		it->dvsync ++;
661196008Smjacob		it->dvsync %= 2997;
662196008Smjacob
663196008Smjacob		for( i = 0, j = 0 ; i < it->dvpacket ; i++){
664196008Smjacob			bcopy(it->dvdma->buf + it->queued * it->psize,
665196008Smjacob				it->stproc->buf + j * it->psize, it->psize);
666196008Smjacob			fp = (struct fw_pkt *)(it->stproc->buf + j * it->psize);
667196008Smjacob			fp->mode.stream.len = htons(488);
668196008Smjacob			fp->mode.stream.chtag = chtag;
669196008Smjacob			fp->mode.stream.tcode = FWTCODE_STREAM;
670196008Smjacob			fp->mode.ld[1] = htonl((fc->nodeid << 24) | 0x00780000 | it->dvdbc);
671196008Smjacob			it->dvdbc++;
672196008Smjacob			it->dvdbc %= 256;
673196008Smjacob			it->queued ++;
674196008Smjacob			j++;
675196008Smjacob/* XXX: Parameter relies on NTSC type DV video */
676196008Smjacob#if 1
677155228Smjacob#define DVDIFF 203
678155228Smjacob#define DVFRAC 2997
679155228Smjacob#else
680155228Smjacob#define DVDIFF 127
681155228Smjacob#define DVFRAC 1875
682155228Smjacob#endif
683155228Smjacob			it->dvdiff += DVDIFF;
684155228Smjacob			if(it->dvdiff >= DVFRAC){
685155228Smjacob				it->dvdiff %= DVFRAC;
686155228Smjacob				fp = (struct fw_pkt *)(it->stproc->buf + j * it->psize);
687155228Smjacob
688196008Smjacob				fp->mode.stream.len = htons(0x8);
689155228Smjacob				fp->mode.stream.chtag = chtag;
690163899Smjacob				fp->mode.stream.tcode = FWTCODE_STREAM;
691155228Smjacob				fp->mode.ld[1] = htonl((fc->nodeid << 24) |
692155228Smjacob					 0x00780000 | it->dvdbc);
693155228Smjacob				j++;
694155228Smjacob			}
695163899Smjacob		}
696155228Smjacob		it->stproc->npacket = j;
697155228Smjacob		s = splfw();
698196008Smjacob		STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
699196008Smjacob		splx(s);
700196008Smjacob		if(it->queued >= it->dvpacket){
701196008Smjacob			s = splfw();
702155228Smjacob			STAILQ_INSERT_TAIL(&it->dvfree, it->dvdma, link);
703196008Smjacob			it->dvdma = NULL;
704196008Smjacob			splx(s);
705196008Smjacob			wakeup(it);
706196008Smjacob			goto dvloop;
707155228Smjacob		}
708155228Smjacob	}
709155228Smjacob	return err;
710155228Smjacob}
711163899Smjacob/*
712155228Smjacob * receving buffer update.
713155228Smjacob */
714196008Smjacobint
715196008Smjacobfw_rbuf_update(struct firewire_comm *fc, int sub, int flag){
716196008Smjacob	struct fw_bulkxfer *bulkxfer, *bulkxfer2 = NULL;
717196008Smjacob	struct fw_xferq *ir;
718155228Smjacob	int s, err = 0;
719196008Smjacob
720196008Smjacob	ir = fc->ir[sub];
721196008Smjacob	s = splfw();
722196008Smjacob	if(ir->stdma != NULL){
723155228Smjacob		if(flag != 0){
724155228Smjacob			STAILQ_INSERT_TAIL(&ir->stvalid, ir->stdma, link);
725155228Smjacob		}else{
726155228Smjacob			ir->stdma->flag = 0;
727155704Smjacob			STAILQ_INSERT_TAIL(&ir->stfree, ir->stdma, link);
728155228Smjacob		}
729155704Smjacob	}
730155228Smjacob	if(ir->stdma2 != NULL){
731155228Smjacob		bulkxfer = ir->stdma2;
732155228Smjacob		bulkxfer2 = STAILQ_FIRST(&ir->stfree);
733155228Smjacob		if(bulkxfer2 != NULL){
734155228Smjacob			STAILQ_REMOVE_HEAD(&ir->stfree, link);
735155228Smjacob		}
736155228Smjacob	}else{
737155228Smjacob		bulkxfer = STAILQ_FIRST(&ir->stfree);
738155228Smjacob		if(bulkxfer != NULL){
739155704Smjacob			STAILQ_REMOVE_HEAD(&ir->stfree, link);
740155228Smjacob			bulkxfer2 = STAILQ_FIRST(&ir->stfree);
741155228Smjacob			if(bulkxfer2 != NULL){
742163899Smjacob				STAILQ_REMOVE_HEAD(&ir->stfree, link);
743155228Smjacob			}
744155228Smjacob		}else{
745155228Smjacob			bulkxfer = STAILQ_FIRST(&ir->stvalid);
746155228Smjacob			STAILQ_REMOVE_HEAD(&ir->stvalid, link);
747155228Smjacob		}
748155228Smjacob	}
749155228Smjacob	splx(s);
750155228Smjacob	ir->stdma = bulkxfer;
751155228Smjacob	ir->stdma2 = bulkxfer2;
752155228Smjacob	return err;
753155228Smjacob}
754155228Smjacob/*
755163899Smjacob * ioctl support.
756155228Smjacob */
757155228Smjacobint
758155228Smjacobfw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
759196008Smjacob{
760196008Smjacob	struct firewire_softc *sc;
761155228Smjacob	int unit = DEV2UNIT(dev);
762155228Smjacob	int sub = DEV2DMACH(dev);
763155228Smjacob	int i, len, err = 0;
764155228Smjacob	struct fw_device *fwdev;
765163899Smjacob	struct fw_bind *fwb;
766155228Smjacob	struct fw_xferq *ir, *it;
767155228Smjacob	struct fw_xfer *xfer;
768163899Smjacob	struct fw_pkt *fp;
769163899Smjacob
770163899Smjacob	struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data;
771163899Smjacob	struct fw_asyreq *asyreq = (struct fw_asyreq *)data;
772163899Smjacob	struct fw_isochreq *ichreq = (struct fw_isochreq *)data;
773163899Smjacob	struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data;
774163899Smjacob	struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data;
775163899Smjacob#if 0
776155228Smjacob	struct fw_map_buf *map_buf = (struct fw_map_buf *)data;
777163899Smjacob#endif
778163899Smjacob	struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data;
779163899Smjacob
780163899Smjacob	if (DEV_FWMEM(dev))
781196008Smjacob		return fwmem_ioctl(dev, cmd, data, flag, td);
782163899Smjacob
783163899Smjacob	sc = devclass_get_softc(firewire_devclass, unit);
784163899Smjacob	if (!data)
785163899Smjacob		return(EINVAL);
786196008Smjacob
787163899Smjacob	switch (cmd) {
788163899Smjacob	case FW_STSTREAM:
789163899Smjacob		sc->fc->it[sub]->flag &= ~0xff;
790163899Smjacob		sc->fc->it[sub]->flag |= (0x3f & ichreq->ch);
791163899Smjacob		sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6);
792163899Smjacob		err = 0;
793163899Smjacob		break;
794163899Smjacob	case FW_GTSTREAM:
795163899Smjacob		ichreq->ch = sc->fc->it[sub]->flag & 0x3f;
796163899Smjacob		ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3;
797163899Smjacob		err = 0;
798163899Smjacob		break;
799163899Smjacob	case FW_SRSTREAM:
800163899Smjacob		sc->fc->ir[sub]->flag &= ~0xff;
801196008Smjacob		sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch);
802163899Smjacob		sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6);
803163899Smjacob		err = sc->fc->irx_enable(sc->fc, sub);
804163899Smjacob		break;
805163899Smjacob	case FW_GRSTREAM:
806163899Smjacob		ichreq->ch = sc->fc->ir[sub]->flag & 0x3f;
807163899Smjacob		ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3;
808163899Smjacob		err = 0;
809163899Smjacob		break;
810163899Smjacob	case FW_SSTDV:
811163899Smjacob		ibufreq = (struct fw_isobufreq *)
812163899Smjacob			malloc(sizeof(struct fw_isobufreq), M_DEVBUF, M_NOWAIT);
813163899Smjacob		if(ibufreq == NULL){
814163899Smjacob			err = ENOMEM;
815291209Smav			break;
816291209Smav		}
817163899Smjacob#define FWDVPACKET 250
818163899Smjacob#define FWDVPMAX 512
819163899Smjacob		ibufreq->rx.nchunk = 8;
820163899Smjacob		ibufreq->rx.npacket = 50;
821163899Smjacob		ibufreq->rx.psize = FWDVPMAX;
822163899Smjacob
823155228Smjacob		ibufreq->tx.nchunk = 5;
824196008Smjacob		ibufreq->tx.npacket = 300;
825196008Smjacob		ibufreq->tx.psize = FWDVPMAX;
826155228Smjacob
827155228Smjacob		err = fw_ioctl(dev, FW_SSTBUF, (caddr_t)ibufreq, flag, td);
828155228Smjacob		sc->fc->it[sub]->dvpacket = FWDVPACKET;
829155228Smjacob		free(ibufreq, M_DEVBUF);
830163899Smjacob/* reserve a buffer space */
831155228Smjacob#define NDVCHUNK 8
832155228Smjacob		sc->fc->it[sub]->dvproc = NULL;
833163899Smjacob		sc->fc->it[sub]->dvdma = NULL;
834163899Smjacob		sc->fc->it[sub]->flag |= FWXFERQ_DV;
835163899Smjacob		sc->fc->it[sub]->dvbuf
836163899Smjacob			= (struct fw_dvbuf *)malloc(sizeof(struct fw_dvbuf) * NDVCHUNK, M_DEVBUF, M_DONTWAIT);
837163899Smjacob		STAILQ_INIT(&sc->fc->it[sub]->dvvalid);
838291209Smav		STAILQ_INIT(&sc->fc->it[sub]->dvfree);
839291209Smav		for( i = 0 ; i < NDVCHUNK ; i++){
840163899Smjacob			sc->fc->it[sub]->dvbuf[i].buf
841163899Smjacob				= malloc(FWDVPMAX * sc->fc->it[sub]->dvpacket, M_DEVBUF, M_DONTWAIT);
842163899Smjacob			STAILQ_INSERT_TAIL(&sc->fc->it[sub]->dvfree,
843163899Smjacob					&sc->fc->it[sub]->dvbuf[i], link);
844155228Smjacob		}
845163899Smjacob		break;
846155228Smjacob	case FW_SSTBUF:
847196008Smjacob		ir = sc->fc->ir[sub];
848196008Smjacob		it = sc->fc->it[sub];
849155228Smjacob
850155228Smjacob		if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){
851155228Smjacob			return(EBUSY);
852155228Smjacob		}
853163899Smjacob		if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){
854155228Smjacob			return(EBUSY);
855155228Smjacob		}
856163899Smjacob		if((ibufreq->rx.nchunk *
857163899Smjacob			ibufreq->rx.psize * ibufreq->rx.npacket) +
858163899Smjacob		   (ibufreq->tx.nchunk *
859163899Smjacob			ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){
860163899Smjacob				return(EINVAL);
861163899Smjacob		}
862238869Smjacob		if(ibufreq->rx.nchunk > FWSTMAXCHUNK ||
863238869Smjacob				ibufreq->tx.nchunk > FWSTMAXCHUNK){
864163899Smjacob			return(EINVAL);
865163899Smjacob		}
866163899Smjacob		ir->bulkxfer
867163899Smjacob			= (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_DEVBUF, M_DONTWAIT);
868155228Smjacob		if(ir->bulkxfer == NULL){
869163899Smjacob			return(ENOMEM);
870155228Smjacob		}
871196008Smjacob		it->bulkxfer
872196008Smjacob			= (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_DEVBUF, M_DONTWAIT);
873196008Smjacob		if(it->bulkxfer == NULL){
874155228Smjacob			return(ENOMEM);
875155228Smjacob		}
876155228Smjacob		ir->buf = malloc(
877155228Smjacob			ibufreq->rx.nchunk * ibufreq->rx.npacket
878163899Smjacob			* ((ibufreq->rx.psize + 3) &~3),
879155228Smjacob			M_DEVBUF, M_DONTWAIT);
880155228Smjacob		if(ir->buf == NULL){
881163899Smjacob			free(ir->bulkxfer, M_DEVBUF);
882163899Smjacob			free(it->bulkxfer, M_DEVBUF);
883163899Smjacob			ir->bulkxfer = NULL;
884163899Smjacob			it->bulkxfer = NULL;
885163899Smjacob			it->buf = NULL;
886238869Smjacob			return(ENOMEM);
887238869Smjacob		}
888163899Smjacob		it->buf = malloc(
889163899Smjacob			ibufreq->tx.nchunk * ibufreq->tx.npacket
890163899Smjacob			* ((ibufreq->tx.psize + 3) &~3),
891163899Smjacob			M_DEVBUF, M_DONTWAIT);
892155228Smjacob		if(it->buf == NULL){
893163899Smjacob			free(ir->bulkxfer, M_DEVBUF);
894155228Smjacob			free(it->bulkxfer, M_DEVBUF);
895196008Smjacob			free(ir->buf, M_DEVBUF);
896196008Smjacob			ir->bulkxfer = NULL;
897196008Smjacob			it->bulkxfer = NULL;
898155228Smjacob			it->buf = NULL;
899155228Smjacob			return(ENOMEM);
900155228Smjacob		}
901155228Smjacob
902163899Smjacob		ir->bnchunk = ibufreq->rx.nchunk;
903155228Smjacob		ir->bnpacket = ibufreq->rx.npacket;
904155228Smjacob		ir->btpacket = ibufreq->rx.npacket;
905163899Smjacob		ir->psize = (ibufreq->rx.psize + 3) & ~3;
906163899Smjacob		ir->queued = 0;
907155228Smjacob
908163899Smjacob		it->bnchunk = ibufreq->tx.nchunk;
909163899Smjacob		it->bnpacket = ibufreq->tx.npacket;
910155228Smjacob		it->btpacket = ibufreq->tx.npacket;
911163899Smjacob		it->psize = (ibufreq->tx.psize + 3) & ~3;
912163899Smjacob		ir->queued = 0;
913155228Smjacob		it->dvdbc = 0;
914163899Smjacob		it->dvdiff = 0;
915163899Smjacob		it->dvsync = 0;
916163899Smjacob
917163899Smjacob		STAILQ_INIT(&ir->stvalid);
918163899Smjacob		STAILQ_INIT(&ir->stfree);
919163899Smjacob		ir->stdma = NULL;
920155228Smjacob		ir->stdma2 = NULL;
921155228Smjacob		ir->stproc = NULL;
922155228Smjacob
923155228Smjacob		STAILQ_INIT(&it->stvalid);
924163899Smjacob		STAILQ_INIT(&it->stfree);
925155228Smjacob		it->stdma = NULL;
926155228Smjacob		it->stdma2 = NULL;
927163899Smjacob		it->stproc = NULL;
928163899Smjacob
929163899Smjacob		for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){
930163899Smjacob			ir->bulkxfer[i].buf =
931163899Smjacob				ir->buf +
932163899Smjacob				i * sc->fc->ir[sub]->bnpacket *
933163899Smjacob			  	sc->fc->ir[sub]->psize;
934163899Smjacob			ir->bulkxfer[i].flag = 0;
935163899Smjacob			STAILQ_INSERT_TAIL(&ir->stfree,
936163899Smjacob					&ir->bulkxfer[i], link);
937163899Smjacob			ir->bulkxfer[i].npacket = ir->bnpacket;
938171159Smjacob		}
939163899Smjacob		for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){
940163899Smjacob			it->bulkxfer[i].buf =
941163899Smjacob				it->buf +
942163899Smjacob				i * sc->fc->it[sub]->bnpacket *
943163899Smjacob			  	sc->fc->it[sub]->psize;
944163899Smjacob			it->bulkxfer[i].flag = 0;
945163899Smjacob			STAILQ_INSERT_TAIL(&it->stfree,
946171159Smjacob					&it->bulkxfer[i], link);
947171159Smjacob			it->bulkxfer[i].npacket = it->bnpacket;
948163899Smjacob		}
949163899Smjacob		ir->flag &= ~FWXFERQ_MODEMASK;
950163899Smjacob		ir->flag |= FWXFERQ_STREAM;
951163899Smjacob		ir->flag |= FWXFERQ_EXTBUF;
952163899Smjacob
953196008Smjacob		it->flag &= ~FWXFERQ_MODEMASK;
954196008Smjacob		it->flag |= FWXFERQ_STREAM;
955196008Smjacob		it->flag |= FWXFERQ_EXTBUF;
956163899Smjacob		err = 0;
957163899Smjacob		break;
958163899Smjacob	case FW_GSTBUF:
959196008Smjacob		ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk;
960196008Smjacob		ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket;
961196008Smjacob		ibufreq->rx.psize = sc->fc->ir[sub]->psize;
962196008Smjacob
963196008Smjacob		ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk;
964196008Smjacob		ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket;
965196008Smjacob		ibufreq->tx.psize = sc->fc->it[sub]->psize;
966196008Smjacob		break;
967196008Smjacob	case FW_ASYREQ:
968196008Smjacob		xfer = fw_xfer_alloc();
969196008Smjacob		if(xfer == NULL){
970196008Smjacob			err = ENOMEM;
971196008Smjacob			return err;
972196008Smjacob		}
973196008Smjacob		fp = &asyreq->pkt;
974196008Smjacob		switch (asyreq->req.type) {
975196008Smjacob		case FWASREQNODE:
976196008Smjacob			xfer->dst = ntohs(fp->mode.hdr.dst);
977196008Smjacob			break;
978196008Smjacob		case FWASREQEUI:
979196008Smjacob			fwdev = fw_noderesolve(sc->fc, asyreq->req.dst.eui);
980196008Smjacob			if (fwdev == NULL) {
981196008Smjacob				printf("%s:cannot found node\n",
982196008Smjacob					device_get_nameunit(sc->fc->dev));
983196008Smjacob				err = EINVAL;
984196008Smjacob				goto error;
985196008Smjacob			}
986196008Smjacob			xfer->dst = fwdev->dst;
987196008Smjacob			fp->mode.hdr.dst = htons(FWLOCALBUS | xfer->dst);
988196008Smjacob			break;
989196008Smjacob		case FWASRESTL:
990163899Smjacob			/* XXX what's this? */
991163899Smjacob			break;
992163899Smjacob		case FWASREQSTREAM:
993163899Smjacob			/* nothing to do */
994163899Smjacob			break;
995163899Smjacob		}
996163899Smjacob		xfer->spd = asyreq->req.sped;
997163899Smjacob		xfer->send.len = asyreq->req.len;
998289886Smav		xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT);
999163899Smjacob		if(xfer->send.buf == NULL){
1000196008Smjacob			return ENOMEM;
1001163899Smjacob		}
1002163899Smjacob		xfer->send.off = 0;
1003163899Smjacob		bcopy(fp, xfer->send.buf, xfer->send.len);
1004163899Smjacob		xfer->act.hand = fw_asy_callback;
1005163899Smjacob		err = fw_asyreq(sc->fc, sub, xfer);
1006196008Smjacob		if(err){
1007163899Smjacob			fw_xfer_free( xfer);
1008163899Smjacob			return err;
1009163899Smjacob		}
1010163899Smjacob		err = tsleep((caddr_t)xfer, FWPRI, "asyreq", hz);
1011163899Smjacob		if(err == 0){
1012163899Smjacob			if(asyreq->req.len >= xfer->recv.len){
1013163899Smjacob				asyreq->req.len = xfer->recv.len;
1014163899Smjacob			}else{
1015155228Smjacob				err = EINVAL;
1016196008Smjacob			}
1017196008Smjacob			bcopy(xfer->recv.buf + xfer->recv.off, fp, asyreq->req.len);
1018155228Smjacob		}
1019155228Smjacoberror:
1020155228Smjacob		fw_xfer_free( xfer);
1021155228Smjacob		break;
1022163899Smjacob	case FW_IBUSRST:
1023155228Smjacob		sc->fc->ibr(sc->fc);
1024155228Smjacob		break;
1025163899Smjacob	case FW_CBINDADDR:
1026155228Smjacob		fwb = fw_bindlookup(sc->fc,
1027196008Smjacob				bindreq->start.hi, bindreq->start.lo);
1028196008Smjacob		if(fwb == NULL){
1029196008Smjacob			err = EINVAL;
1030155228Smjacob			break;
1031155228Smjacob		}
1032155228Smjacob		STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
1033155228Smjacob		STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist);
1034163899Smjacob		free(fwb, M_DEVBUF);
1035155228Smjacob		break;
1036155228Smjacob	case FW_SBINDADDR:
1037163899Smjacob		if(bindreq->len <= 0 ){
1038163899Smjacob			err = EINVAL;
1039163899Smjacob			break;
1040196008Smjacob		}
1041163899Smjacob		if(bindreq->start.hi > 0xffff ){
1042163899Smjacob			err = EINVAL;
1043163899Smjacob			break;
1044163899Smjacob		}
1045163899Smjacob		fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_DEVBUF, M_DONTWAIT);
1046238869Smjacob		if(fwb == NULL){
1047196008Smjacob			err = ENOMEM;
1048155228Smjacob			break;
1049238869Smjacob		}
1050196008Smjacob		fwb->start_hi = bindreq->start.hi;
1051155228Smjacob		fwb->start_lo = bindreq->start.lo;
1052155228Smjacob		fwb->addrlen = bindreq->len;
1053155228Smjacob
1054155228Smjacob		xfer = fw_xfer_alloc();
1055238869Smjacob		if(xfer == NULL){
1056238869Smjacob			err = ENOMEM;
1057238869Smjacob			return err;
1058238869Smjacob		}
1059238869Smjacob		xfer->act_type = FWACT_CH;
1060238869Smjacob		xfer->sub = sub;
1061238869Smjacob		xfer->fc = sc->fc;
1062238869Smjacob
1063238869Smjacob		fwb->xfer = xfer;
1064238869Smjacob		err = fw_bindadd(sc->fc, fwb);
1065238869Smjacob		break;
1066238869Smjacob	case FW_GDEVLST:
1067238869Smjacob		i = 0;
1068238869Smjacob		for(fwdev = TAILQ_FIRST(&sc->fc->devices); fwdev != NULL;
1069238869Smjacob			fwdev = TAILQ_NEXT(fwdev, link)){
1070238869Smjacob			if(i < fwdevlst->n){
1071238869Smjacob				fwdevlst->dst[i] = fwdev->dst;
1072238869Smjacob				fwdevlst->status[i] =
1073238869Smjacob					(fwdev->status == FWDEVATTACHED)?1:0;
1074196008Smjacob				fwdevlst->eui[i].hi = fwdev->eui.hi;
1075155228Smjacob				fwdevlst->eui[i].lo = fwdev->eui.lo;
1076155228Smjacob			}
1077171159Smjacob			i++;
1078171159Smjacob		}
1079163899Smjacob		fwdevlst->n = i;
1080163899Smjacob		break;
1081196008Smjacob	case FW_GTPMAP:
1082163899Smjacob		bcopy(sc->fc->topology_map, data,
1083163899Smjacob				(sc->fc->topology_map->crc_len + 1) * 4);
1084163899Smjacob		break;
1085163899Smjacob	case FW_GSPMAP:
1086289855Smav		/* speed_map is larger than a page */
1087163899Smjacob		err = copyout(sc->fc->speed_map, *(void **)data,
1088163899Smjacob				(sc->fc->speed_map->crc_len + 1) * 4);
1089163899Smjacob		break;
1090163899Smjacob	case FW_GCROM:
1091171159Smjacob		for (fwdev = TAILQ_FIRST(&sc->fc->devices); fwdev != NULL;
1092171159Smjacob			fwdev = TAILQ_NEXT(fwdev, link)) {
1093171159Smjacob			if (fwdev->eui.hi == crom_buf->eui.hi &&
1094171159Smjacob					fwdev->eui.lo == crom_buf->eui.lo)
1095155228Smjacob				break;
1096155228Smjacob		}
1097155228Smjacob		if (fwdev == NULL) {
1098155228Smjacob			err = FWNODE_INVAL;
1099163899Smjacob			break;
1100163899Smjacob		}
1101163899Smjacob#if 0
1102163899Smjacob		if (fwdev->csrrom[0] >> 24 == 1)
1103163899Smjacob			len = 4;
1104163899Smjacob		else
1105163899Smjacob			len = (1 + ((fwdev->csrrom[0] >> 16) & 0xff)) * 4;
1106163899Smjacob#else
1107289886Smav		if (fwdev->rommax < CSRROMOFF)
1108171159Smjacob			len = 0;
1109196008Smjacob		else
1110163899Smjacob			len = fwdev->rommax - CSRROMOFF + 4;
1111163899Smjacob#endif
1112163899Smjacob		if (crom_buf->len < len)
1113163899Smjacob			len = crom_buf->len;
1114171159Smjacob		else
1115196008Smjacob			crom_buf->len = len;
1116163899Smjacob		err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len);
1117163899Smjacob		break;
1118163899Smjacob	default:
1119163899Smjacob		sc->fc->ioctl (dev, cmd, data, flag, td);
1120163899Smjacob		break;
1121204397Smjacob	}
1122204397Smjacob	return err;
1123204397Smjacob}
1124204397Smjacobint
1125204397Smjacobfw_poll(dev_t dev, int events, fw_proc *td)
1126204397Smjacob{
1127204397Smjacob	int revents;
1128204397Smjacob	int tmp;
1129204397Smjacob	int unit = DEV2UNIT(dev);
1130204397Smjacob	int sub = DEV2DMACH(dev);
1131204397Smjacob	struct firewire_softc *sc;
1132204397Smjacob
1133204397Smjacob	if (DEV_FWMEM(dev))
1134204397Smjacob		return fwmem_poll(dev, events, td);
1135204397Smjacob
1136204397Smjacob	sc = devclass_get_softc(firewire_devclass, unit);
1137204397Smjacob	revents = 0;
1138155704Smjacob	tmp = POLLIN | POLLRDNORM;
1139155228Smjacob	if (events & tmp) {
1140204397Smjacob		if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL)
1141155228Smjacob			revents |= tmp;
1142204397Smjacob		else
1143163899Smjacob			selrecord(td, &sc->fc->ir[sub]->rsel);
1144204397Smjacob	}
1145204397Smjacob	tmp = POLLOUT | POLLWRNORM;
1146163899Smjacob	if (events & tmp) {
1147155228Smjacob		/* XXX should be fixed */
1148196008Smjacob		revents |= tmp;
1149155228Smjacob	}
1150204397Smjacob
1151155228Smjacob	return revents;
1152155228Smjacob}
1153155228Smjacob
1154155228Smjacob/*
1155155228Smjacob * To lookup node id. from EUI64.
1156163899Smjacob */
1157155228Smjacobstruct fw_device *
1158155228Smjacobfw_noderesolve(struct firewire_comm *fc, struct fw_eui64 eui)
1159155228Smjacob{
1160163899Smjacob	struct fw_device *fwdev;
1161163899Smjacob	for(fwdev = TAILQ_FIRST(&fc->devices); fwdev != NULL;
1162155228Smjacob		fwdev = TAILQ_NEXT(fwdev, link)){
1163163899Smjacob		if(fwdev->eui.hi == eui.hi && fwdev->eui.lo == eui.lo){
1164163899Smjacob			break;
1165155228Smjacob		}
1166163899Smjacob	}
1167163899Smjacob	if(fwdev == NULL) return NULL;
1168163899Smjacob	if(fwdev->status == FWDEVINVAL) return NULL;
1169163899Smjacob	return fwdev;
1170155228Smjacob}
1171163899Smjacob/*
1172163899Smjacob * Async. request procedure for userland application.
1173155228Smjacob */
1174163899Smjacobint
1175163899Smjacobfw_asyreq(struct firewire_comm *fc, int sub, struct fw_xfer *xfer)
1176155228Smjacob{
1177155228Smjacob	int err = 0;
1178163899Smjacob	struct fw_xferq *xferq;
1179155228Smjacob	int tl = 0, len;
1180163899Smjacob	struct fw_pkt *fp;
1181155228Smjacob	int tcode;
1182163899Smjacob	struct tcode_info *info;
1183163899Smjacob
1184155228Smjacob	if(xfer == NULL) return EINVAL;
1185163899Smjacob	if(xfer->send.len > fc->maxrec){
1186163899Smjacob		printf("send.len > maxrec\n");
1187155228Smjacob		return EINVAL;
1188155228Smjacob	}
1189163899Smjacob	if(xfer->act.hand == NULL){
1190155228Smjacob		printf("act.hand == NULL\n");
1191163899Smjacob		return EINVAL;
1192163899Smjacob	}
1193163899Smjacob	fp = (struct fw_pkt *)xfer->send.buf;
1194163899Smjacob
1195155228Smjacob	tcode = fp->mode.common.tcode & 0xf;
1196163899Smjacob	info = &fc->tcode[tcode];
1197155228Smjacob	if (info->flag == 0) {
1198155228Smjacob		printf("invalid tcode=%d\n", tcode);
1199163899Smjacob		return EINVAL;
1200155228Smjacob	}
1201163899Smjacob	if (info->flag & FWTI_REQ)
1202155228Smjacob		xferq = fc->atq;
1203163899Smjacob	else
1204163899Smjacob		xferq = fc->ats;
1205155228Smjacob	len = info->hdr_len;
1206163899Smjacob	if (info->flag & FWTI_BLOCK_STR)
1207163899Smjacob		len += ntohs(fp->mode.stream.len);
1208155228Smjacob	else if (info->flag & FWTI_BLOCK_ASY)
1209163899Smjacob		len += ntohs(fp->mode.rresb.len);
1210163899Smjacob	if( len >  xfer->send.len ){
1211163899Smjacob		printf("len(%d) > send.len(%d) (tcode=%d)\n",
1212155228Smjacob				len, xfer->send.len, tcode);
1213163899Smjacob		return EINVAL;
1214163899Smjacob	}
1215155228Smjacob	xfer->send.len = len;
1216163899Smjacob
1217163899Smjacob	if(xferq->start == NULL){
1218155228Smjacob		printf("xferq->start == NULL\n");
1219163899Smjacob		return EINVAL;
1220155228Smjacob	}
1221155228Smjacob	if(!(xferq->queued < xferq->maxq)){
1222155228Smjacob		printf("%s:Discard a packet (queued=%d)\n",
1223163899Smjacob			device_get_nameunit(fc->dev), xferq->queued);
1224155228Smjacob		return EINVAL;
1225155228Smjacob	}
1226163899Smjacob
1227163899Smjacob
1228163899Smjacob	if (info->flag & FWTI_TLABEL) {
1229163899Smjacob		if((tl = fw_get_tlabel(fc, xfer)) == -1 )
1230163899Smjacob			return EIO;
1231163899Smjacob		fp->mode.hdr.tlrt = tl << 2;
1232163899Smjacob	}
1233163899Smjacob
1234163899Smjacob	xfer->tl = tl;
1235163899Smjacob	xfer->tcode = tcode;
1236163899Smjacob	xfer->resp = 0;
1237163899Smjacob	xfer->fc = fc;
1238163899Smjacob	xfer->q = xferq;
1239163899Smjacob	xfer->act_type = FWACT_XFER;
1240163899Smjacob	xfer->retry_req = fw_asybusy;
1241163899Smjacob
1242163899Smjacob	fw_asystart(xfer);
1243163899Smjacob	return err;
1244163899Smjacob}
1245163899Smjacob/*
1246163899Smjacob * Wakeup blocked process.
1247163899Smjacob */
1248163899Smjacobvoid
1249163899Smjacobfw_asy_callback(struct fw_xfer *xfer){
1250163899Smjacob	wakeup(xfer);
1251163899Smjacob	return;
1252163899Smjacob}
1253163899Smjacob/*
1254163899Smjacob * Postpone to later retry.
1255291730Smav */
1256291730Smavvoid fw_asybusy(struct fw_xfer *xfer){
1257291730Smav#if 0
1258196008Smjacob	printf("fw_asybusy\n");
1259163899Smjacob#endif
1260163899Smjacob#if XFER_TIMEOUT
1261163899Smjacob	untimeout(fw_xfer_timeout, (void *)xfer, xfer->ch);
1262163899Smjacob#endif
1263196008Smjacob/*
1264163899Smjacob	xfer->ch =  timeout((timeout_t *)fw_asystart, (void *)xfer, 20000);
1265163899Smjacob*/
1266163899Smjacob	DELAY(20000);
1267163899Smjacob	fw_asystart(xfer);
1268163899Smjacob	return;
1269163899Smjacob}
1270291730Smav#if XFER_TIMEOUT
1271291730Smav/*
1272196008Smjacob * Post timeout for async. request.
1273291730Smav */
1274291730Smavvoid
1275291730Smavfw_xfer_timeout(void *arg)
1276291730Smav{
1277291730Smav	int s;
1278163899Smjacob	struct fw_xfer *xfer;
1279163899Smjacob
1280163899Smjacob	xfer = (struct fw_xfer *)arg;
1281196008Smjacob	printf("fw_xfer_timeout status=%d resp=%d\n", xfer->state, xfer->resp);
1282196008Smjacob	/* XXX set error code */
1283196008Smjacob	s = splfw();
1284196008Smjacob	xfer->act.hand(xfer);
1285196008Smjacob	splx(s);
1286196008Smjacob}
1287196008Smjacob#endif
1288196008Smjacob/*
1289196008Smjacob * Async. request with given xfer structure.
1290196008Smjacob */
1291196008Smjacobstatic void
1292196008Smjacobfw_asystart(struct fw_xfer *xfer)
1293196008Smjacob{
1294196008Smjacob	struct firewire_comm *fc = xfer->fc;
1295196008Smjacob	int s;
1296196008Smjacob	if(xfer->retry++ >= fc->max_asyretry){
1297196008Smjacob		xfer->resp = EBUSY;
1298196008Smjacob		xfer->state = FWXF_BUSY;
1299196008Smjacob		xfer->act.hand(xfer);
1300196008Smjacob		return;
1301196008Smjacob	}
1302196008Smjacob#if 0 /* XXX allow bus explore packets only after bus rest */
1303196008Smjacob	if (fc->status < FWBUSEXPLORE) {
1304196008Smjacob		xfer->resp = EAGAIN;
1305196008Smjacob		xfer->state = FWXF_BUSY;
1306196008Smjacob		if (xfer->act.hand != NULL)
1307196008Smjacob			xfer->act.hand(xfer);
1308196008Smjacob		return;
1309196008Smjacob	}
1310196008Smjacob#endif
1311196008Smjacob	s = splfw();
1312196008Smjacob	xfer->state = FWXF_INQ;
1313196008Smjacob	STAILQ_INSERT_TAIL(&xfer->q->q, xfer, link);
1314196008Smjacob	xfer->q->queued ++;
1315196008Smjacob	splx(s);
1316196008Smjacob	/* XXX just queue for mbuf */
1317196008Smjacob	if (xfer->mbuf == NULL)
1318196008Smjacob		xfer->q->start(fc);
1319196008Smjacob#if XFER_TIMEOUT
1320196008Smjacob	if (xfer->act.hand != NULL)
1321196008Smjacob		xfer->ch = timeout(fw_xfer_timeout, (void *)xfer, hz);
1322196008Smjacob#endif
1323196008Smjacob	return;
1324196008Smjacob}
1325196008Smjacob
1326196008Smjacobstatic int
1327196008Smjacobfw_mmap (dev_t dev, vm_offset_t offset, int nproto)
1328196008Smjacob{
1329196008Smjacob	struct firewire_softc *fc;
1330196008Smjacob	int unit = DEV2UNIT(dev);
1331196008Smjacob
1332196008Smjacob	if (DEV_FWMEM(dev))
1333196008Smjacob		return fwmem_mmap(dev, offset, nproto);
1334290018Smav
1335196008Smjacob	fc = devclass_get_softc(firewire_devclass, unit);
1336290018Smav
1337196008Smjacob	return EINVAL;
1338196008Smjacob}
1339196008Smjacob
1340196008Smjacobstatic int
1341196008Smjacobfirewire_match( device_t dev )
1342196008Smjacob{
1343196008Smjacob	device_set_desc(dev, "IEEE1394(Firewire) bus");
1344196008Smjacob	return -140;
1345196008Smjacob}
1346196008Smjacob
1347196008Smjacob/*
1348196008Smjacob * The attach routine.
1349196008Smjacob */
1350196008Smjacobstatic int
1351196008Smjacobfirewire_attach( device_t dev )
1352196008Smjacob{
1353290018Smav	int i, unitmask, mn;
1354196008Smjacob	struct firewire_softc *sc = device_get_softc(dev);
1355290018Smav	device_t pa = device_get_parent(dev);
1356196008Smjacob	struct firewire_comm *fc;
1357196008Smjacob	dev_t d;
1358196008Smjacob
1359196008Smjacob	fc = (struct firewire_comm *)device_get_softc(pa);
1360196008Smjacob	sc->fc = fc;
1361196008Smjacob	sc->fc->dev = dev;
1362196008Smjacob
1363196008Smjacob	unitmask = UNIT2MIN(device_get_unit(dev));
1364196008Smjacob
1365196008Smjacob	if( fc->nisodma > FWMAXNDMA) fc->nisodma = FWMAXNDMA;
1366196008Smjacob	for ( i = 0 ; i < fc->nisodma ; i++ ){
1367196008Smjacob		mn = unitmask | i;
1368196008Smjacob		/* XXX device name should be improved */
1369196008Smjacob		d = make_dev(&firewire_cdevsw, unit2minor(mn),
1370196008Smjacob			UID_ROOT, GID_OPERATOR, 0770,
1371196008Smjacob			"fw%x", mn);
1372196008Smjacob#if __FreeBSD_version >= 500000
1373196008Smjacob		if (i == 0)
1374196008Smjacob			sc->dev = d;
1375196008Smjacob		else
1376196008Smjacob			dev_depends(sc->dev, d);
1377196008Smjacob#else
1378196008Smjacob		sc->dev[i] = d;
1379196008Smjacob#endif
1380196008Smjacob	}
1381196008Smjacob	d = make_dev(&firewire_cdevsw, unit2minor(unitmask | FWMEM_FLAG),
1382196008Smjacob			UID_ROOT, GID_OPERATOR, 0770,
1383196008Smjacob			"fwmem%d", device_get_unit(dev));
1384196008Smjacob#if __FreeBSD_version >= 500000
1385196008Smjacob	dev_depends(sc->dev, d);
1386196008Smjacob#else
1387196008Smjacob	sc->dev[i] = d;
1388196008Smjacob#endif
1389196008Smjacob	printf("%s: firewire bus attach\n", device_get_nameunit(sc->fc->dev));
1390196008Smjacob	sc->fc->timeouthandle = timeout((timeout_t *)sc->fc->timeout, (void *)sc->fc, hz * 10);
1391196008Smjacob
1392196008Smjacob	/* Locate our children */
1393196008Smjacob	bus_generic_probe(dev);
1394196008Smjacob
1395196008Smjacob	/* launch attachement of the added children */
1396196008Smjacob	bus_generic_attach(dev);
1397196008Smjacob
1398196008Smjacob	/* bus_reset */
1399196008Smjacob	fc->ibr(fc);
1400196008Smjacob
1401196008Smjacob	return 0;
1402196008Smjacob}
1403196008Smjacob
1404196008Smjacob/*
1405196008Smjacob * Attach it as child.
1406196008Smjacob */
1407196008Smjacobstatic device_t
1408196008Smjacobfirewire_add_child(device_t dev, int order, const char *name, int unit)
1409196008Smjacob{
1410196008Smjacob        device_t child;
1411196008Smjacob	struct firewire_softc *sc;
1412196008Smjacob
1413196008Smjacob	sc = (struct firewire_softc *)device_get_softc(dev);
1414196008Smjacob	child = device_add_child(dev, name, unit);
1415163899Smjacob	if (child) {
1416163899Smjacob		device_set_ivars(child, sc->fc);
1417163899Smjacob		device_probe_and_attach(child);
1418155228Smjacob	}
1419155228Smjacob
1420155228Smjacob	return child;
1421155228Smjacob}
1422196008Smjacob
1423155228Smjacob/*
1424155228Smjacob * Dettach it.
1425196008Smjacob */
1426155228Smjacobstatic int
1427155228Smjacobfirewire_detach( device_t dev )
1428155228Smjacob{
1429155228Smjacob	struct firewire_softc *sc;
1430155228Smjacob
1431155228Smjacob	sc = (struct firewire_softc *)device_get_softc(dev);
1432155228Smjacob
1433155228Smjacob#if __FreeBSD_version >= 500000
1434155228Smjacob	destroy_dev(sc->dev);
1435155228Smjacob#else
1436155228Smjacob	{
1437155228Smjacob		int j;
1438155228Smjacob		for (j = 0 ; j < sc->fc->nisodma + 1; j++)
1439155228Smjacob			destroy_dev(sc->dev[j]);
1440155228Smjacob	}
1441155228Smjacob#endif
1442155228Smjacob	/* XXX xfree_free and untimeout on all xfers */
1443155228Smjacob	untimeout((timeout_t *)sc->fc->timeout, sc->fc, sc->fc->timeouthandle);
1444155228Smjacob	free(sc->fc->topology_map, M_DEVBUF);
1445155228Smjacob	free(sc->fc->speed_map, M_DEVBUF);
1446155228Smjacob	bus_generic_detach(dev);
1447155228Smjacob	return(0);
1448155228Smjacob}
1449155228Smjacob#if 0
1450155228Smjacobstatic int
1451155228Smjacobfirewire_shutdown( device_t dev )
1452155228Smjacob{
1453155228Smjacob	return 0;
1454155228Smjacob}
1455155228Smjacob#endif
1456155228Smjacob
1457155228Smjacob/*
1458155228Smjacob * Called after bus reset.
1459155228Smjacob */
1460155228Smjacobvoid
1461155228Smjacobfw_busreset(struct firewire_comm *fc)
1462155228Smjacob{
1463155228Smjacob	int i;
1464155228Smjacob	struct fw_xfer *xfer;
1465155228Smjacob
1466163899Smjacob	switch(fc->status){
1467163899Smjacob	case FWBUSMGRELECT:
1468163899Smjacob		untimeout((timeout_t *)fw_try_bmr, (void *)fc, fc->bmrhandle);
1469163899Smjacob		break;
1470163899Smjacob	default:
1471163899Smjacob		break;
1472163899Smjacob	}
1473163899Smjacob	fc->status = FWBUSRESET;
1474196008Smjacob/* XXX: discard all queued packet */
1475163899Smjacob	while((xfer = STAILQ_FIRST(&fc->atq->q)) != NULL){
1476163899Smjacob		STAILQ_REMOVE_HEAD(&fc->atq->q, link);
1477196008Smjacob		xfer->resp = EAGAIN;
1478163899Smjacob		switch(xfer->act_type){
1479163899Smjacob		case FWACT_XFER:
1480163899Smjacob			fw_xfer_done(xfer);
1481163899Smjacob			break;
1482163899Smjacob		default:
1483163899Smjacob			break;
1484163899Smjacob		}
1485163899Smjacob		fw_xfer_free( xfer);
1486163899Smjacob	}
1487163899Smjacob	while((xfer = STAILQ_FIRST(&fc->ats->q)) != NULL){
1488163899Smjacob		STAILQ_REMOVE_HEAD(&fc->ats->q, link);
1489163899Smjacob		xfer->resp = EAGAIN;
1490163899Smjacob		switch(xfer->act_type){
1491163899Smjacob		case FWACT_XFER:
1492196008Smjacob			fw_xfer_done(xfer);
1493163899Smjacob		default:
1494163899Smjacob			break;
1495155228Smjacob		}
1496290104Smav		fw_xfer_free( xfer);
1497290104Smav	}
1498290104Smav	for(i = 0; i < fc->nisodma; i++)
1499290104Smav		while((xfer = STAILQ_FIRST(&fc->it[i]->q)) != NULL){
1500290104Smav			STAILQ_REMOVE_HEAD(&fc->it[i]->q, link);
1501290104Smav			xfer->resp = 0;
1502290104Smav			switch(xfer->act_type){
1503290104Smav			case FWACT_XFER:
1504290104Smav				fw_xfer_done(xfer);
1505290104Smav				break;
1506290104Smav			default:
1507290104Smav				break;
1508290104Smav			}
1509290104Smav			fw_xfer_free( xfer);
1510290104Smav		}
1511290104Smav
1512290104Smav	CSRARC(fc, STATE_CLEAR)
1513290104Smav			= 1 << 23 | 0 << 17 | 1 << 16 | 1 << 15 | 1 << 14 ;
1514290104Smav	CSRARC(fc, STATE_SET) = CSRARC(fc, STATE_CLEAR);
1515290104Smav	CSRARC(fc, NODE_IDS) = 0x3f;
1516290104Smav
1517290104Smav	CSRARC(fc, TOPO_MAP + 8) = 0;
1518290104Smav	fc->irm = -1;
1519290104Smav
1520290104Smav	fc->max_node = -1;
1521290104Smav
1522290104Smav	for(i = 2; i < 0x100/4 - 2 ; i++){
1523290104Smav		CSRARC(fc, SPED_MAP + i * 4) = 0;
1524290104Smav	}
1525290104Smav	CSRARC(fc, STATE_CLEAR) = 1 << 23 | 0 << 17 | 1 << 16 | 1 << 15 | 1 << 14 ;
1526290104Smav	CSRARC(fc, STATE_SET) = CSRARC(fc, STATE_CLEAR);
1527290104Smav	CSRARC(fc, RESET_START) = 0;
1528290104Smav	CSRARC(fc, SPLIT_TIMEOUT_HI) = 0;
1529290104Smav	CSRARC(fc, SPLIT_TIMEOUT_LO) = 800 << 19;
1530290104Smav	CSRARC(fc, CYCLE_TIME) = 0x0;
1531290104Smav	CSRARC(fc, BUS_TIME) = 0x0;
1532290104Smav	CSRARC(fc, BUS_MGR_ID) = 0x3f;
1533290104Smav	CSRARC(fc, BANDWIDTH_AV) = 4915;
1534155228Smjacob	CSRARC(fc, CHANNELS_AV_HI) = 0xffffffff;
1535163899Smjacob	CSRARC(fc, CHANNELS_AV_LO) = 0xffffffff;
1536155228Smjacob	CSRARC(fc, IP_CHANNELS) = (1 << 31);
1537163899Smjacob
1538155228Smjacob	CSRARC(fc, CONF_ROM) = 0x04 << 24;
1539163899Smjacob	CSRARC(fc, CONF_ROM + 4) = 0x31333934; /* means strings 1394 */
1540155228Smjacob	CSRARC(fc, CONF_ROM + 8) = 1 << 31 | 1 << 30 | 1 << 29 |
1541163899Smjacob				1 << 28 | 0xff << 16 | 0x09 << 8;
1542163899Smjacob	CSRARC(fc, CONF_ROM + 0xc) = 0;
1543163899Smjacob
1544163899Smjacob/* DV depend CSRs see blue book */
1545163899Smjacob	CSRARC(fc, oPCR) &= ~DV_BROADCAST_ON;
1546163899Smjacob	CSRARC(fc, iPCR) &= ~DV_BROADCAST_ON;
1547163899Smjacob
1548163899Smjacob	CSRARC(fc, STATE_CLEAR) &= ~(1 << 23 | 1 << 15 | 1 << 14 );
1549163899Smjacob	CSRARC(fc, STATE_SET) = CSRARC(fc, STATE_CLEAR);
1550163899Smjacob}
1551196008Smjacob
1552196008Smjacob/* Call once after reboot */
1553163899Smjacobvoid fw_init(struct firewire_comm *fc)
1554155228Smjacob{
1555155228Smjacob	int i;
1556163899Smjacob	struct csrdir *csrd;
1557163899Smjacob#ifdef FW_VMACCESS
1558163899Smjacob	struct fw_xfer *xfer;
1559163899Smjacob	struct fw_bind *fwb;
1560163899Smjacob#endif
1561163899Smjacob
1562163899Smjacob	fc->max_asyretry = FW_MAXASYRTY;
1563163899Smjacob
1564163899Smjacob	fc->arq->queued = 0;
1565163899Smjacob	fc->ars->queued = 0;
1566163899Smjacob	fc->atq->queued = 0;
1567163899Smjacob	fc->ats->queued = 0;
1568163899Smjacob
1569196008Smjacob	fc->arq->psize = FWPMAX_S400;
1570196008Smjacob	fc->ars->psize = FWPMAX_S400;
1571163899Smjacob	fc->atq->psize = FWPMAX_S400;
1572163899Smjacob	fc->ats->psize = FWPMAX_S400;
1573163899Smjacob
1574155228Smjacob
1575196008Smjacob	fc->arq->buf = NULL;
1576196008Smjacob	fc->ars->buf = NULL;
1577196008Smjacob	fc->atq->buf = NULL;
1578196008Smjacob	fc->ats->buf = NULL;
1579196008Smjacob
1580196008Smjacob	fc->arq->flag = FWXFERQ_PACKET;
1581196008Smjacob	fc->ars->flag = FWXFERQ_PACKET;
1582196008Smjacob	fc->atq->flag = FWXFERQ_PACKET;
1583290978Smav	fc->ats->flag = FWXFERQ_PACKET;
1584290978Smav
1585290978Smav	STAILQ_INIT(&fc->atq->q);
1586290978Smav	STAILQ_INIT(&fc->ats->q);
1587196008Smjacob
1588196008Smjacob	for( i = 0 ; i < fc->nisodma ; i ++ ){
1589196008Smjacob		fc->it[i]->queued = 0;
1590196008Smjacob		fc->ir[i]->queued = 0;
1591196008Smjacob
1592196008Smjacob		fc->it[i]->start = NULL;
1593196008Smjacob		fc->ir[i]->start = NULL;
1594196008Smjacob
1595196008Smjacob		fc->it[i]->buf = NULL;
1596196008Smjacob		fc->ir[i]->buf = NULL;
1597196008Smjacob
1598196008Smjacob		fc->it[i]->flag = FWXFERQ_STREAM;
1599196008Smjacob		fc->ir[i]->flag = FWXFERQ_STREAM;
1600163899Smjacob
1601163899Smjacob		STAILQ_INIT(&fc->it[i]->q);
1602163899Smjacob		STAILQ_INIT(&fc->ir[i]->q);
1603163899Smjacob
1604163899Smjacob		STAILQ_INIT(&fc->it[i]->binds);
1605163899Smjacob		STAILQ_INIT(&fc->ir[i]->binds);
1606163899Smjacob	}
1607163899Smjacob
1608163899Smjacob	fc->arq->maxq = FWMAXQUEUE;
1609163899Smjacob	fc->ars->maxq = FWMAXQUEUE;
1610163899Smjacob	fc->atq->maxq = FWMAXQUEUE;
1611163899Smjacob	fc->ats->maxq = FWMAXQUEUE;
1612196008Smjacob
1613196008Smjacob	for( i = 0 ; i < fc->nisodma ; i++){
1614163899Smjacob		fc->ir[i]->maxq = FWMAXQUEUE;
1615196008Smjacob		fc->it[i]->maxq = FWMAXQUEUE;
1616163899Smjacob	}
1617163899Smjacob/* Initialize csr registers */
1618196008Smjacob	fc->topology_map = (struct fw_topology_map *)malloc(
1619163899Smjacob				sizeof(struct fw_topology_map),
1620163899Smjacob				M_DEVBUF, M_DONTWAIT | M_ZERO);
1621163899Smjacob	fc->speed_map = (struct fw_speed_map *)malloc(
1622163899Smjacob				sizeof(struct fw_speed_map),
1623196008Smjacob				M_DEVBUF, M_DONTWAIT | M_ZERO);
1624196008Smjacob	CSRARC(fc, TOPO_MAP) = 0x3f1 << 16;
1625196008Smjacob	CSRARC(fc, TOPO_MAP + 4) = 1;
1626163899Smjacob	CSRARC(fc, SPED_MAP) = 0x3f1 << 16;
1627163899Smjacob	CSRARC(fc, SPED_MAP + 4) = 1;
1628163899Smjacob
1629163899Smjacob	TAILQ_INIT(&fc->devices);
1630164370Smjacob	STAILQ_INIT(&fc->pending);
1631164370Smjacob
1632164370Smjacob/* Initialize csr ROM work space */
1633164370Smjacob	SLIST_INIT(&fc->ongocsr);
1634164370Smjacob	SLIST_INIT(&fc->csrfree);
1635164370Smjacob	for( i = 0 ; i < FWMAXCSRDIR ; i++){
1636164370Smjacob		csrd = (struct csrdir *) malloc(sizeof(struct csrdir), M_DEVBUF,M_DONTWAIT);
1637164370Smjacob		if(csrd == NULL) break;
1638164370Smjacob		SLIST_INSERT_HEAD(&fc->csrfree, csrd, link);
1639164370Smjacob	}
1640164370Smjacob
1641164370Smjacob/* Initialize Async handlers */
1642164370Smjacob	STAILQ_INIT(&fc->binds);
1643164370Smjacob	for( i = 0 ; i < 0x40 ; i++){
1644164370Smjacob		STAILQ_INIT(&fc->tlabels[i]);
1645164370Smjacob	}
1646164370Smjacob
1647164370Smjacob/* DV depend CSRs see blue book */
1648164370Smjacob#if 0
1649164370Smjacob	CSRARC(fc, oMPR) = 0x3fff0001; /* # output channel = 1 */
1650196008Smjacob	CSRARC(fc, oPCR) = 0x8000007a;
1651196008Smjacob	for(i = 4 ; i < 0x7c/4 ; i+=4){
1652196008Smjacob		CSRARC(fc, i + oPCR) = 0x8000007a;
1653164370Smjacob	}
1654164370Smjacob
1655164370Smjacob	CSRARC(fc, iMPR) = 0x00ff0001; /* # input channel = 1 */
1656164370Smjacob	CSRARC(fc, iPCR) = 0x803f0000;
1657163899Smjacob	for(i = 4 ; i < 0x7c/4 ; i+=4){
1658163899Smjacob		CSRARC(fc, i + iPCR) = 0x0;
1659163899Smjacob	}
1660163899Smjacob#endif
1661163899Smjacob
1662163899Smjacob
1663163899Smjacob#ifdef FW_VMACCESS
1664163899Smjacob	xfer = fw_xfer_alloc();
1665163899Smjacob	if(xfer == NULL) return;
1666196008Smjacob
1667196008Smjacob	fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_DEVBUF, M_DONTWAIT);
1668163899Smjacob	if(fwb == NULL){
1669196008Smjacob		fw_xfer_free(xfer);
1670163899Smjacob	}
1671163899Smjacob	xfer->act.hand = fw_vmaccess;
1672196008Smjacob	xfer->act_type = FWACT_XFER;
1673163899Smjacob	xfer->fc = fc;
1674163899Smjacob	xfer->sc = NULL;
1675163899Smjacob
1676163899Smjacob	fwb->start_hi = 0x2;
1677196008Smjacob	fwb->start_lo = 0;
1678196008Smjacob	fwb->addrlen = 0xffffffff;
1679196008Smjacob	fwb->xfer = xfer;
1680163899Smjacob	fw_bindadd(fc, fwb);
1681163899Smjacob#endif
1682163899Smjacob}
1683164370Smjacob
1684164370Smjacob/*
1685164370Smjacob * To lookup binded process from IEEE1394 address.
1686164370Smjacob */
1687164370Smjacobstatic struct fw_bind *
1688164370Smjacobfw_bindlookup(struct firewire_comm *fc, u_int32_t dest_hi, u_int32_t dest_lo)
1689164370Smjacob{
1690164370Smjacob	struct fw_bind *tfw;
1691164370Smjacob	for(tfw = STAILQ_FIRST(&fc->binds) ; tfw != NULL ;
1692164370Smjacob		tfw = STAILQ_NEXT(tfw, fclist)){
1693164370Smjacob		if(tfw->xfer->act_type != FWACT_NULL &&
1694164370Smjacob			tfw->start_hi == dest_hi &&
1695164370Smjacob			tfw->start_lo <= dest_lo &&
1696164370Smjacob			(tfw->start_lo + tfw->addrlen) > dest_lo){
1697164370Smjacob			return(tfw);
1698164370Smjacob		}
1699164370Smjacob	}
1700164370Smjacob	return(NULL);
1701164370Smjacob}
1702164370Smjacob
1703164370Smjacob/*
1704196008Smjacob * To bind IEEE1394 address block to process.
1705196008Smjacob */
1706196008Smjacobint
1707164370Smjacobfw_bindadd(struct firewire_comm *fc, struct fw_bind *fwb)
1708164370Smjacob{
1709164370Smjacob	struct fw_bind *tfw, *tfw2 = NULL;
1710163899Smjacob	int err = 0;
1711155228Smjacob	tfw = STAILQ_FIRST(&fc->binds);
1712155228Smjacob	if(tfw == NULL){
1713155228Smjacob		STAILQ_INSERT_HEAD(&fc->binds, fwb, fclist);
1714155228Smjacob		goto out;
1715155704Smjacob	}
1716155228Smjacob	if((tfw->start_hi > fwb->start_hi) ||
1717155228Smjacob		(tfw->start_hi == fwb->start_hi &&
1718155228Smjacob		(tfw->start_lo > (fwb->start_lo + fwb->addrlen)))){
1719155228Smjacob		STAILQ_INSERT_HEAD(&fc->binds, fwb, fclist);
1720155228Smjacob		goto out;
1721155228Smjacob	}
1722155228Smjacob	for(; tfw != NULL; tfw = STAILQ_NEXT(tfw, fclist)){
1723155228Smjacob		if((tfw->start_hi < fwb->start_hi) ||
1724155228Smjacob		   (tfw->start_hi == fwb->start_hi &&
1725155228Smjacob		    (tfw->start_lo + tfw->addrlen) < fwb->start_lo)){
1726155228Smjacob		   tfw2 = STAILQ_NEXT(tfw, fclist);
1727155228Smjacob			if(tfw2 == NULL)
1728155228Smjacob				break;
1729196008Smjacob			if((tfw2->start_hi > fwb->start_hi) ||
1730155228Smjacob			   (tfw2->start_hi == fwb->start_hi &&
1731155228Smjacob			    tfw2->start_lo > (fwb->start_lo + fwb->addrlen))){
1732163899Smjacob				break;
1733155228Smjacob			}else{
1734155228Smjacob				err = EBUSY;
1735155228Smjacob				goto out;
1736155228Smjacob			}
1737155228Smjacob		}
1738163899Smjacob	}
1739155228Smjacob	if(tfw != NULL){
1740155228Smjacob		STAILQ_INSERT_AFTER(&fc->binds, tfw, fwb, fclist);
1741163899Smjacob	}else{
1742155228Smjacob		STAILQ_INSERT_TAIL(&fc->binds, fwb, fclist);
1743155228Smjacob	}
1744155228Smjacobout:
1745155228Smjacob	if(!err && fwb->xfer->act_type == FWACT_CH){
1746321870Smav		STAILQ_INSERT_HEAD(&fc->ir[fwb->xfer->sub]->binds, fwb, chlist);
1747155228Smjacob	}
1748155228Smjacob	return err;
1749163899Smjacob}
1750155228Smjacob
1751155228Smjacob/*
1752155228Smjacob * To free IEEE1394 address block.
1753155228Smjacob */
1754155228Smjacobint
1755163899Smjacobfw_bindremove(struct firewire_comm *fc, struct fw_bind *fwb)
1756155228Smjacob{
1757321870Smav	int s;
1758163899Smjacob
1759321870Smav	s = splfw();
1760321870Smav	/* shall we check the existance? */
1761321870Smav	STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist);
1762321870Smav	splx(s);
1763155228Smjacob	if (fwb->xfer)
1764155228Smjacob		fw_xfer_free(fwb->xfer);
1765155228Smjacob
1766321870Smav	return 0;
1767155228Smjacob}
1768321870Smav
1769321870Smav/*
1770321870Smav * To free transaction label.
1771321870Smav */
1772321870Smavstatic void
1773321870Smavfw_tl_free(struct firewire_comm *fc, struct fw_xfer *xfer)
1774321870Smav{
1775321870Smav	struct tlabel *tl;
1776321870Smav	int s = splfw();
1777321870Smav
1778321870Smav	for( tl = STAILQ_FIRST(&fc->tlabels[xfer->tl]); tl != NULL;
1779321870Smav		tl = STAILQ_NEXT(tl, link)){
1780155228Smjacob		if(tl->xfer == xfer){
1781155228Smjacob			STAILQ_REMOVE(&fc->tlabels[xfer->tl], tl, tlabel, link);
1782155228Smjacob			free(tl, M_DEVBUF);
1783321870Smav			splx(s);
1784155228Smjacob			return;
1785321870Smav		}
1786321870Smav	}
1787155228Smjacob	splx(s);
1788155228Smjacob	return;
1789321870Smav}
1790321870Smav
1791155228Smjacob/*
1792321870Smav * To obtain XFER structure by transaction label.
1793321870Smav */
1794155228Smjacobstatic struct fw_xfer *
1795321870Smavfw_tl2xfer(struct firewire_comm *fc, int node, int tlabel)
1796155228Smjacob{
1797155228Smjacob	struct fw_xfer *xfer;
1798155228Smjacob	struct tlabel *tl;
1799155228Smjacob	int s = splfw();
1800155228Smjacob
1801196008Smjacob	for( tl = STAILQ_FIRST(&fc->tlabels[tlabel]); tl != NULL;
1802155228Smjacob		tl = STAILQ_NEXT(tl, link)){
1803155228Smjacob		if(tl->xfer->dst == node){
1804321870Smav			xfer = tl->xfer;
1805155228Smjacob			splx(s);
1806321870Smav			return(xfer);
1807321870Smav		}
1808321870Smav	}
1809321870Smav	splx(s);
1810321870Smav	return(NULL);
1811321870Smav}
1812321870Smav
1813321870Smav/*
1814321870Smav * To allocate IEEE1394 XFER structure.
1815321870Smav */
1816196008Smjacobstruct fw_xfer *
1817321870Smavfw_xfer_alloc()
1818321870Smav{
1819196008Smjacob	struct fw_xfer *xfer;
1820155228Smjacob
1821155228Smjacob	xfer = malloc(sizeof(struct fw_xfer), M_DEVBUF, M_DONTWAIT | M_ZERO);
1822155228Smjacob	if (xfer == NULL)
1823196008Smjacob		return xfer;
1824155228Smjacob
1825155228Smjacob	xfer->time = time_second;
1826321870Smav	xfer->sub = -1;
1827155228Smjacob
1828155228Smjacob	return xfer;
1829321870Smav}
1830321870Smav
1831155228Smjacob/*
1832155228Smjacob * IEEE1394 XFER post process.
1833155228Smjacob */
1834155228Smjacobvoid
1835196008Smjacobfw_xfer_done(struct fw_xfer *xfer)
1836155228Smjacob{
1837155228Smjacob	if (xfer->act.hand == NULL)
1838155228Smjacob		return;
1839321870Smav
1840155228Smjacob#if XFER_TIMEOUT
1841321870Smav	untimeout(fw_xfer_timeout, (void *)xfer, xfer->ch);
1842155228Smjacob#endif
1843155228Smjacob
1844321870Smav	if (xfer->fc->status != FWBUSRESET)
1845155228Smjacob		xfer->act.hand(xfer);
1846321870Smav	else {
1847155228Smjacob		printf("fw_xfer_done: pending\n");
1848321870Smav		if (xfer->fc != NULL)
1849155228Smjacob			STAILQ_INSERT_TAIL(&xfer->fc->pending, xfer, link);
1850155228Smjacob		else
1851321870Smav			panic("fw_xfer_done: why xfer->fc is NULL?");
1852155228Smjacob	}
1853321870Smav}
1854155228Smjacob
1855321870Smav/*
1856155228Smjacob * To free IEEE1394 XFER structure.
1857155228Smjacob */
1858321870Smavvoid
1859155228Smjacobfw_xfer_free( struct fw_xfer* xfer)
1860155228Smjacob{
1861321870Smav	int s;
1862155228Smjacob	if(xfer == NULL ) return;
1863155228Smjacob	if(xfer->state == FWXF_INQ){
1864321870Smav		printf("fw_xfer_free FWXF_INQ\n");
1865155228Smjacob		s = splfw();
1866155228Smjacob		STAILQ_REMOVE(&xfer->q->q, xfer, fw_xfer, link);
1867321870Smav		xfer->q->queued --;
1868155228Smjacob		splx(s);
1869155228Smjacob	}
1870321870Smav	if(xfer->fc != NULL){
1871155228Smjacob		if(xfer->state == FWXF_START){
1872321870Smav#if 0 /* this could happen if we call fwohci_arcv() before fwohci_txd() */
1873155228Smjacob			printf("fw_xfer_free FWXF_START\n");
1874321870Smav#endif
1875155228Smjacob			s = splfw();
1876155228Smjacob			xfer->q->drain(xfer->fc, xfer);
1877155228Smjacob			splx(s);
1878163899Smjacob		}
1879163899Smjacob	}
1880163899Smjacob	if(xfer->send.buf != NULL){
1881163899Smjacob		free(xfer->send.buf, M_DEVBUF);
1882163899Smjacob	}
1883163899Smjacob	if(xfer->recv.buf != NULL){
1884163899Smjacob		free(xfer->recv.buf, M_DEVBUF);
1885163899Smjacob	}
1886163899Smjacob	if(xfer->fc != NULL){
1887163899Smjacob		fw_tl_free(xfer->fc, xfer);
1888163899Smjacob	}
1889163899Smjacob	free(xfer, M_DEVBUF);
1890163899Smjacob}
1891163899Smjacob
1892163899Smjacob/*
1893163899Smjacob * Callback for PHY configuration.
1894163899Smjacob */
1895163899Smjacobstatic void
1896163899Smjacobfw_phy_config_callback(struct fw_xfer *xfer)
1897163899Smjacob{
1898163899Smjacob#if 0
1899163899Smjacob	printf("phy_config done state=%d resp=%d\n",
1900163899Smjacob				xfer->state, xfer->resp);
1901163899Smjacob#endif
1902163899Smjacob	fw_xfer_free(xfer);
1903163899Smjacob	/* XXX need bus reset ?? */
1904196008Smjacob	/* sc->fc->ibr(xfer->fc);  LOOP */
1905163899Smjacob}
1906163899Smjacob
1907163899Smjacob/*
1908163899Smjacob * To configure PHY.
1909163899Smjacob */
1910163899Smjacobstatic void
1911163899Smjacobfw_phy_config(struct firewire_comm *fc, int root_node, int gap_count)
1912163899Smjacob{
1913163899Smjacob	struct fw_xfer *xfer;
1914163899Smjacob	struct fw_pkt *fp;
1915163899Smjacob
1916163899Smjacob	fc->status = FWBUSPHYCONF;
1917163899Smjacob
1918163899Smjacob	DELAY(100000);
1919163899Smjacob	xfer = fw_xfer_alloc();
1920163899Smjacob	xfer->send.len = 12;
1921163899Smjacob	xfer->send.off = 0;
1922163899Smjacob	xfer->fc = fc;
1923163899Smjacob	xfer->retry_req = fw_asybusy;
1924163899Smjacob	xfer->act.hand = fw_phy_config_callback;
1925163899Smjacob
1926163899Smjacob	xfer->send.buf = malloc(sizeof(u_int32_t),
1927163899Smjacob					M_DEVBUF, M_DONTWAIT | M_ZERO);
1928163899Smjacob	fp = (struct fw_pkt *)xfer->send.buf;
1929163899Smjacob	fp->mode.ld[1] = 0;
1930163899Smjacob	if (root_node >= 0)
1931163899Smjacob		fp->mode.ld[1] |= htonl((root_node & 0x3f) << 24 | 1 << 23);
1932163899Smjacob	if (gap_count >= 0)
1933163899Smjacob		fp->mode.ld[1] |= htonl(1 << 22 | (gap_count & 0x3f) << 16);
1934163899Smjacob	fp->mode.ld[2] = ~fp->mode.ld[1];
1935163899Smjacob/* XXX Dangerous, how to pass PHY packet to device driver */
1936163899Smjacob	fp->mode.common.tcode |= FWTCODE_PHY;
1937163899Smjacob
1938163899Smjacob	printf("send phy_config root_node=%d gap_count=%d\n",
1939163899Smjacob						root_node, gap_count);
1940163899Smjacob	fw_asyreq(fc, -1, xfer);
1941163899Smjacob}
1942163899Smjacob
1943163899Smjacob#if 0
1944163899Smjacob/*
1945163899Smjacob * Dump self ID.
1946163899Smjacob */
1947163899Smjacobstatic void
1948163899Smjacobfw_print_sid(u_int32_t sid)
1949163899Smjacob{
1950163899Smjacob	union fw_self_id *s;
1951163899Smjacob	s = (union fw_self_id *) &sid;
1952163899Smjacob	printf("node:%d link:%d gap:%d spd:%d del:%d con:%d pwr:%d"
1953163899Smjacob		" p0:%d p1:%d p2:%d i:%d m:%d\n",
1954163899Smjacob		s->p0.phy_id, s->p0.link_active, s->p0.gap_count,
1955163899Smjacob		s->p0.phy_speed, s->p0.phy_delay, s->p0.contender,
1956163899Smjacob		s->p0.power_class, s->p0.port0, s->p0.port1,
1957163899Smjacob		s->p0.port2, s->p0.initiated_reset, s->p0.more_packets);
1958196008Smjacob}
1959196008Smjacob#endif
1960196008Smjacob
1961163899Smjacob/*
1962163899Smjacob * To receive self ID.
1963163899Smjacob */
1964163899Smjacobvoid fw_sidrcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int off)
1965163899Smjacob{
1966163899Smjacob	u_int32_t *p, *sid = (u_int32_t *)(buf + off);
1967163899Smjacob	union fw_self_id *self_id;
1968163899Smjacob	u_int i, j, node, c_port = 0, i_branch = 0;
1969163899Smjacob
1970238869Smjacob	fc->sid_cnt = len /(sizeof(u_int32_t) * 2);
1971238869Smjacob	fc->status = FWBUSINIT;
1972238869Smjacob	fc->max_node = fc->nodeid & 0x3f;
1973238869Smjacob	CSRARC(fc, NODE_IDS) = ((u_int32_t)fc->nodeid) << 16;
1974238869Smjacob	fc->status = FWBUSCYMELECT;
1975238869Smjacob	fc->topology_map->crc_len = 2;
1976238869Smjacob	fc->topology_map->generation ++;
1977238869Smjacob	fc->topology_map->self_id_count = 0;
1978238869Smjacob	fc->topology_map->node_count = 0;
1979238869Smjacob	fc->speed_map->generation ++;
1980238869Smjacob	fc->speed_map->crc_len = 1 + (64*64 + 3) / 4;
1981238869Smjacob	self_id = &fc->topology_map->self_id[0];
1982238869Smjacob	for(i = 0; i < fc->sid_cnt; i ++){
1983238869Smjacob		if (sid[1] != ~sid[0]) {
1984238869Smjacob			printf("fw_sidrcv: invalid self-id packet\n");
1985238869Smjacob			sid += 2;
1986238869Smjacob			continue;
1987238869Smjacob		}
1988238869Smjacob		*self_id = *((union fw_self_id *)sid);
1989238869Smjacob		fc->topology_map->crc_len++;
1990238869Smjacob		if(self_id->p0.sequel == 0){
1991238869Smjacob			fc->topology_map->node_count ++;
1992238869Smjacob			c_port = 0;
1993163899Smjacob#if 0
1994163899Smjacob			fw_print_sid(sid[0]);
1995163899Smjacob#endif
1996163899Smjacob			node = self_id->p0.phy_id;
1997163899Smjacob			if(fc->max_node < node){
1998163899Smjacob				fc->max_node = self_id->p0.phy_id;
1999163899Smjacob			}
2000163899Smjacob			/* XXX I'm not sure this is the right speed_map */
2001196008Smjacob			fc->speed_map->speed[node][node]
2002196008Smjacob					= self_id->p0.phy_speed;
2003196008Smjacob			for (j = 0; j < node; j ++) {
2004163899Smjacob				fc->speed_map->speed[j][node]
2005196008Smjacob					= fc->speed_map->speed[node][j]
2006163899Smjacob					= min(fc->speed_map->speed[j][j],
2007196008Smjacob							self_id->p0.phy_speed);
2008163899Smjacob			}
2009163899Smjacob			if ((fc->irm == -1 || self_id->p0.phy_id > fc->irm) &&
2010163899Smjacob			  (self_id->p0.link_active && self_id->p0.contender)) {
2011163899Smjacob				fc->irm = self_id->p0.phy_id;
2012163899Smjacob			}
2013163899Smjacob			if(self_id->p0.port0 >= 0x2){
2014163899Smjacob				c_port++;
2015163899Smjacob			}
2016163899Smjacob			if(self_id->p0.port1 >= 0x2){
2017163899Smjacob				c_port++;
2018163899Smjacob			}
2019163899Smjacob			if(self_id->p0.port2 >= 0x2){
2020196008Smjacob				c_port++;
2021163899Smjacob			}
2022163899Smjacob		}
2023163899Smjacob		if(c_port > 2){
2024163899Smjacob			i_branch += (c_port - 2);
2025297751Smav		}
2026297751Smav		sid += 2;
2027297751Smav		self_id++;
2028297751Smav		fc->topology_map->self_id_count ++;
2029297751Smav	}
2030297751Smav	printf("%s: %d nodes", device_get_nameunit(fc->dev), fc->max_node + 1);
2031297751Smav	/* CRC */
2032297751Smav	fc->topology_map->crc = fw_crc16(
2033297751Smav			(u_int32_t *)&fc->topology_map->generation,
2034297751Smav			fc->topology_map->crc_len * 4);
2035297751Smav	fc->speed_map->crc = fw_crc16(
2036291000Smav			(u_int32_t *)&fc->speed_map->generation,
2037291000Smav			fc->speed_map->crc_len * 4);
2038291000Smav	/* byteswap and copy to CSR */
2039291000Smav	p = (u_int32_t *)fc->topology_map;
2040291000Smav	for (i = 0; i <= fc->topology_map->crc_len; i++)
2041291000Smav		CSRARC(fc, TOPO_MAP + i * 4) = htonl(*p++);
2042291000Smav	p = (u_int32_t *)fc->speed_map;
2043291000Smav	CSRARC(fc, SPED_MAP) = htonl(*p++);
2044291000Smav	CSRARC(fc, SPED_MAP + 4) = htonl(*p++);
2045291000Smav	/* don't byte-swap u_int8_t array */
2046291000Smav	bcopy(p, &CSRARC(fc, SPED_MAP + 8), (fc->speed_map->crc_len - 1)*4);
2047291000Smav
2048291000Smav	fc->max_hop = fc->max_node - i_branch;
2049291000Smav#if 1
2050297751Smav	printf(", maxhop <= %d", fc->max_hop);
2051297751Smav#endif
2052297751Smav
2053297751Smav	if(fc->irm == -1 ){
2054297751Smav		printf(", Not found IRM capable node");
2055297751Smav	}else{
2056297751Smav		printf(", cable IRM = %d", fc->irm);
2057297751Smav		if (fc->irm == fc->nodeid)
2058297751Smav			printf(" (me)\n");
2059297751Smav		else
2060297751Smav			printf("\n");
2061297751Smav	}
2062163899Smjacob
2063163899Smjacob	if((fc->irm != -1) && (CSRARC(fc, BUS_MGR_ID) == 0x3f) ){
2064163899Smjacob		if(fc->irm == ((CSRARC(fc, NODE_IDS) >> 16 ) & 0x3f)){
2065163899Smjacob			fc->status = FWBUSMGRDONE;
2066163899Smjacob			CSRARC(fc, BUS_MGR_ID) = fc->set_bmr(fc, fc->irm);
2067163899Smjacob		}else{
2068163899Smjacob			fc->status = FWBUSMGRELECT;
2069163899Smjacob			fc->bmrhandle = timeout((timeout_t *)fw_try_bmr,(void *)fc, hz / 8);
2070163899Smjacob		}
2071163899Smjacob	}else{
2072163899Smjacob		fc->status = FWBUSMGRDONE;
2073163899Smjacob		printf("%s: BMR = %x\n", device_get_nameunit(fc->dev), CSRARC(fc, BUS_MGR_ID));
2074163899Smjacob	}
2075163899Smjacob	free(buf, M_DEVBUF);
2076163899Smjacob#if 1
2077163899Smjacob	/* XXX optimize gap_count, if I am BMGR */
2078163899Smjacob	if(fc->irm == ((CSRARC(fc, NODE_IDS) >> 16 ) & 0x3f)){
2079163899Smjacob		fw_phy_config(fc, -1, gap_cnt[fc->max_hop]);
2080163899Smjacob	}
2081163899Smjacob#endif
2082163899Smjacob#if 1
2083163899Smjacob	timeout((timeout_t *)fw_bus_probe, (void *)fc, hz/4);
2084163899Smjacob#else
2085163899Smjacob	fw_bus_probe(fc);
2086163899Smjacob#endif
2087163899Smjacob}
2088163899Smjacob
2089163899Smjacob/*
2090163899Smjacob * To probe devices on the IEEE1394 bus.
2091163899Smjacob */
2092163899Smjacobstatic void
2093163899Smjacobfw_bus_probe(struct firewire_comm *fc)
2094163899Smjacob{
2095163899Smjacob	int s;
2096163899Smjacob	struct fw_device *fwdev, *next;
2097163899Smjacob
2098163899Smjacob	s = splfw();
2099238869Smjacob	fc->status = FWBUSEXPLORE;
2100238869Smjacob	fc->retry_count = 0;
2101238869Smjacob
2102238869Smjacob/*
2103238869Smjacob * Invalidate all devices, just after bus reset. Devices
2104238869Smjacob * to be removed has not been seen longer time.
2105238869Smjacob */
2106238869Smjacob	for(fwdev = TAILQ_FIRST(&fc->devices); fwdev != NULL; fwdev = next) {
2107238869Smjacob		next = TAILQ_NEXT(fwdev, link);
2108238869Smjacob		if(fwdev->status != FWDEVINVAL){
2109238869Smjacob			fwdev->status = FWDEVINVAL;
2110238869Smjacob			fwdev->rcnt = 0;
2111238869Smjacob		}else if(fwdev->rcnt < FW_MAXDEVRCNT){
2112238869Smjacob			fwdev->rcnt ++;
2113238869Smjacob		}else{
2114196008Smjacob			TAILQ_REMOVE(&fc->devices, fwdev, link);
2115285459Smav			free(fwdev, M_DEVBUF);
2116196008Smjacob		}
2117196008Smjacob	}
2118291080Smav	fc->ongonode = 0;
2119196008Smjacob	fc->ongoaddr = CSRROMOFF;
2120291080Smav	fc->ongodev = NULL;
2121196008Smjacob	fc->ongoeui.hi = 0xffffffff; fc->ongoeui.lo = 0xffffffff;
2122196008Smjacob	fw_bus_explore(fc);
2123285459Smav	splx(s);
2124284681Smav}
2125196008Smjacob
2126291080Smav/*
2127291080Smav * To collect device informations on the IEEE1394 bus.
2128291080Smav */
2129291080Smavstatic void
2130291080Smavfw_bus_explore(struct firewire_comm *fc )
2131291080Smav{
2132291080Smav	int err = 0;
2133291080Smav	struct fw_device *fwdev, *tfwdev;
2134291080Smav	u_int32_t addr;
2135291080Smav	struct fw_xfer *xfer;
2136291080Smav	struct fw_pkt *fp;
2137291080Smav
2138291080Smav	if(fc->status != FWBUSEXPLORE)
2139291080Smav		return;
2140291080Smav
2141291080Smavloop:
2142291080Smav	if(fc->ongonode == fc->nodeid) fc->ongonode++;
2143285459Smav
2144284681Smav	if(fc->ongonode > fc->max_node) goto done;
2145291080Smav	if(fc->ongonode >= 0x3f) goto done;
2146284681Smav
2147284681Smav	/* check link */
2148196008Smjacob	/* XXX we need to check phy_id first */
2149196008Smjacob	if (!fc->topology_map->self_id[fc->ongonode].p0.link_active) {
2150196008Smjacob		printf("fw_bus_explore: node %d link down\n", fc->ongonode);
2151196008Smjacob		fc->ongonode++;
2152196008Smjacob		goto loop;
2153196008Smjacob	}
2154291080Smav
2155291080Smav	if(fc->ongoaddr <= CSRROMOFF &&
2156196008Smjacob		fc->ongoeui.hi == 0xffffffff &&
2157291080Smav		fc->ongoeui.lo == 0xffffffff ){
2158196008Smjacob		fc->ongoaddr = CSRROMOFF;
2159196008Smjacob		addr = 0xf0000000 | fc->ongoaddr;
2160285459Smav	}else if(fc->ongoeui.hi == 0xffffffff ){
2161285459Smav		fc->ongoaddr = CSRROMOFF + 0xc;
2162285459Smav		addr = 0xf0000000 | fc->ongoaddr;
2163285459Smav	}else if(fc->ongoeui.lo == 0xffffffff ){
2164285459Smav		fc->ongoaddr = CSRROMOFF + 0x10;
2165285459Smav		addr = 0xf0000000 | fc->ongoaddr;
2166285459Smav	}else if(fc->ongodev == NULL){
2167285459Smav		for(fwdev = TAILQ_FIRST(&fc->devices); fwdev != NULL;
2168285459Smav			fwdev = TAILQ_NEXT(fwdev, link)){
2169196008Smjacob			if(fwdev->eui.hi == fc->ongoeui.hi && fwdev->eui.lo == fc->ongoeui.lo){
2170196008Smjacob				break;
2171196008Smjacob			}
2172196008Smjacob		}
2173196008Smjacob		if(fwdev != NULL){
2174291080Smav			fwdev->dst = fc->ongonode;
2175291080Smav			fwdev->status = FWDEVATTACHED;
2176196008Smjacob			fc->ongonode++;
2177291080Smav			fc->ongoaddr = CSRROMOFF;
2178196008Smjacob			fc->ongodev = NULL;
2179196008Smjacob			fc->ongoeui.hi = 0xffffffff; fc->ongoeui.lo = 0xffffffff;
2180285459Smav			goto loop;
2181196008Smjacob		}
2182196008Smjacob		fwdev = malloc(sizeof(struct fw_device), M_DEVBUF, M_DONTWAIT);
2183285459Smav		if(fwdev == NULL)
2184196008Smjacob			return;
2185291080Smav		fwdev->fc = fc;
2186196008Smjacob		fwdev->rommax = 0;
2187196008Smjacob		fwdev->dst = fc->ongonode;
2188196008Smjacob		fwdev->eui.hi = fc->ongoeui.hi; fwdev->eui.lo = fc->ongoeui.lo;
2189196008Smjacob		fwdev->status = FWDEVINIT;
2190196008Smjacob#if 0
2191196008Smjacob		fwdev->speed = CSRARC(fc, SPED_MAP + 8 + fc->ongonode / 4)
2192196008Smjacob			>> ((3 - (fc->ongonode % 4)) * 8);
2193291080Smav#else
2194155228Smjacob		fwdev->speed = fc->speed_map->speed[fc->nodeid][fc->ongonode];
2195196008Smjacob#endif
2196196008Smjacob
2197196008Smjacob		tfwdev = TAILQ_FIRST(&fc->devices);
2198196008Smjacob		while( tfwdev != NULL &&
2199196008Smjacob			(tfwdev->eui.hi > fwdev->eui.hi) &&
2200196008Smjacob			((tfwdev->eui.hi == fwdev->eui.hi) &&
2201196008Smjacob				tfwdev->eui.lo > fwdev->eui.lo)){
2202290993Smav			tfwdev = TAILQ_NEXT( tfwdev, link);
2203297991Smav		}
2204196008Smjacob		if(tfwdev == NULL){
2205196008Smjacob			TAILQ_INSERT_TAIL(&fc->devices, fwdev, link);
2206196008Smjacob		}else{
2207196008Smjacob			TAILQ_INSERT_BEFORE(tfwdev, fwdev, link);
2208196008Smjacob		}
2209196008Smjacob
2210196008Smjacob		printf("%s:Discover new %s device ID:%08x%08x\n", device_get_nameunit(fc->dev), linkspeed[fwdev->speed], fc->ongoeui.hi, fc->ongoeui.lo);
2211196008Smjacob
2212196008Smjacob		fc->ongodev = fwdev;
2213196008Smjacob		fc->ongoaddr = CSRROMOFF;
2214196008Smjacob		addr = 0xf0000000 | fc->ongoaddr;
2215196008Smjacob	}else{
2216196008Smjacob		addr = 0xf0000000 | fc->ongoaddr;
2217289838Smav	}
2218289838Smav#if 0
2219196008Smjacob	xfer = asyreqq(fc, FWSPD_S100, 0, 0,
2220238869Smjacob		((FWLOCALBUS | fc->ongonode) << 16) | 0xffff , addr,
2221196008Smjacob		fw_bus_explore_callback);
2222196008Smjacob	if(xfer == NULL) goto done;
2223285459Smav#else
2224196008Smjacob	xfer = fw_xfer_alloc();
2225196008Smjacob	if(xfer == NULL){
2226196008Smjacob		goto done;
2227285459Smav	}
2228285459Smav	xfer->send.len = 16;
2229289838Smav	xfer->spd = 0;
2230196008Smjacob	xfer->send.buf = malloc(16, M_DEVBUF, M_DONTWAIT);
2231196008Smjacob	if(xfer->send.buf == NULL){
2232196008Smjacob		fw_xfer_free( xfer);
2233284681Smav		return;
2234284681Smav	}
2235284681Smav
2236284681Smav	xfer->send.off = 0;
2237284681Smav	fp = (struct fw_pkt *)xfer->send.buf;
2238291080Smav	fp->mode.rreqq.dest_hi = htons(0xffff);
2239291144Smav	fp->mode.rreqq.tlrt = 0;
2240285459Smav	fp->mode.rreqq.tcode = FWTCODE_RREQQ;
2241285459Smav	fp->mode.rreqq.pri = 0;
2242285459Smav	fp->mode.rreqq.src = 0;
2243291144Smav	xfer->dst = FWLOCALBUS | fc->ongonode;
2244291144Smav	fp->mode.rreqq.dst = htons(xfer->dst);
2245284681Smav	fp->mode.rreqq.dest_lo = htonl(addr);
2246285459Smav	xfer->act.hand = fw_bus_explore_callback;
2247285459Smav
2248284681Smav	err = fw_asyreq(fc, -1, xfer);
2249284681Smav	if(err){
2250284681Smav		fw_xfer_free( xfer);
2251284681Smav		return;
2252285459Smav	}
2253285459Smav#endif
2254284681Smav	return;
2255284681Smavdone:
2256284681Smav	/* fw_attach_devs */
2257284681Smav	fc->status = FWBUSEXPDONE;
2258196008Smjacob	printf("bus_explore done\n");
2259285459Smav	fw_attach_dev(fc);
2260285459Smav	return;
2261196008Smjacob
2262289838Smav}
2263196008Smjacob
2264284681Smav/* Portable Async. request read quad */
2265285459Smavstruct fw_xfer *
2266289838Smavasyreqq(struct firewire_comm *fc, u_int8_t spd, u_int8_t tl, u_int8_t rt,
2267285459Smav	u_int32_t addr_hi, u_int32_t addr_lo,
2268289838Smav	void (*hand) __P((struct fw_xfer*)))
2269289838Smav{
2270284681Smav	struct fw_xfer *xfer;
2271285459Smav	struct fw_pkt *fp;
2272289838Smav	int err;
2273285459Smav
2274284681Smav	xfer = fw_xfer_alloc();
2275289838Smav	if(xfer == NULL){
2276284681Smav		return NULL;
2277284681Smav	}
2278196008Smjacob	xfer->send.len = 16;
2279289838Smav	xfer->spd = spd; /* XXX:min(spd, fc->spd) */
2280285459Smav	xfer->send.buf = malloc(16, M_DEVBUF, M_DONTWAIT);
2281196008Smjacob	if(xfer->send.buf == NULL){
2282289838Smav		fw_xfer_free( xfer);
2283289838Smav		return NULL;
2284289838Smav	}
2285289838Smav
2286289838Smav	xfer->send.off = 0;
2287289838Smav	fp = (struct fw_pkt *)xfer->send.buf;
2288289838Smav	fp->mode.rreqq.dest_hi = htons(addr_hi & 0xffff);
2289289838Smav	if(tl & FWP_TL_VALID){
2290289838Smav		fp->mode.rreqq.tlrt = (tl & 0x3f) << 2;
2291289838Smav	}else{
2292289838Smav		fp->mode.rreqq.tlrt = 0;
2293289838Smav	}
2294289838Smav	fp->mode.rreqq.tlrt |= rt & 0x3;
2295289838Smav	fp->mode.rreqq.tcode = FWTCODE_RREQQ;
2296289838Smav	fp->mode.rreqq.pri = 0;
2297289838Smav	fp->mode.rreqq.src = 0;
2298289838Smav	xfer->dst = addr_hi >> 16;
2299289838Smav	fp->mode.rreqq.dst = htons(xfer->dst);
2300285459Smav	fp->mode.rreqq.dest_lo = htonl(addr_lo);
2301285459Smav	xfer->act.hand = hand;
2302284681Smav
2303285459Smav	err = fw_asyreq(fc, -1, xfer);
2304285459Smav	if(err){
2305284681Smav		fw_xfer_free( xfer);
2306285459Smav		return NULL;
2307285459Smav	}
2308285459Smav	return xfer;
2309238869Smjacob}
2310285459Smav
2311285459Smav/*
2312285459Smav * Callback for the IEEE1394 bus information collection.
2313285459Smav */
2314284681Smavstatic void
2315285459Smavfw_bus_explore_callback(struct fw_xfer *xfer)
2316285459Smav{
2317285459Smav	struct firewire_comm *fc;
2318196008Smjacob	struct fw_pkt *sfp,*rfp;
2319285459Smav	struct csrhdr *chdr;
2320285459Smav	struct csrdir *csrd;
2321285459Smav	struct csrreg *csrreg;
2322285459Smav	u_int32_t offset;
2323285459Smav
2324285459Smav
2325285459Smav	if(xfer == NULL) return;
2326285459Smav	fc = xfer->fc;
2327285459Smav	if(xfer->resp != 0){
2328284681Smav		printf("resp != 0: node=%d addr=0x%x\n",
2329285459Smav			fc->ongonode, fc->ongoaddr);
2330285459Smav		fc->retry_count++;
2331196008Smjacob		goto nextnode;
2332285459Smav	}
2333284681Smav
2334284681Smav	if(xfer->send.buf == NULL){
2335284681Smav		printf("send.buf == NULL: node=%d addr=0x%x\n",
2336285459Smav			fc->ongonode, fc->ongoaddr);
2337285459Smav		printf("send.buf == NULL\n");
2338285459Smav		fc->retry_count++;
2339196008Smjacob		goto nextnode;
2340285459Smav	}
2341284681Smav	sfp = (struct fw_pkt *)xfer->send.buf;
2342285459Smav
2343284681Smav	if(xfer->recv.buf == NULL){
2344289838Smav		printf("recv.buf == NULL: node=%d addr=0x%x\n",
2345284681Smav			fc->ongonode, fc->ongoaddr);
2346284681Smav		fc->retry_count++;
2347196008Smjacob		goto nextnode;
2348196008Smjacob	}
2349196008Smjacob	rfp = (struct fw_pkt *)xfer->recv.buf;
2350284681Smav#if 0
2351285459Smav	{
2352196008Smjacob		u_int32_t *qld;
2353196008Smjacob		int i;
2354196008Smjacob		qld = (u_int32_t *)xfer->recv.buf;
2355289838Smav		printf("len:%d\n", xfer->recv.len);
2356289838Smav		for( i = 0 ; i <= xfer->recv.len && i < 32; i+= 4){
2357285459Smav			printf("0x%08x ", ntohl(rfp->mode.ld[i/4]));
2358284681Smav			if((i % 16) == 15) printf("\n");
2359284681Smav		}
2360238869Smjacob		if((i % 16) != 15) printf("\n");
2361285459Smav	}
2362285459Smav#endif
2363289838Smav	if(fc->ongodev == NULL){
2364196008Smjacob		if(sfp->mode.rreqq.dest_lo == htonl((0xf0000000 | CSRROMOFF))){
2365285459Smav			rfp->mode.rresq.data = ntohl(rfp->mode.rresq.data);
2366285459Smav			chdr = (struct csrhdr *)(&rfp->mode.rresq.data);
2367196008Smjacob/* If CSR is minimul confinguration, more investgation is not needed. */
2368196008Smjacob			if(chdr->info_len == 1){
2369196008Smjacob				goto nextnode;
2370196008Smjacob			}else{
2371196008Smjacob				fc->ongoaddr = CSRROMOFF + 0xc;
2372196008Smjacob			}
2373289838Smav		}else if(sfp->mode.rreqq.dest_lo == htonl((0xf0000000 |(CSRROMOFF + 0xc)))){
2374196008Smjacob			fc->ongoeui.hi = ntohl(rfp->mode.rresq.data);
2375196008Smjacob			fc->ongoaddr = CSRROMOFF + 0x10;
2376196008Smjacob		}else if(sfp->mode.rreqq.dest_lo == htonl((0xf0000000 |(CSRROMOFF + 0x10)))){
2377196008Smjacob			fc->ongoeui.lo = ntohl(rfp->mode.rresq.data);
2378196008Smjacob			if (fc->ongoeui.hi == 0 && fc->ongoeui.lo == 0)
2379285459Smav				goto nextnode;
2380289838Smav			fc->ongoaddr = CSRROMOFF;
2381196008Smjacob		}
2382196008Smjacob	}else{
2383196008Smjacob		fc->ongodev->csrrom[(fc->ongoaddr - CSRROMOFF)/4] = ntohl(rfp->mode.rresq.data);
2384196008Smjacob		if(fc->ongoaddr > fc->ongodev->rommax){
2385285459Smav			fc->ongodev->rommax = fc->ongoaddr;
2386285459Smav		}
2387289838Smav		csrd = SLIST_FIRST(&fc->ongocsr);
2388196008Smjacob		if((csrd = SLIST_FIRST(&fc->ongocsr)) == NULL){
2389196008Smjacob			chdr = (struct csrhdr *)(fc->ongodev->csrrom);
2390196008Smjacob			offset = CSRROMOFF;
2391285459Smav		}else{
2392285459Smav			chdr = (struct csrhdr *)&fc->ongodev->csrrom[(csrd->off - CSRROMOFF)/4];
2393285459Smav			offset = csrd->off;
2394196008Smjacob		}
2395285459Smav		if(fc->ongoaddr > (CSRROMOFF + 0x14) && fc->ongoaddr != offset){
2396285459Smav			csrreg = (struct csrreg *)&fc->ongodev->csrrom[(fc->ongoaddr - CSRROMOFF)/4];
2397196008Smjacob			if( csrreg->key == 0x81 || csrreg->key == 0xd1){
2398196008Smjacob				csrd = SLIST_FIRST(&fc->csrfree);
2399196008Smjacob				if(csrd == NULL){
2400196008Smjacob					goto nextnode;
2401196008Smjacob				}else{
2402196008Smjacob					csrd->ongoaddr = fc->ongoaddr;
2403196008Smjacob					fc->ongoaddr += csrreg->val * 4;
2404196008Smjacob					csrd->off = fc->ongoaddr;
2405196008Smjacob					SLIST_REMOVE_HEAD(&fc->csrfree, link);
2406196008Smjacob					SLIST_INSERT_HEAD(&fc->ongocsr, csrd, link);
2407196008Smjacob					goto nextaddr;
2408196008Smjacob				}
2409196008Smjacob			}
2410196008Smjacob		}
2411196008Smjacob		fc->ongoaddr += 4;
2412196008Smjacob		if(((fc->ongoaddr - offset)/4 > chdr->crc_len) &&
2413196008Smjacob				(fc->ongodev->rommax < 0x414)){
2414196008Smjacob			if(fc->ongodev->rommax <= 0x414){
2415196008Smjacob				csrd = SLIST_FIRST(&fc->csrfree);
2416196008Smjacob				if(csrd == NULL) goto nextnode;
2417196008Smjacob				csrd->off = fc->ongoaddr;
2418196008Smjacob				csrd->ongoaddr = fc->ongoaddr;
2419196008Smjacob				SLIST_REMOVE_HEAD(&fc->csrfree, link);
2420196008Smjacob				SLIST_INSERT_HEAD(&fc->ongocsr, csrd, link);
2421196008Smjacob			}
2422196008Smjacob			goto nextaddr;
2423196008Smjacob		}
2424196008Smjacob
2425196008Smjacob		while(((fc->ongoaddr - offset)/4 > chdr->crc_len)){
2426196008Smjacob			if(csrd == NULL){
2427285459Smav				goto nextnode;
2428285459Smav			};
2429285459Smav			fc->ongoaddr = csrd->ongoaddr + 4;
2430285459Smav			SLIST_REMOVE_HEAD(&fc->ongocsr, link);
2431196008Smjacob			SLIST_INSERT_HEAD(&fc->csrfree, csrd, link);
2432196008Smjacob			csrd = SLIST_FIRST(&fc->ongocsr);
2433196008Smjacob			if((csrd = SLIST_FIRST(&fc->ongocsr)) == NULL){
2434196008Smjacob				chdr = (struct csrhdr *)(fc->ongodev->csrrom);
2435196008Smjacob				offset = CSRROMOFF;
2436196008Smjacob			}else{
2437196008Smjacob				chdr = (struct csrhdr *)&(fc->ongodev->csrrom[(csrd->off - CSRROMOFF)/4]);
2438196008Smjacob				offset = csrd->off;
2439196008Smjacob			}
2440196008Smjacob		}
2441196008Smjacob		if((fc->ongoaddr - CSRROMOFF) > CSRROMSIZE){
2442196008Smjacob			goto nextnode;
2443196008Smjacob		}
2444196008Smjacob	}
2445196008Smjacobnextaddr:
2446196008Smjacob	fw_xfer_free( xfer);
2447196008Smjacob	fw_bus_explore(fc);
2448196008Smjacob	return;
2449196008Smjacobnextnode:
2450196008Smjacob	fw_xfer_free( xfer);
2451196008Smjacob	fc->ongonode++;
2452196008Smjacob/* housekeeping work space */
2453196008Smjacob	fc->ongoaddr = CSRROMOFF;
2454196008Smjacob	fc->ongodev = NULL;
2455196008Smjacob	fc->ongoeui.hi = 0xffffffff; fc->ongoeui.lo = 0xffffffff;
2456196008Smjacob	while((csrd = SLIST_FIRST(&fc->ongocsr)) != NULL){
2457196008Smjacob		SLIST_REMOVE_HEAD(&fc->ongocsr, link);
2458285459Smav		SLIST_INSERT_HEAD(&fc->csrfree, csrd, link);
2459196008Smjacob	}
2460196008Smjacob	fw_bus_explore(fc);
2461196008Smjacob	return;
2462196008Smjacob}
2463291144Smav#if 0
2464291080Smav/*
2465196008Smjacob * Async. write responce support for kernel internal use.
2466196008Smjacob */
2467196008Smjacobint
2468196008Smjacobfw_writeres(struct firewire_comm *fc, u_int32_t dst, u_int32_t tlrt)
2469291144Smav{
2470291080Smav	int err = 0;
2471196008Smjacob	struct fw_xfer *xfer;
2472196008Smjacob	struct fw_pkt *fp;
2473196008Smjacob
2474196008Smjacob	xfer = fw_xfer_alloc();
2475285459Smav	if(xfer == NULL){
2476285459Smav		err = ENOMEM;
2477196008Smjacob		return err;
2478196008Smjacob	}
2479196008Smjacob	xfer->send.len = 12;
2480163899Smjacob	xfer->spd = 0;
2481155228Smjacob	xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT);
2482155228Smjacob	if(xfer->send.buf == NULL){
2483163899Smjacob		return ENOMEM;
2484163899Smjacob	}
2485163899Smjacob	xfer->send.off = 0;
2486163899Smjacob	fp = (struct fw_pkt *)xfer->send.buf;
2487163899Smjacob
2488163899Smjacob	fp->mode.wres.tlrt = tlrt;
2489163899Smjacob	fp->mode.wres.tcode = FWTCODE_WRES;
2490163899Smjacob	fp->mode.wres.pri = 0;
2491163899Smjacob	fp->mode.wres.dst = htons(dst);
2492163899Smjacob
2493163899Smjacob	xfer->act.hand = fw_asy_callback;
2494155228Smjacob	err = fw_asyreq(fc, -1, xfer);
2495163899Smjacob	if(err){
2496155228Smjacob		fw_xfer_free( xfer);
2497163899Smjacob		return err;
2498163899Smjacob	}
2499155228Smjacob	err = tsleep((caddr_t)xfer, FWPRI, "asyreq", 0);
2500163899Smjacob	fw_xfer_free( xfer);
2501155228Smjacob
2502155228Smjacob	return err;
2503196008Smjacob}
2504155228Smjacob
2505163899Smjacob/*
2506155228Smjacob * Async. read responce block support for kernel internal use.
2507155228Smjacob */
2508155228Smjacobint
2509163899Smjacobfw_readresb(struct firewire_comm *fc, u_int32_t dst, u_int32_t tlrt,
2510155228Smjacob	u_int32_t len, u_int32_t *buf)
2511155228Smjacob{
2512163899Smjacob	int err = 0;
2513163899Smjacob	struct fw_xfer *xfer ;
2514163899Smjacob	struct fw_pkt *fp;
2515163899Smjacob
2516163899Smjacob	xfer = fw_xfer_alloc();
2517163899Smjacob	if(xfer == NULL){
2518163899Smjacob		err = ENOMEM;
2519163899Smjacob		return err;
2520163899Smjacob	}
2521163899Smjacob	xfer->send.len = sizeof(struct fw_pkt) + len;
2522155228Smjacob	xfer->spd = 0;
2523163899Smjacob	xfer->send.buf = malloc(sizeof(struct fw_pkt) + 1024, M_DEVBUF, M_DONTWAIT);
2524155228Smjacob	if(xfer->send.buf == NULL){
2525163899Smjacob		return ENOMEM;
2526163899Smjacob	}
2527155228Smjacob	xfer->send.off = 0;
2528163899Smjacob	fp = (struct fw_pkt *)xfer->send.buf;
2529155228Smjacob	fp->mode.rresb.tlrt = tlrt;
2530155228Smjacob	fp->mode.rresb.tcode = FWTCODE_RRESB;
2531196008Smjacob	fp->mode.rresb.pri = 0;
2532155228Smjacob	fp->mode.rresb.dst = htons(dst);
2533163899Smjacob	fp->mode.rresb.rtcode = 0;
2534155228Smjacob	fp->mode.rresb.extcode = 0;
2535155228Smjacob	fp->mode.rresb.len = htons(len);
2536155228Smjacob	bcopy(buf, fp->mode.rresb.payload, len);
2537163899Smjacob	xfer->act.hand = fw_asy_callback;
2538155228Smjacob	err = fw_asyreq(fc, -1, xfer);
2539155228Smjacob	if(err){
2540163899Smjacob		fw_xfer_free( xfer);
2541163899Smjacob		return err;
2542163899Smjacob	}
2543163899Smjacob	err = tsleep((caddr_t)xfer, FWPRI, "asyreq", 0);
2544163899Smjacob
2545163899Smjacob	fw_xfer_free( xfer);
2546163899Smjacob	return err;
2547163899Smjacob}
2548163899Smjacob
2549163899Smjacob/*
2550163899Smjacob * Async. write request block support for kernel internal use.
2551155228Smjacob */
2552163899Smjacobint
2553155228Smjacobfw_writereqb(struct firewire_comm *fc, u_int32_t addr_hi, u_int32_t addr_lo,
2554163899Smjacob	u_int len, u_int32_t *buf)
2555163899Smjacob{
2556155228Smjacob	int err = 0;
2557163899Smjacob	struct fw_xfer *xfer ;
2558155228Smjacob	struct fw_pkt *fp;
2559155228Smjacob
2560196008Smjacob	xfer = fw_xfer_alloc();
2561155228Smjacob	if(xfer == NULL){
2562163899Smjacob		err = ENOMEM;
2563155228Smjacob		return err;
2564155228Smjacob	}
2565155228Smjacob	xfer->send.len = sizeof(struct fw_pkt) + len;
2566163899Smjacob	xfer->spd = 0;
2567155228Smjacob	xfer->send.buf = malloc(sizeof(struct fw_pkt) + 1024, M_DEVBUF, M_DONTWAIT);
2568155228Smjacob	if(xfer->send.buf == NULL){
2569163899Smjacob		return ENOMEM;
2570163899Smjacob	}
2571163899Smjacob	xfer->send.off = 0;
2572163899Smjacob	fp = (struct fw_pkt *)xfer->send.buf;
2573163899Smjacob	fp->mode.wreqb.dest_hi = htonl(addr_hi & 0xffff);
2574163899Smjacob	fp->mode.wreqb.tlrt = 0;
2575163899Smjacob	fp->mode.wreqb.tcode = FWTCODE_WREQB;
2576163899Smjacob	fp->mode.wreqb.pri = 0;
2577163899Smjacob	fp->mode.wreqb.dst = htons(addr_hi >> 16);
2578163899Smjacob	fp->mode.wreqb.dest_lo = htonl(addr_lo);
2579155228Smjacob	fp->mode.wreqb.len = htons(len);
2580163899Smjacob	fp->mode.wreqb.extcode = 0;
2581155228Smjacob	bcopy(buf, fp->mode.wreqb.payload, len);
2582163899Smjacob	xfer->act.hand = fw_asy_callback;
2583163899Smjacob	err = fw_asyreq(fc, -1, xfer);
2584155228Smjacob	if(err){
2585163899Smjacob		fw_xfer_free( xfer);
2586155228Smjacob		return err;
2587155228Smjacob	}
2588196008Smjacob	err = tsleep((caddr_t)xfer, FWPRI, "asyreq", 0);
2589155228Smjacob
2590163899Smjacob	fw_xfer_free( xfer);
2591155228Smjacob	return err;
2592155228Smjacob}
2593155228Smjacob
2594163899Smjacob/*
2595155228Smjacob * Async. read request support for kernel internal use.
2596163899Smjacob */
2597163899Smjacobint
2598163899Smjacobfw_readreqq(struct firewire_comm *fc, u_int32_t addr_hi, u_int32_t addr_lo, u_int32_t *ret){
2599163899Smjacob	int err = 0;
2600163899Smjacob	struct fw_xfer *xfer ;
2601163899Smjacob	struct fw_pkt *fp, *rfp;
2602163899Smjacob
2603163899Smjacob	xfer = fw_xfer_alloc();
2604163899Smjacob	if(xfer == NULL){
2605163899Smjacob		err = ENOMEM;
2606155228Smjacob		return err;
2607155228Smjacob	}
2608163899Smjacob	xfer->send.len = 16;
2609163899Smjacob	xfer->spd = 0;
2610163899Smjacob	xfer->send.buf = malloc(16, M_DEVBUF, M_DONTWAIT);
2611163899Smjacob	if(xfer->send.buf == NULL){
2612163899Smjacob		return ENOMEM;
2613163899Smjacob	}
2614163899Smjacob	xfer->send.off = 0;
2615163899Smjacob	fp = (struct fw_pkt *)xfer->send.buf;
2616163899Smjacob	fp->mode.rreqq.dest_hi = htonl(addr_hi & 0xffff);
2617163899Smjacob	fp->mode.rreqq.tlrt = 0;
2618163899Smjacob	fp->mode.rreqq.tcode = FWTCODE_RREQQ;
2619196008Smjacob	fp->mode.rreqq.pri = 0;
2620196008Smjacob	xfer->dst = addr_hi >> 16;
2621196008Smjacob	fp->mode.rreqq.dst = htons(xfer->dst);
2622196008Smjacob	fp->mode.rreqq.dest_lo = htonl(addr_lo);
2623163899Smjacob	xfer->act.hand = fw_asy_callback;
2624155228Smjacob	err = fw_asyreq(fc, -1, xfer);
2625196008Smjacob	if(err){
2626196008Smjacob		fw_xfer_free( xfer);
2627155228Smjacob		return err;
2628163899Smjacob	}
2629155228Smjacob	err = tsleep((caddr_t)xfer, FWPRI, "asyreq", 0);
2630196008Smjacob
2631196008Smjacob	if(err == 0 && xfer->recv.buf != NULL){
2632196008Smjacob		rfp = (struct fw_pkt *)xfer->recv.buf;
2633155228Smjacob		*ret = ntohl(rfp->mode.rresq.data);
2634163899Smjacob	}
2635196008Smjacob	fw_xfer_free( xfer);
2636163899Smjacob	return err;
2637196008Smjacob}
2638155228Smjacob#endif
2639163899Smjacob/*
2640196008Smjacob * To obtain CSR register values.
2641196008Smjacob */
2642196008Smjacobu_int32_t getcsrdata(struct fw_device *fwdev, u_int8_t key)
2643196008Smjacob{
2644196008Smjacob	int i;
2645155228Smjacob	struct csrhdr *chdr;
2646196008Smjacob	struct csrreg *creg;
2647155228Smjacob	chdr = (struct csrhdr *)&fwdev->csrrom[0];
2648155228Smjacob	for( i = chdr->info_len + 4; i <= fwdev->rommax - CSRROMOFF; i+=4){
2649196008Smjacob		creg = (struct csrreg *)&fwdev->csrrom[i/4];
2650196008Smjacob		if(creg->key == key){
2651196008Smjacob			return (u_int32_t)creg->val;
2652196008Smjacob		}
2653238869Smjacob	}
2654238869Smjacob	return 0;
2655238869Smjacob}
2656238869Smjacob/*
2657238869Smjacob * To attach sub-devices layer onto IEEE1394 bus.
2658238869Smjacob */
2659238869Smjacobstatic void fw_attach_dev(struct firewire_comm *fc)
2660238869Smjacob{
2661155228Smjacob	struct fw_device *fwdev;
2662155228Smjacob	struct fw_xfer *xfer;
2663155228Smjacob	int i, err;
2664155228Smjacob	device_t *devlistp;
2665163899Smjacob	int devcnt;
2666155228Smjacob	struct firewire_dev_comm *fdc;
2667155228Smjacob
2668163899Smjacob	for(fwdev = TAILQ_FIRST(&fc->devices); fwdev != NULL;
2669163899Smjacob			fwdev = TAILQ_NEXT(fwdev, link)){
2670163899Smjacob		if(fwdev->status == FWDEVINIT){
2671163899Smjacob			fwdev->spec = getcsrdata(fwdev, CSRKEY_SPEC);
2672163899Smjacob			if(fwdev->spec == 0)
2673163899Smjacob				continue;
2674163899Smjacob			fwdev->ver = getcsrdata(fwdev, CSRKEY_VER);
2675163899Smjacob			if(fwdev->ver == 0)
2676163899Smjacob				continue;
2677163899Smjacob			fwdev->maxrec = (fwdev->csrrom[2] >> 12) & 0xf;
2678196008Smjacob
2679196008Smjacob			switch(fwdev->spec){
2680196008Smjacob			case CSRVAL_ANSIT10:
2681196008Smjacob				switch(fwdev->ver){
2682163899Smjacob				case CSRVAL_T10SBP2:
2683155228Smjacob					printf("Device SBP-II");
2684196008Smjacob					break;
2685196008Smjacob				default:
2686155228Smjacob					break;
2687163899Smjacob				}
2688155228Smjacob				break;
2689196008Smjacob			case CSRVAL_1394TA:
2690196008Smjacob				switch(fwdev->ver){
2691196008Smjacob				case CSR_PROTAVC:
2692155228Smjacob					printf("Device AV/C");
2693163899Smjacob					break;
2694196008Smjacob				case CSR_PROTCAL:
2695196008Smjacob					printf("Device CAL");
2696196008Smjacob					break;
2697155228Smjacob				case CSR_PROTEHS:
2698163899Smjacob					printf("Device EHS");
2699196008Smjacob					break;
2700196008Smjacob				case CSR_PROTHAVI:
2701196008Smjacob					printf("Device HAVi");
2702196008Smjacob					break;
2703196008Smjacob				case CSR_PROTCAM104:
2704155228Smjacob					printf("Device 1394 Cam 1.04");
2705196008Smjacob					break;
2706155228Smjacob				case CSR_PROTCAM120:
2707155228Smjacob					printf("Device 1394 Cam 1.20");
2708196008Smjacob					break;
2709196008Smjacob				case CSR_PROTCAM130:
2710196008Smjacob					printf("Device 1394 Cam 1.30");
2711196008Smjacob					break;
2712238869Smjacob				case CSR_PROTDPP:
2713238869Smjacob					printf("Device 1394 Direct print");
2714238869Smjacob					break;
2715238869Smjacob				case CSR_PROTIICP:
2716238869Smjacob					printf("Device Industrial & Instrument");
2717238869Smjacob					break;
2718238869Smjacob				default:
2719238869Smjacob					printf("Device unkwon 1394TA");
2720155228Smjacob					break;
2721155228Smjacob				}
2722155228Smjacob				break;
2723155228Smjacob			default:
2724163899Smjacob				break;
2725155228Smjacob			}
2726163899Smjacob			fwdev->status = FWDEVATTACHED;
2727163899Smjacob			printf("\n");
2728163899Smjacob		}
2729163899Smjacob	}
2730163899Smjacob	err = device_get_children(fc->dev, &devlistp, &devcnt);
2731163899Smjacob	if( err != 0 )
2732163899Smjacob		return;
2733196008Smjacob	for( i = 0 ; i < devcnt ; i++){
2734163899Smjacob		if (device_get_state(devlistp[i]) >= DS_ATTACHED)  {
2735163899Smjacob			fdc = device_get_softc(devlistp[i]);
2736163899Smjacob			if (fdc->post_explore != NULL)
2737163899Smjacob				fdc->post_explore(fdc);
2738163899Smjacob		}
2739163899Smjacob	}
2740163899Smjacob	free(devlistp, M_TEMP);
2741163899Smjacob
2742163899Smjacob	/* call pending handlers */
2743163899Smjacob	i = 0;
2744163899Smjacob	while ((xfer = STAILQ_FIRST(&fc->pending))) {
2745163899Smjacob		STAILQ_REMOVE_HEAD(&fc->pending, link);
2746196008Smjacob		i++;
2747196008Smjacob		if (xfer->act.hand)
2748196008Smjacob			xfer->act.hand(xfer);
2749196008Smjacob	}
2750196008Smjacob	if (i > 0)
2751196008Smjacob		printf("fw_attach_dev: %d pending handlers called\n", i);
2752163899Smjacob	if (fc->retry_count > 0) {
2753196008Smjacob		printf("retry_count = %d\n", fc->retry_count);
2754196008Smjacob		fc->retry_probe_handle = timeout((timeout_t *)fc->ibr,
2755196008Smjacob							(void *)fc, hz*2);
2756163899Smjacob	}
2757196008Smjacob	return;
2758196008Smjacob}
2759196008Smjacob/*
2760196008Smjacob * To allocate uniq transaction label.
2761163899Smjacob */
2762163899Smjacobstatic int fw_get_tlabel(struct firewire_comm *fc, struct fw_xfer *xfer)
2763196008Smjacob{
2764238869Smjacob	u_int i;
2765196008Smjacob	struct tlabel *tl, *tmptl;
2766238869Smjacob	int s;
2767196008Smjacob	static u_int32_t label = 0;
2768196008Smjacob
2769196008Smjacob	s = splfw();
2770163899Smjacob	for( i = 0 ; i < 0x40 ; i ++){
2771155228Smjacob		label = (label + 1) & 0x3f;
2772155228Smjacob		for(tmptl = STAILQ_FIRST(&fc->tlabels[label]);
2773163899Smjacob			tmptl != NULL; tmptl = STAILQ_NEXT(tmptl, link)){
2774155228Smjacob			if(tmptl->xfer->dst == xfer->dst) break;
2775163899Smjacob		}
2776155228Smjacob		if(tmptl == NULL) {
2777163899Smjacob			tl = malloc(sizeof(struct tlabel),M_DEVBUF,M_DONTWAIT);
2778163899Smjacob			if (tl == NULL) {
2779163899Smjacob				splx(s);
2780163899Smjacob				return (-1);
2781163899Smjacob			}
2782163899Smjacob			tl->xfer = xfer;
2783163899Smjacob			STAILQ_INSERT_TAIL(&fc->tlabels[label], tl, link);
2784163899Smjacob			splx(s);
2785163899Smjacob			return(label);
2786163899Smjacob		}
2787163899Smjacob	}
2788163899Smjacob	splx(s);
2789163899Smjacob
2790163899Smjacob	printf("fw_get_tlabel: no free tlabel\n");
2791196008Smjacob	return(-1);
2792196008Smjacob}
2793196008Smjacob/*
2794196008Smjacob * Generic packet receving process.
2795163899Smjacob */
2796163899Smjacobvoid fw_rcv(struct firewire_comm* fc, caddr_t buf, u_int len, u_int sub, u_int off, u_int spd)
2797196008Smjacob{
2798196008Smjacob	struct fw_pkt *fp, *resfp;
2799163899Smjacob	struct fw_xfer *xfer;
2800163899Smjacob	struct fw_bind *bind;
2801163899Smjacob	struct firewire_softc *sc;
2802196008Smjacob	int s;
2803196008Smjacob#if 0
2804196008Smjacob	{
2805163899Smjacob		u_int32_t *qld;
2806163899Smjacob		int i;
2807196008Smjacob		qld = (u_int32_t *)buf;
2808196008Smjacob		printf("spd %d len:%d\n", spd, len);
2809196008Smjacob		for( i = 0 ; i <= len && i < 32; i+= 4){
2810163899Smjacob			printf("0x%08x ", ntohl(qld[i/4]));
2811163899Smjacob			if((i % 16) == 15) printf("\n");
2812196008Smjacob		}
2813196008Smjacob		if((i % 16) != 15) printf("\n");
2814196008Smjacob	}
2815196008Smjacob#endif
2816196008Smjacob	fp = (struct fw_pkt *)(buf + off);
2817163899Smjacob	switch(fp->mode.common.tcode){
2818196008Smjacob	case FWTCODE_WRES:
2819163899Smjacob	case FWTCODE_RRESQ:
2820163899Smjacob	case FWTCODE_RRESB:
2821196008Smjacob	case FWTCODE_LRES:
2822196008Smjacob		xfer = fw_tl2xfer(fc, ntohs(fp->mode.hdr.src),
2823196008Smjacob					fp->mode.hdr.tlrt >> 2);
2824196008Smjacob		if(xfer == NULL) {
2825238869Smjacob			printf("fw_rcv: unknown response "
2826238869Smjacob					"tcode=%d src=0x%x tl=%x rt=%d data=0x%x\n",
2827238869Smjacob					fp->mode.common.tcode,
2828238869Smjacob					ntohs(fp->mode.hdr.src),
2829238869Smjacob					fp->mode.hdr.tlrt >> 2,
2830238869Smjacob					fp->mode.hdr.tlrt & 3,
2831238869Smjacob					fp->mode.rresq.data);
2832238869Smjacob#if 1
2833163899Smjacob			printf("try ad-hoc work around!!\n");
2834155228Smjacob			xfer = fw_tl2xfer(fc, ntohs(fp->mode.hdr.src),
2835155228Smjacob					(fp->mode.hdr.tlrt >> 2)^3);
2836155228Smjacob			if (xfer == NULL) {
2837163899Smjacob				printf("no use...\n");
2838163899Smjacob				goto err;
2839163899Smjacob			}
2840163899Smjacob#else
2841163899Smjacob			goto err;
2842163899Smjacob#endif
2843163899Smjacob		}
2844163899Smjacob		switch(xfer->act_type){
2845163899Smjacob		case FWACT_XFER:
2846163899Smjacob			if((xfer->sub >= 0) &&
2847163899Smjacob				((fc->ir[xfer->sub]->flag & FWXFERQ_MODEMASK ) == 0)){
2848163899Smjacob				xfer->resp = EINVAL;
2849163899Smjacob				fw_xfer_done(xfer);
2850163899Smjacob				goto err;
2851163899Smjacob			}
2852196008Smjacob			xfer->recv.len = len;
2853196008Smjacob			xfer->recv.off = off;
2854196008Smjacob			xfer->recv.buf = buf;
2855196008Smjacob			xfer->resp = 0;
2856163899Smjacob			fw_xfer_done(xfer);
2857163899Smjacob			return;
2858196008Smjacob			break;
2859196008Smjacob		case FWACT_CH:
2860163899Smjacob		default:
2861163899Smjacob			goto err;
2862163899Smjacob			break;
2863196008Smjacob		}
2864196008Smjacob		break;
2865196008Smjacob	case FWTCODE_WREQQ:
2866163899Smjacob	case FWTCODE_WREQB:
2867163899Smjacob	case FWTCODE_RREQQ:
2868196008Smjacob	case FWTCODE_RREQB:
2869196008Smjacob	case FWTCODE_LREQ:
2870196008Smjacob		bind = fw_bindlookup(fc, ntohs(fp->mode.rreqq.dest_hi),
2871163899Smjacob			ntohl(fp->mode.rreqq.dest_lo));
2872163899Smjacob		if(bind == NULL){
2873196008Smjacob			printf("Unknown service addr 0x%08x:0x%08x tcode=%x\n",
2874196008Smjacob				ntohs(fp->mode.rreqq.dest_hi),
2875196008Smjacob				ntohl(fp->mode.rreqq.dest_lo),
2876196008Smjacob				fp->mode.common.tcode);
2877196008Smjacob			if (fc->status == FWBUSRESET) {
2878163899Smjacob				printf("fw_rcv: cannot response(bus reset)!\n");
2879196008Smjacob				goto err;
2880163899Smjacob			}
2881163899Smjacob			xfer = fw_xfer_alloc();
2882196008Smjacob			if(xfer == NULL){
2883196008Smjacob				return;
2884196008Smjacob			}
2885196008Smjacob			xfer->spd = spd;
2886238869Smjacob			xfer->send.buf = malloc(16, M_DEVBUF, M_DONTWAIT);
2887238869Smjacob			resfp = (struct fw_pkt *)xfer->send.buf;
2888238869Smjacob			switch(fp->mode.common.tcode){
2889238869Smjacob			case FWTCODE_WREQQ:
2890238869Smjacob			case FWTCODE_WREQB:
2891238869Smjacob				resfp->mode.hdr.tcode = FWTCODE_WRES;
2892238869Smjacob				xfer->send.len = 12;
2893238869Smjacob				break;
2894163899Smjacob			case FWTCODE_RREQQ:
2895163899Smjacob				resfp->mode.hdr.tcode = FWTCODE_RRESQ;
2896163899Smjacob				xfer->send.len = 16;
2897163899Smjacob				break;
2898163899Smjacob			case FWTCODE_RREQB:
2899163899Smjacob				resfp->mode.hdr.tcode = FWTCODE_RRESB;
2900163899Smjacob				xfer->send.len = 16;
2901163899Smjacob				break;
2902163899Smjacob			case FWTCODE_LREQ:
2903163899Smjacob				resfp->mode.hdr.tcode = FWTCODE_LRES;
2904163899Smjacob				xfer->send.len = 16;
2905163899Smjacob				break;
2906163899Smjacob			}
2907196008Smjacob			resfp->mode.hdr.dst = fp->mode.hdr.src;
2908163899Smjacob			resfp->mode.hdr.tlrt = fp->mode.hdr.tlrt;
2909163899Smjacob			resfp->mode.hdr.pri = fp->mode.hdr.pri;
2910163899Smjacob			resfp->mode.rresb.rtcode = 7;
2911163899Smjacob			resfp->mode.rresb.extcode = 0;
2912163899Smjacob			resfp->mode.rresb.len = 0;
2913163899Smjacob/*
2914163899Smjacob			xfer->act.hand = fw_asy_callback;
2915163899Smjacob*/
2916163899Smjacob			xfer->act.hand = fw_xfer_free;
2917163899Smjacob			if(fw_asyreq(fc, -1, xfer)){
2918163899Smjacob				fw_xfer_free( xfer);
2919163899Smjacob				return;
2920196008Smjacob			}
2921196008Smjacob			goto err;
2922196008Smjacob		}
2923196008Smjacob		switch(bind->xfer->act_type){
2924196008Smjacob		case FWACT_XFER:
2925196008Smjacob			xfer = fw_xfer_alloc();
2926163899Smjacob			if(xfer == NULL) goto err;
2927196008Smjacob			xfer->fc = bind->xfer->fc;
2928196008Smjacob			xfer->sc = bind->xfer->sc;
2929196008Smjacob			xfer->recv.buf = buf;
2930163899Smjacob			xfer->recv.len = len;
2931196008Smjacob			xfer->recv.off = off;
2932196008Smjacob			xfer->spd = spd;
2933163899Smjacob			xfer->act.hand = bind->xfer->act.hand;
2934196008Smjacob			if (fc->status != FWBUSRESET)
2935163899Smjacob				xfer->act.hand(xfer);
2936196008Smjacob			else
2937196008Smjacob				STAILQ_INSERT_TAIL(&fc->pending, xfer, link);
2938196008Smjacob			return;
2939163899Smjacob			break;
2940196008Smjacob		case FWACT_CH:
2941196008Smjacob			if(fc->ir[bind->xfer->sub]->queued >=
2942196008Smjacob				fc->ir[bind->xfer->sub]->maxq){
2943196008Smjacob				printf("%s:Discard a packet %x %d\n",
2944196008Smjacob					device_get_nameunit(fc->dev),
2945196008Smjacob					bind->xfer->sub,
2946163899Smjacob					fc->ir[bind->xfer->sub]->queued);
2947163899Smjacob				goto err;
2948163899Smjacob			}
2949163899Smjacob			xfer = fw_xfer_alloc();
2950196008Smjacob			if(xfer == NULL) goto err;
2951155228Smjacob			xfer->recv.buf = buf;
2952163899Smjacob			xfer->recv.len = len;
2953163899Smjacob			xfer->recv.off = off;
2954163899Smjacob			xfer->spd = spd;
2955163899Smjacob			s = splfw();
2956163899Smjacob			fc->ir[bind->xfer->sub]->queued++;
2957163899Smjacob			STAILQ_INSERT_TAIL(&fc->ir[bind->xfer->sub]->q, xfer, link);
2958163899Smjacob			splx(s);
2959163899Smjacob
2960163899Smjacob			wakeup((caddr_t)fc->ir[bind->xfer->sub]);
2961155228Smjacob
2962155228Smjacob			return;
2963155228Smjacob			break;
2964196008Smjacob		default:
2965155228Smjacob			goto err;
2966163899Smjacob			break;
2967163899Smjacob		}
2968163899Smjacob		break;
2969163899Smjacob	case FWTCODE_STREAM:
2970163899Smjacob	{
2971163899Smjacob		struct fw_xferq *xferq;
2972163899Smjacob
2973163899Smjacob		xferq = fc->ir[sub];
2974155228Smjacob#if 0
2975155228Smjacob		printf("stream rcv dma %d len %d off %d spd %d\n",
2976155228Smjacob			sub, len, off, spd);
2977196008Smjacob#endif
2978155228Smjacob		if(xferq->queued >= xferq->maxq) {
2979163899Smjacob			printf("receive queue is full\n");
2980163899Smjacob			goto err;
2981163899Smjacob		}
2982163899Smjacob		xfer = fw_xfer_alloc();
2983163899Smjacob		if(xfer == NULL) goto err;
2984163899Smjacob		xfer->recv.buf = buf;
2985163899Smjacob		xfer->recv.len = len;
2986163899Smjacob		xfer->recv.off = off;
2987163899Smjacob		xfer->spd = spd;
2988163899Smjacob		s = splfw();
2989289838Smav		xferq->queued++;
2990163899Smjacob		STAILQ_INSERT_TAIL(&xferq->q, xfer, link);
2991163899Smjacob		splx(s);
2992163899Smjacob		sc = device_get_softc(fc->bdev);
2993163899Smjacob#if __FreeBSD_version >= 500000
2994163899Smjacob		if (SEL_WAITING(&xferq->rsel))
2995196008Smjacob#else
2996196008Smjacob		if (&xferq->rsel.si_pid != 0)
2997196008Smjacob#endif
2998196008Smjacob			selwakeup(&xferq->rsel);
2999196008Smjacob		if (xferq->flag & FWXFERQ_WAKEUP) {
3000196008Smjacob			xferq->flag &= ~FWXFERQ_WAKEUP;
3001163899Smjacob			wakeup((caddr_t)xferq);
3002196008Smjacob		}
3003196008Smjacob		if (xferq->flag & FWXFERQ_HANDLER) {
3004196008Smjacob			xferq->hand(xferq);
3005163899Smjacob		}
3006163899Smjacob		return;
3007196008Smjacob		break;
3008196008Smjacob	}
3009163899Smjacob	default:
3010155228Smjacob		printf("fw_rcv: unknow tcode\n");
3011155228Smjacob		break;
3012155228Smjacob	}
3013196008Smjacoberr:
3014155228Smjacob	free(buf, M_DEVBUF);
3015163899Smjacob}
3016163899Smjacob/*
3017163899Smjacob * Post process for Bus Manager election process.
3018163899Smjacob */
3019163899Smjacobstatic void
3020163899Smjacobfw_try_bmr_callback(struct fw_xfer *xfer)
3021163899Smjacob{
3022163899Smjacob	struct fw_pkt *sfp,*rfp;
3023163899Smjacob	struct firewire_comm *fc;
3024155228Smjacob
3025155228Smjacob	if(xfer == NULL) return;
3026155228Smjacob	fc = xfer->fc;
3027196008Smjacob	if(xfer->resp != 0){
3028155228Smjacob		goto error;
3029163899Smjacob	}
3030163899Smjacob
3031163899Smjacob	if(xfer->send.buf == NULL){
3032163899Smjacob		goto error;
3033163899Smjacob	}
3034163899Smjacob	sfp = (struct fw_pkt *)xfer->send.buf;
3035163899Smjacob
3036163899Smjacob	if(xfer->recv.buf == NULL){
3037163899Smjacob		goto error;
3038163899Smjacob	}
3039163899Smjacob	rfp = (struct fw_pkt *)xfer->recv.buf;
3040196008Smjacob	CSRARC(fc, BUS_MGR_ID)
3041163899Smjacob		= fc->set_bmr(fc, ntohl(rfp->mode.lres.payload[0]) & 0x3f);
3042155228Smjacob	printf("%s: new bus manager %d ",
3043163899Smjacob		device_get_nameunit(fc->dev), CSRARC(fc, BUS_MGR_ID));
3044163899Smjacob	if((htonl(rfp->mode.lres.payload[0]) & 0x3f) == fc->nodeid){
3045163899Smjacob		printf("(me)\n");
3046163899Smjacob/* If I am bus manager, optimize gapcount */
3047163899Smjacob		if(fc->max_hop <= MAX_GAPHOP ){
3048163899Smjacob			fw_phy_config(fc, -1, gap_cnt[fc->max_hop]);
3049163899Smjacob		}
3050163899Smjacob	}else{
3051163899Smjacob		printf("\n");
3052289838Smav	}
3053163899Smjacoberror:
3054163899Smjacob	fw_xfer_free(xfer);
3055163899Smjacob}
3056163899Smjacob/*
3057163899Smjacob * To candidate Bus Manager election process.
3058196008Smjacob */
3059196008Smjacobvoid fw_try_bmr(void *arg)
3060196008Smjacob{
3061196008Smjacob	struct fw_xfer *xfer;
3062196008Smjacob	struct firewire_comm *fc = (struct firewire_comm *)arg;
3063196008Smjacob	struct fw_pkt *fp;
3064163899Smjacob	int err = 0;
3065196008Smjacob
3066196008Smjacob	xfer = fw_xfer_alloc();
3067196008Smjacob	if(xfer == NULL){
3068163899Smjacob		return;
3069163899Smjacob	}
3070196008Smjacob	xfer->send.len = 24;
3071196008Smjacob	xfer->spd = 0;
3072163899Smjacob	xfer->send.buf = malloc(24, M_DEVBUF, M_DONTWAIT);
3073163899Smjacob	if(xfer->send.buf == NULL){
3074163899Smjacob		fw_xfer_free( xfer);
3075163899Smjacob		return;
3076196008Smjacob	}
3077155228Smjacob
3078155228Smjacob	fc->status = FWBUSMGRELECT;
3079163899Smjacob
3080163899Smjacob	xfer->send.off = 0;
3081163899Smjacob	fp = (struct fw_pkt *)xfer->send.buf;
3082163899Smjacob	fp->mode.lreq.dest_hi = htons(0xffff);
3083163899Smjacob	fp->mode.lreq.tlrt = 0;
3084163899Smjacob	fp->mode.lreq.tcode = FWTCODE_LREQ;
3085163899Smjacob	fp->mode.lreq.pri = 0;
3086163899Smjacob	fp->mode.lreq.src = 0;
3087163899Smjacob	fp->mode.lreq.len = htons(8);
3088163899Smjacob	fp->mode.lreq.extcode = htons(FW_LREQ_CMPSWAP);
3089155228Smjacob	xfer->dst = FWLOCALBUS | fc->irm;
3090196008Smjacob	fp->mode.lreq.dst = htons(xfer->dst);
3091155228Smjacob	fp->mode.lreq.dest_lo = htonl(0xf0000000 | BUS_MGR_ID);
3092155228Smjacob	fp->mode.lreq.payload[0] = 0x3f;
3093155228Smjacob	fp->mode.lreq.payload[1] = fc->nodeid;
3094155228Smjacob	xfer->act_type = FWACT_XFER;
3095196008Smjacob	xfer->act.hand = fw_try_bmr_callback;
3096155228Smjacob
3097155228Smjacob	err = fw_asyreq(fc, -1, xfer);
3098163899Smjacob	if(err){
3099163899Smjacob		fw_xfer_free( xfer);
3100163899Smjacob		return;
3101163899Smjacob	}
3102163899Smjacob	return;
3103163899Smjacob}
3104163899Smjacob
3105163899Smjacob#ifdef FW_VMACCESS
3106163899Smjacob/*
3107155228Smjacob * Software implementation for physical memory block access.
3108196008Smjacob * XXX:Too slow, usef for debug purpose only.
3109155228Smjacob */
3110155228Smjacobstatic void fw_vmaccess(struct fw_xfer *xfer){
3111155228Smjacob	struct fw_pkt *rfp, *sfp = NULL;
3112155228Smjacob	u_int32_t *ld = (u_int32_t *)(xfer->recv.buf + xfer->recv.off);
3113196008Smjacob
3114155228Smjacob	printf("vmaccess spd:%2x len:%03x %d data:%08x %08x %08x %08x\n",
3115155228Smjacob			xfer->spd, xfer->recv.len, xfer->recv.off, ntohl(ld[0]), ntohl(ld[1]), ntohl(ld[2]), ntohl(ld[3]));
3116163899Smjacob	printf("vmaccess          data:%08x %08x %08x %08x\n", ntohl(ld[4]), ntohl(ld[5]), ntohl(ld[6]), ntohl(ld[7]));
3117163899Smjacob	if(xfer->resp != 0){
3118163899Smjacob		fw_xfer_free( xfer);
3119163899Smjacob		return;
3120163899Smjacob	}
3121163899Smjacob	if(xfer->recv.buf == NULL){
3122163899Smjacob		fw_xfer_free( xfer);
3123163899Smjacob		return;
3124163899Smjacob	}
3125289838Smav	rfp = (struct fw_pkt *)xfer->recv.buf;
3126163899Smjacob	switch(rfp->mode.hdr.tcode){
3127163899Smjacob		/* XXX need fix for 64bit arch */
3128163899Smjacob		case FWTCODE_WREQB:
3129163899Smjacob			xfer->send.buf = malloc(12, M_DEVBUF, M_NOWAIT);
3130163899Smjacob			xfer->send.len = 12;
3131163899Smjacob			sfp = (struct fw_pkt *)xfer->send.buf;
3132163899Smjacob			bcopy(rfp->mode.wreqb.payload,
3133163899Smjacob				(caddr_t)ntohl(rfp->mode.wreqb.dest_lo), ntohs(rfp->mode.wreqb.len));
3134163899Smjacob			sfp->mode.wres.tcode = FWTCODE_WRES;
3135196008Smjacob			sfp->mode.wres.rtcode = 0;
3136196008Smjacob			break;
3137196008Smjacob		case FWTCODE_WREQQ:
3138163899Smjacob			xfer->send.buf = malloc(12, M_DEVBUF, M_NOWAIT);
3139163899Smjacob			xfer->send.len = 12;
3140163899Smjacob			sfp->mode.wres.tcode = FWTCODE_WRES;
3141163899Smjacob			*((u_int32_t *)(ntohl(rfp->mode.wreqb.dest_lo))) = rfp->mode.wreqq.data;
3142163899Smjacob			sfp->mode.wres.rtcode = 0;
3143163899Smjacob			break;
3144163899Smjacob		case FWTCODE_RREQB:
3145163899Smjacob			xfer->send.buf = malloc(16 + rfp->mode.rreqb.len, M_DEVBUF, M_NOWAIT);
3146163899Smjacob			xfer->send.len = 16 + ntohs(rfp->mode.rreqb.len);
3147196008Smjacob			sfp = (struct fw_pkt *)xfer->send.buf;
3148163899Smjacob			bcopy((caddr_t)ntohl(rfp->mode.rreqb.dest_lo),
3149163899Smjacob				sfp->mode.rresb.payload, (u_int16_t)ntohs(rfp->mode.rreqb.len));
3150163899Smjacob			sfp->mode.rresb.tcode = FWTCODE_RRESB;
3151163899Smjacob			sfp->mode.rresb.len = rfp->mode.rreqb.len;
3152163899Smjacob			sfp->mode.rresb.rtcode = 0;
3153163899Smjacob			sfp->mode.rresb.extcode = 0;
3154163899Smjacob			break;
3155163899Smjacob		case FWTCODE_RREQQ:
3156163899Smjacob			xfer->send.buf = malloc(16, M_DEVBUF, M_NOWAIT);
3157163899Smjacob			xfer->send.len = 16;
3158163899Smjacob			sfp = (struct fw_pkt *)xfer->send.buf;
3159163899Smjacob			sfp->mode.rresq.data = *(u_int32_t *)(ntohl(rfp->mode.rreqq.dest_lo));
3160155228Smjacob			sfp->mode.wres.tcode = FWTCODE_RRESQ;
3161196008Smjacob			sfp->mode.rresb.rtcode = 0;
3162155228Smjacob			break;
3163155228Smjacob		default:
3164155228Smjacob			fw_xfer_free( xfer);
3165155228Smjacob			return;
3166196008Smjacob	}
3167155228Smjacob	xfer->send.off = 0;
3168155228Smjacob	sfp->mode.hdr.dst = rfp->mode.hdr.src;
3169163899Smjacob	xfer->dst = ntohs(rfp->mode.hdr.src);
3170163899Smjacob	xfer->act.hand = fw_xfer_free;
3171163899Smjacob	xfer->retry_req = fw_asybusy;
3172163899Smjacob
3173163899Smjacob	sfp->mode.hdr.tlrt = rfp->mode.hdr.tlrt;
3174163899Smjacob	sfp->mode.hdr.pri = 0;
3175163899Smjacob
3176163899Smjacob	fw_asyreq(xfer->fc, -1, xfer);
3177163899Smjacob/**/
3178155228Smjacob	return;
3179196008Smjacob}
3180155228Smjacob#endif
3181155228Smjacob
3182163899Smjacob/*
3183163899Smjacob * CRC16 check-sum for IEEE1394 register blocks.
3184196008Smjacob */
3185163899Smjacobu_int16_t fw_crc16(u_int32_t *ptr, u_int32_t len){
3186163899Smjacob	u_int32_t i, sum, crc = 0;
3187163899Smjacob	int shift;
3188163899Smjacob	len = (len + 3) & ~3;
3189163899Smjacob	for(i = 0 ; i < len ; i+= 4){
3190163899Smjacob		for( shift = 28 ; shift >= 0 ; shift -= 4){
3191163899Smjacob			sum = ((crc >> 12) ^ (ptr[i/4] >> shift)) & 0xf;
3192163899Smjacob			crc = (crc << 4) ^ ( sum << 12 ) ^ ( sum << 5) ^ sum;
3193163899Smjacob		}
3194163899Smjacob		crc &= 0xffff;
3195163899Smjacob	}
3196289838Smav	return((u_int16_t) crc);
3197163899Smjacob}
3198163899SmjacobDRIVER_MODULE(firewire,fwohci,firewire_driver,firewire_devclass,0,0);
3199163899SmjacobMODULE_VERSION(firewire, 1);
3200163899Smjacob