proc->thread stage 2: MAJOR revamping of system calls, ucred, jail API,
[dragonfly.git] / sys / bus / firewire / fwdev.c
1 /*
2  * Copyright (c) 2003 Hidetoshi Shimokawa
3  * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the acknowledgement as bellow:
16  *
17  *    This product includes software developed by K. Kobayashi and H. Shimokawa
18  *
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
26  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  * 
34  * $FreeBSD: src/sys/dev/firewire/fwdev.c,v 1.2.4.11 2003/04/28 03:29:18 simokawa Exp $
35  * $DragonFly: src/sys/bus/firewire/fwdev.c,v 1.3 2003/06/23 17:55:30 dillon Exp $
36  *
37  */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/types.h>
42 #include <sys/mbuf.h>
43
44 #include <sys/kernel.h>
45 #include <sys/malloc.h>
46 #include <sys/conf.h>
47 #include <sys/proc.h>
48 #include <sys/poll.h>
49
50 #include <sys/bus.h>
51 #include <machine/bus.h>
52
53 #include <sys/ioccom.h>
54
55 #include <dev/firewire/firewire.h>
56 #include <dev/firewire/firewirereg.h>
57 #include <dev/firewire/fwdma.h>
58 #include <dev/firewire/fwmem.h>
59 #include <dev/firewire/iec68113.h>
60
61 #define CDEV_MAJOR 127
62 #define FWNODE_INVAL 0xffff
63
64 static  d_open_t        fw_open;
65 static  d_close_t       fw_close;
66 static  d_ioctl_t       fw_ioctl;
67 static  d_poll_t        fw_poll;
68 static  d_read_t        fw_read;        /* for Isochronous packet */
69 static  d_write_t       fw_write;
70 static  d_mmap_t        fw_mmap;
71
72 struct cdevsw firewire_cdevsw = 
73 {
74 #if __FreeBSD_version >= 500104
75         .d_open =       fw_open,
76         .d_close =      fw_close,
77         .d_read =       fw_read,
78         .d_write =      fw_write,
79         .d_ioctl =      fw_ioctl,
80         .d_poll =       fw_poll,
81         .d_mmap =       fw_mmap,
82         .d_name =       "fw",
83         .d_maj =        CDEV_MAJOR,
84         .d_flags =      D_MEM
85 #else
86         fw_open, fw_close, fw_read, fw_write, fw_ioctl,
87         fw_poll, fw_mmap, nostrategy, "fw", CDEV_MAJOR, nodump, nopsize, D_MEM
88 #endif
89 };
90
91 static int
92 fw_open (dev_t dev, int flags, int fmt, fw_proc *td)
93 {
94         struct firewire_softc *sc;
95         int unit = DEV2UNIT(dev);
96         int sub = DEV2DMACH(dev);
97
98         int err = 0;
99
100         if (DEV_FWMEM(dev))
101                 return fwmem_open(dev, flags, fmt, td);
102
103         sc = devclass_get_softc(firewire_devclass, unit);
104         if(sc->fc->ir[sub]->flag & FWXFERQ_OPEN){
105                 err = EBUSY;
106                 return err;
107         }
108         if(sc->fc->it[sub]->flag & FWXFERQ_OPEN){
109                 err = EBUSY;
110                 return err;
111         }
112         if(sc->fc->ir[sub]->flag & FWXFERQ_MODEMASK){
113                 err = EBUSY;
114                 return err;
115         }
116 /* Default is per packet mode */
117         sc->fc->ir[sub]->flag |= FWXFERQ_OPEN;
118         sc->fc->it[sub]->flag |= FWXFERQ_OPEN;
119         return err;
120 }
121
122 static int
123 fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
124 {
125         struct firewire_softc *sc;
126         int unit = DEV2UNIT(dev);
127         int sub = DEV2DMACH(dev);
128         struct fw_xfer *xfer;
129         struct fw_bind *fwb;
130         int err = 0;
131
132         if (DEV_FWMEM(dev))
133                 return fwmem_close(dev, flags, fmt, td);
134
135         sc = devclass_get_softc(firewire_devclass, unit);
136         if(!(sc->fc->ir[sub]->flag & FWXFERQ_OPEN)){
137                 err = EINVAL;
138                 return err;
139         }
140         sc->fc->ir[sub]->flag &= ~FWXFERQ_OPEN;
141         if(!(sc->fc->it[sub]->flag & FWXFERQ_OPEN)){
142                 err = EINVAL;
143                 return err;
144         }
145         sc->fc->it[sub]->flag &= ~FWXFERQ_OPEN;
146
147         if(sc->fc->ir[sub]->flag & FWXFERQ_RUNNING){
148                 sc->fc->irx_disable(sc->fc, sub);
149         }
150         if(sc->fc->it[sub]->flag & FWXFERQ_RUNNING){
151                 sc->fc->it[sub]->flag &= ~FWXFERQ_RUNNING;
152                 sc->fc->itx_disable(sc->fc, sub);
153         }
154         if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){
155                 if (sc->fc->ir[sub]->buf != NULL)
156                         fwdma_free_multiseg(sc->fc->ir[sub]->buf);
157                 sc->fc->ir[sub]->buf = NULL;
158                 free(sc->fc->ir[sub]->bulkxfer, M_FW);
159                 sc->fc->ir[sub]->bulkxfer = NULL;
160                 sc->fc->ir[sub]->flag &= ~FWXFERQ_EXTBUF;
161                 sc->fc->ir[sub]->psize = PAGE_SIZE;
162                 sc->fc->ir[sub]->maxq = FWMAXQUEUE;
163         }
164         if(sc->fc->it[sub]->flag & FWXFERQ_EXTBUF){
165                 if (sc->fc->it[sub]->buf != NULL)
166                         fwdma_free_multiseg(sc->fc->it[sub]->buf);
167                 sc->fc->it[sub]->buf = NULL;
168                 free(sc->fc->it[sub]->bulkxfer, M_FW);
169                 sc->fc->it[sub]->bulkxfer = NULL;
170                 sc->fc->it[sub]->flag &= ~FWXFERQ_EXTBUF;
171                 sc->fc->it[sub]->psize = 0;
172                 sc->fc->it[sub]->maxq = FWMAXQUEUE;
173         }
174         for(xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q);
175                 xfer != NULL; xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q)){
176                 sc->fc->ir[sub]->queued--;
177                 STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->q, link);
178
179                 xfer->resp = 0;
180                 fw_xfer_done(xfer);
181         }
182         for(fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds); fwb != NULL;
183                 fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds)){
184                 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
185                 STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->binds, chlist);
186                 free(fwb, M_FW);
187         }
188         sc->fc->ir[sub]->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
189         sc->fc->it[sub]->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
190         return err;
191 }
192
193 /*
194  * read request.
195  */
196 static int
197 fw_read (dev_t dev, struct uio *uio, int ioflag)
198 {
199         struct firewire_softc *sc;
200         struct fw_xferq *ir;
201         struct fw_xfer *xfer;
202         int err = 0, s, slept = 0;
203         int unit = DEV2UNIT(dev);
204         int sub = DEV2DMACH(dev);
205         struct fw_pkt *fp;
206
207         if (DEV_FWMEM(dev))
208                 return fwmem_read(dev, uio, ioflag);
209
210         sc = devclass_get_softc(firewire_devclass, unit);
211
212         ir = sc->fc->ir[sub];
213
214 readloop:
215         xfer = STAILQ_FIRST(&ir->q);
216         if (ir->stproc == NULL) {
217                 /* iso bulkxfer */
218                 ir->stproc = STAILQ_FIRST(&ir->stvalid);
219                 if (ir->stproc != NULL) {
220                         s = splfw();
221                         STAILQ_REMOVE_HEAD(&ir->stvalid, link);
222                         splx(s);
223                         ir->queued = 0;
224                 }
225         }
226         if (xfer == NULL && ir->stproc == NULL) {
227                 /* no data avaliable */
228                 if (slept == 0) {
229                         slept = 1;
230                         ir->flag |= FWXFERQ_WAKEUP;
231                         err = tsleep(ir, FWPRI, "fw_read", hz);
232                         ir->flag &= ~FWXFERQ_WAKEUP;
233                         if (err == 0)
234                                 goto readloop;
235                 } else if (slept == 1)
236                         err = EIO;
237                 return err;
238         } else if(xfer != NULL) {
239                 /* per packet mode or FWACT_CH bind?*/
240                 s = splfw();
241                 ir->queued --;
242                 STAILQ_REMOVE_HEAD(&ir->q, link);
243                 splx(s);
244                 fp = (struct fw_pkt *)xfer->recv.buf;
245                 if(sc->fc->irx_post != NULL)
246                         sc->fc->irx_post(sc->fc, fp->mode.ld);
247                 err = uiomove(xfer->recv.buf, xfer->recv.len, uio);
248                 /* XXX we should recycle this xfer */
249                 fw_xfer_free( xfer);
250         } else if(ir->stproc != NULL) {
251                 /* iso bulkxfer */
252                 fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 
253                                 ir->stproc->poffset + ir->queued);
254                 if(sc->fc->irx_post != NULL)
255                         sc->fc->irx_post(sc->fc, fp->mode.ld);
256                 if(fp->mode.stream.len == 0){
257                         err = EIO;
258                         return err;
259                 }
260                 err = uiomove((caddr_t)fp,
261                         fp->mode.stream.len + sizeof(u_int32_t), uio);
262                 ir->queued ++;
263                 if(ir->queued >= ir->bnpacket){
264                         s = splfw();
265                         STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
266                         splx(s);
267                         sc->fc->irx_enable(sc->fc, sub);
268                         ir->stproc = NULL;
269                 }
270                 if (uio->uio_resid >= ir->psize) {
271                         slept = -1;
272                         goto readloop;
273                 }
274         }
275         return err;
276 }
277
278 static int
279 fw_write (dev_t dev, struct uio *uio, int ioflag)
280 {
281         int err = 0;
282         struct firewire_softc *sc;
283         int unit = DEV2UNIT(dev);
284         int sub = DEV2DMACH(dev);
285         int s, slept = 0;
286         struct fw_pkt *fp;
287         struct firewire_comm *fc;
288         struct fw_xferq *it;
289
290         if (DEV_FWMEM(dev))
291                 return fwmem_write(dev, uio, ioflag);
292
293         sc = devclass_get_softc(firewire_devclass, unit);
294         fc = sc->fc;
295         it = sc->fc->it[sub];
296 isoloop:
297         if (it->stproc == NULL) {
298                 it->stproc = STAILQ_FIRST(&it->stfree);
299                 if (it->stproc != NULL) {
300                         s = splfw();
301                         STAILQ_REMOVE_HEAD(&it->stfree, link);
302                         splx(s);
303                         it->queued = 0;
304                 } else if (slept == 0) {
305                         slept = 1;
306                         err = sc->fc->itx_enable(sc->fc, sub);
307                         if (err)
308                                 return err;
309                         err = tsleep(it, FWPRI, "fw_write", hz);
310                         if (err)
311                                 return err;
312                         goto isoloop;
313                 } else {
314                         err = EIO;
315                         return err;
316                 }
317         }
318         fp = (struct fw_pkt *)fwdma_v_addr(it->buf,
319                         it->stproc->poffset + it->queued);
320         err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio);
321         err = uiomove((caddr_t)fp->mode.stream.payload,
322                                 fp->mode.stream.len, uio);
323         it->queued ++;
324         if (it->queued >= it->bnpacket) {
325                 s = splfw();
326                 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
327                 splx(s);
328                 it->stproc = NULL;
329                 err = sc->fc->itx_enable(sc->fc, sub);
330         }
331         if (uio->uio_resid >= sizeof(struct fw_isohdr)) {
332                 slept = 0;
333                 goto isoloop;
334         }
335         return err;
336 }
337
338 /*
339  * ioctl support.
340  */
341 int
342 fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
343 {
344         struct firewire_softc *sc;
345         int unit = DEV2UNIT(dev);
346         int sub = DEV2DMACH(dev);
347         int s, i, len, err = 0;
348         struct fw_device *fwdev;
349         struct fw_bind *fwb;
350         struct fw_xferq *ir, *it;
351         struct fw_xfer *xfer;
352         struct fw_pkt *fp;
353         struct fw_devinfo *devinfo;
354
355         struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data;
356         struct fw_asyreq *asyreq = (struct fw_asyreq *)data;
357         struct fw_isochreq *ichreq = (struct fw_isochreq *)data;
358         struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data;
359         struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data;
360         struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data;
361
362         if (DEV_FWMEM(dev))
363                 return fwmem_ioctl(dev, cmd, data, flag, td);
364
365         sc = devclass_get_softc(firewire_devclass, unit);
366         if (!data)
367                 return(EINVAL);
368
369         switch (cmd) {
370         case FW_STSTREAM:
371                 sc->fc->it[sub]->flag &= ~0xff;
372                 sc->fc->it[sub]->flag |= (0x3f & ichreq->ch);
373                 sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6);
374                 err = 0;
375                 break;
376         case FW_GTSTREAM:
377                 ichreq->ch = sc->fc->it[sub]->flag & 0x3f;
378                 ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3;
379                 err = 0;
380                 break;
381         case FW_SRSTREAM:
382                 sc->fc->ir[sub]->flag &= ~0xff;
383                 sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch);
384                 sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6);
385                 err = sc->fc->irx_enable(sc->fc, sub);
386                 break;
387         case FW_GRSTREAM:
388                 ichreq->ch = sc->fc->ir[sub]->flag & 0x3f;
389                 ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3;
390                 err = 0;
391                 break;
392         case FW_SSTBUF:
393                 ir = sc->fc->ir[sub];
394                 it = sc->fc->it[sub];
395
396                 if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){
397                         return(EBUSY);
398                 }
399                 if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){
400                         return(EBUSY);
401                 }
402                 if((ibufreq->rx.nchunk *
403                         ibufreq->rx.psize * ibufreq->rx.npacket) +
404                    (ibufreq->tx.nchunk *
405                         ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){
406                                 return(EINVAL);
407                 }
408                 ir->bulkxfer
409                         = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_FW, M_WAITOK);
410                 if(ir->bulkxfer == NULL){
411                         return(ENOMEM);
412                 }
413                 it->bulkxfer
414                         = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_FW, M_WAITOK);
415                 if(it->bulkxfer == NULL){
416                         return(ENOMEM);
417                 }
418                 if (ibufreq->rx.psize > 0) {
419                         ibufreq->rx.psize = roundup2(ibufreq->rx.psize,
420                                                         sizeof(u_int32_t));
421                         ir->buf = fwdma_malloc_multiseg(
422                                 sc->fc, sizeof(u_int32_t),
423                                 ibufreq->rx.psize,
424                                 ibufreq->rx.nchunk * ibufreq->rx.npacket,
425                                 BUS_DMA_WAITOK);
426
427                         if(ir->buf == NULL){
428                                 free(ir->bulkxfer, M_FW);
429                                 free(it->bulkxfer, M_FW);
430                                 ir->bulkxfer = NULL;
431                                 it->bulkxfer = NULL;
432                                 it->buf = NULL;
433                                 return(ENOMEM);
434                         }
435                 }
436                 if (ibufreq->tx.psize > 0) {
437                         ibufreq->tx.psize = roundup2(ibufreq->tx.psize,
438                                                         sizeof(u_int32_t));
439                         it->buf = fwdma_malloc_multiseg(
440                                 sc->fc, sizeof(u_int32_t),
441                                 ibufreq->tx.psize,
442                                 ibufreq->tx.nchunk * ibufreq->tx.npacket,
443                                 BUS_DMA_WAITOK);
444
445                         if(it->buf == NULL){
446                                 free(ir->bulkxfer, M_FW);
447                                 free(it->bulkxfer, M_FW);
448                                 fwdma_free_multiseg(ir->buf);
449                                 ir->bulkxfer = NULL;
450                                 it->bulkxfer = NULL;
451                                 it->buf = NULL;
452                                 return(ENOMEM);
453                         }
454                 }
455
456                 ir->bnchunk = ibufreq->rx.nchunk;
457                 ir->bnpacket = ibufreq->rx.npacket;
458                 ir->psize = (ibufreq->rx.psize + 3) & ~3;
459                 ir->queued = 0;
460
461                 it->bnchunk = ibufreq->tx.nchunk;
462                 it->bnpacket = ibufreq->tx.npacket;
463                 it->psize = (ibufreq->tx.psize + 3) & ~3;
464                 it->queued = 0;
465
466                 STAILQ_INIT(&ir->stvalid);
467                 STAILQ_INIT(&ir->stfree);
468                 STAILQ_INIT(&ir->stdma);
469                 ir->stproc = NULL;
470
471                 STAILQ_INIT(&it->stvalid);
472                 STAILQ_INIT(&it->stfree);
473                 STAILQ_INIT(&it->stdma);
474                 it->stproc = NULL;
475
476                 for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){
477                         ir->bulkxfer[i].poffset = i * ir->bnpacket;
478                         ir->bulkxfer[i].mbuf = NULL;
479                         STAILQ_INSERT_TAIL(&ir->stfree,
480                                         &ir->bulkxfer[i], link);
481                 }
482                 for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){
483                         it->bulkxfer[i].poffset = i * it->bnpacket;
484                         it->bulkxfer[i].mbuf = NULL;
485                         STAILQ_INSERT_TAIL(&it->stfree,
486                                         &it->bulkxfer[i], link);
487                 }
488                 ir->flag &= ~FWXFERQ_MODEMASK;
489                 ir->flag |= FWXFERQ_STREAM;
490                 ir->flag |= FWXFERQ_EXTBUF;
491
492                 it->flag &= ~FWXFERQ_MODEMASK;
493                 it->flag |= FWXFERQ_STREAM;
494                 it->flag |= FWXFERQ_EXTBUF;
495                 err = 0;
496                 break;
497         case FW_GSTBUF:
498                 ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk;
499                 ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket;
500                 ibufreq->rx.psize = sc->fc->ir[sub]->psize;
501
502                 ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk;
503                 ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket;
504                 ibufreq->tx.psize = sc->fc->it[sub]->psize;
505                 break;
506         case FW_ASYREQ:
507                 xfer = fw_xfer_alloc_buf(M_FWXFER, asyreq->req.len,
508                                                         PAGE_SIZE /* XXX */);
509                 if(xfer == NULL){
510                         err = ENOMEM;
511                         return err;
512                 }
513                 fp = &asyreq->pkt;
514                 switch (asyreq->req.type) {
515                 case FWASREQNODE:
516                         xfer->dst = fp->mode.hdr.dst;
517                         break;
518                 case FWASREQEUI:
519                         fwdev = fw_noderesolve_eui64(sc->fc,
520                                                 &asyreq->req.dst.eui);
521                         if (fwdev == NULL) {
522                                 device_printf(sc->fc->bdev,
523                                         "cannot find node\n");
524                                 err = EINVAL;
525                                 goto error;
526                         }
527                         xfer->dst = FWLOCALBUS | fwdev->dst;
528                         fp->mode.hdr.dst = xfer->dst;
529                         break;
530                 case FWASRESTL:
531                         /* XXX what's this? */
532                         break;
533                 case FWASREQSTREAM:
534                         /* nothing to do */
535                         break;
536                 }
537                 xfer->spd = asyreq->req.sped;
538                 bcopy(fp, xfer->send.buf, xfer->send.len);
539                 xfer->act.hand = fw_asy_callback;
540                 err = fw_asyreq(sc->fc, sub, xfer);
541                 if(err){
542                         fw_xfer_free( xfer);
543                         return err;
544                 }
545                 err = tsleep(xfer, FWPRI, "asyreq", hz);
546                 if(err == 0){
547                         if(asyreq->req.len >= xfer->recv.len){
548                                 asyreq->req.len = xfer->recv.len;
549                         }else{
550                                 err = EINVAL;
551                         }
552                         bcopy(xfer->recv.buf, fp, asyreq->req.len);
553                 }
554 error:
555                 fw_xfer_free( xfer);
556                 break;
557         case FW_IBUSRST:
558                 sc->fc->ibr(sc->fc);
559                 break;
560         case FW_CBINDADDR:
561                 fwb = fw_bindlookup(sc->fc,
562                                 bindreq->start.hi, bindreq->start.lo);
563                 if(fwb == NULL){
564                         err = EINVAL;
565                         break;
566                 }
567                 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
568                 STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist);
569                 free(fwb, M_FW);
570                 break;
571         case FW_SBINDADDR:
572                 if(bindreq->len <= 0 ){
573                         err = EINVAL;
574                         break;
575                 }
576                 if(bindreq->start.hi > 0xffff ){
577                         err = EINVAL;
578                         break;
579                 }
580                 fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT);
581                 if(fwb == NULL){
582                         err = ENOMEM;
583                         break;
584                 }
585                 fwb->start_hi = bindreq->start.hi;
586                 fwb->start_lo = bindreq->start.lo;
587                 fwb->addrlen = bindreq->len;
588                 fwb->sub = sub;
589                 fwb->act_type = FWACT_CH;
590
591                 xfer = fw_xfer_alloc(M_FWXFER);
592                 if(xfer == NULL){
593                         err = ENOMEM;
594                         return err;
595                 }
596                 xfer->fc = sc->fc;
597
598                 s = splfw();
599                 /* XXX broken. need multiple xfer */
600                 STAILQ_INIT(&fwb->xferlist);
601                 STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link);
602                 splx(s);
603                 err = fw_bindadd(sc->fc, fwb);
604                 break;
605         case FW_GDEVLST:
606                 i = len = 1;
607                 /* myself */
608                 devinfo = &fwdevlst->dev[0];
609                 devinfo->dst = sc->fc->nodeid;
610                 devinfo->status = 0;    /* XXX */
611                 devinfo->eui.hi = sc->fc->eui.hi;
612                 devinfo->eui.lo = sc->fc->eui.lo;
613                 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) {
614                         if(len < FW_MAX_DEVLST){
615                                 devinfo = &fwdevlst->dev[len++];
616                                 devinfo->dst = fwdev->dst;
617                                 devinfo->status = 
618                                         (fwdev->status == FWDEVINVAL)?0:1;
619                                 devinfo->eui.hi = fwdev->eui.hi;
620                                 devinfo->eui.lo = fwdev->eui.lo;
621                         }
622                         i++;
623                 }
624                 fwdevlst->n = i;
625                 fwdevlst->info_len = len;
626                 break;
627         case FW_GTPMAP:
628                 bcopy(sc->fc->topology_map, data,
629                                 (sc->fc->topology_map->crc_len + 1) * 4);
630                 break;
631         case FW_GCROM:
632                 STAILQ_FOREACH(fwdev, &sc->fc->devices, link)
633                         if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui))
634                                 break;
635                 if (fwdev == NULL) {
636                         err = FWNODE_INVAL;
637                         break;
638                 }
639                 if (fwdev->rommax < CSRROMOFF)
640                         len = 0;
641                 else
642                         len = fwdev->rommax - CSRROMOFF + 4;
643                 if (crom_buf->len < len)
644                         len = crom_buf->len;
645                 else
646                         crom_buf->len = len;
647                 err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len);
648                 break;
649         default:
650                 sc->fc->ioctl (dev, cmd, data, flag, td);
651                 break;
652         }
653         return err;
654 }
655 int
656 fw_poll(dev_t dev, int events, fw_proc *td)
657 {
658         int revents;
659         int tmp;
660         int unit = DEV2UNIT(dev);
661         int sub = DEV2DMACH(dev);
662         struct firewire_softc *sc;
663
664         if (DEV_FWMEM(dev))
665                 return fwmem_poll(dev, events, td);
666
667         sc = devclass_get_softc(firewire_devclass, unit);
668         revents = 0;
669         tmp = POLLIN | POLLRDNORM;
670         if (events & tmp) {
671                 if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL)
672                         revents |= tmp;
673                 else
674                         selrecord(td, &sc->fc->ir[sub]->rsel); /* YYY */
675         }
676         tmp = POLLOUT | POLLWRNORM;
677         if (events & tmp) {
678                 /* XXX should be fixed */       
679                 revents |= tmp;
680         }
681
682         return revents;
683 }
684
685 static int
686 #if __FreeBSD_version < 500102
687 fw_mmap (dev_t dev, vm_offset_t offset, int nproto)
688 #else
689 fw_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto)
690 #endif
691 {  
692         struct firewire_softc *fc;
693         int unit = DEV2UNIT(dev);
694
695         if (DEV_FWMEM(dev))
696 #if __FreeBSD_version < 500102
697                 return fwmem_mmap(dev, offset, nproto);
698 #else
699                 return fwmem_mmap(dev, offset, paddr, nproto);
700 #endif
701
702         fc = devclass_get_softc(firewire_devclass, unit);
703
704         return EINVAL;
705 }