Change the kernel dev_t, representing a pointer to a specinfo structure,
[dragonfly.git] / sys / bus / firewire / fwdev.c
CommitLineData
984263bc
MD
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 *
78748771 34 * $FreeBSD: src/sys/dev/firewire/fwdev.c,v 1.36 2004/01/22 14:41:17 simokawa Exp $
b13267a5 35 * $DragonFly: src/sys/bus/firewire/fwdev.c,v 1.16 2006/09/10 01:26:32 dillon Exp $
984263bc
MD
36 *
37 */
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/types.h>
42#include <sys/mbuf.h>
90dec0df 43#if defined(__DragonFly__) || __FreeBSD_version < 500000
78748771
JS
44#include <sys/buf.h>
45#else
46#include <sys/bio.h>
47#endif
984263bc
MD
48
49#include <sys/kernel.h>
50#include <sys/malloc.h>
51#include <sys/conf.h>
52#include <sys/poll.h>
53
54#include <sys/bus.h>
78748771 55#include <sys/ctype.h>
984263bc
MD
56#include <machine/bus.h>
57
58#include <sys/ioccom.h>
4e01b467 59#include <sys/thread2.h>
984263bc 60
78748771 61#ifdef __DragonFly__
1f2de5d4
MD
62#include "firewire.h"
63#include "firewirereg.h"
64#include "fwdma.h"
65#include "fwmem.h"
66#include "iec68113.h"
78748771
JS
67#else
68#include <dev/firewire/firewire.h>
69#include <dev/firewire/firewirereg.h>
70#include <dev/firewire/fwdma.h>
71#include <dev/firewire/fwmem.h>
72#include <dev/firewire/iec68113.h>
73#endif
984263bc
MD
74
75#define CDEV_MAJOR 127
76#define FWNODE_INVAL 0xffff
77
78static d_open_t fw_open;
79static d_close_t fw_close;
80static d_ioctl_t fw_ioctl;
81static d_poll_t fw_poll;
82static d_read_t fw_read; /* for Isochronous packet */
83static d_write_t fw_write;
84static d_mmap_t fw_mmap;
78748771 85static d_strategy_t fw_strategy;
984263bc 86
fef8985e 87struct dev_ops firewire_ops =
984263bc 88{
fef8985e 89 { "fw", CDEV_MAJOR, D_MEM },
984263bc
MD
90 .d_open = fw_open,
91 .d_close = fw_close,
92 .d_read = fw_read,
93 .d_write = fw_write,
94 .d_ioctl = fw_ioctl,
95 .d_poll = fw_poll,
96 .d_mmap = fw_mmap,
78748771 97 .d_strategy = fw_strategy,
984263bc
MD
98};
99
78748771
JS
100struct fw_drv1 {
101 struct fw_xferq *ir;
102 struct fw_xferq *it;
103 struct fw_isobufreq bufreq;
104};
105
984263bc 106static int
78748771
JS
107fwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q,
108 struct fw_bufspec *b)
984263bc 109{
78748771
JS
110 int i;
111
112 if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF))
113 return(EBUSY);
114
77652cad 115 q->bulkxfer = (struct fw_bulkxfer *) kmalloc(
78748771
JS
116 sizeof(struct fw_bulkxfer) * b->nchunk,
117 M_FW, M_WAITOK);
118 if (q->bulkxfer == NULL)
119 return(ENOMEM);
120
121 b->psize = roundup2(b->psize, sizeof(u_int32_t));
122 q->buf = fwdma_malloc_multiseg(fc, sizeof(u_int32_t),
123 b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK);
124
125 if (q->buf == NULL) {
efda3bd0 126 kfree(q->bulkxfer, M_FW);
78748771
JS
127 q->bulkxfer = NULL;
128 return(ENOMEM);
129 }
130 q->bnchunk = b->nchunk;
131 q->bnpacket = b->npacket;
132 q->psize = (b->psize + 3) & ~3;
133 q->queued = 0;
134
135 STAILQ_INIT(&q->stvalid);
136 STAILQ_INIT(&q->stfree);
137 STAILQ_INIT(&q->stdma);
138 q->stproc = NULL;
139
140 for(i = 0 ; i < q->bnchunk; i++){
141 q->bulkxfer[i].poffset = i * q->bnpacket;
142 q->bulkxfer[i].mbuf = NULL;
143 STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link);
144 }
145
146 q->flag &= ~FWXFERQ_MODEMASK;
147 q->flag |= FWXFERQ_STREAM;
148 q->flag |= FWXFERQ_EXTBUF;
149
150 return (0);
151}
984263bc 152
78748771
JS
153static int
154fwdev_freebuf(struct fw_xferq *q)
155{
156 if (q->flag & FWXFERQ_EXTBUF) {
157 if (q->buf != NULL)
158 fwdma_free_multiseg(q->buf);
159 q->buf = NULL;
efda3bd0 160 kfree(q->bulkxfer, M_FW);
78748771
JS
161 q->bulkxfer = NULL;
162 q->flag &= ~FWXFERQ_EXTBUF;
163 q->psize = 0;
164 q->maxq = FWMAXQUEUE;
165 }
166 return (0);
167}
168
169
170static int
fef8985e 171fw_open (struct dev_open_args *ap)
78748771 172{
b13267a5 173 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
174 int err = 0;
175
176 if (DEV_FWMEM(dev))
fef8985e 177 return fwmem_open(ap);
984263bc 178
78748771
JS
179 if (dev->si_drv1 != NULL)
180 return (EBUSY);
181
90dec0df 182#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
78748771
JS
183 if ((dev->si_flags & SI_NAMED) == 0) {
184 int unit = DEV2UNIT(dev);
185 int sub = DEV2SUB(dev);
186
fef8985e 187 make_dev(&firewire_ops, minor(dev),
78748771
JS
188 UID_ROOT, GID_OPERATOR, 0660,
189 "fw%d.%d", unit, sub);
984263bc 190 }
78748771
JS
191#endif
192
efda3bd0 193 dev->si_drv1 = kmalloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO);
78748771 194
984263bc
MD
195 return err;
196}
197
198static int
fef8985e 199fw_close (struct dev_close_args *ap)
984263bc 200{
b13267a5 201 cdev_t dev = ap->a_head.a_dev;
984263bc 202 struct firewire_softc *sc;
78748771
JS
203 struct firewire_comm *fc;
204 struct fw_drv1 *d;
984263bc 205 int unit = DEV2UNIT(dev);
984263bc
MD
206 struct fw_xfer *xfer;
207 struct fw_bind *fwb;
208 int err = 0;
209
210 if (DEV_FWMEM(dev))
fef8985e 211 return fwmem_close(ap);
984263bc
MD
212
213 sc = devclass_get_softc(firewire_devclass, unit);
78748771
JS
214 fc = sc->fc;
215 d = (struct fw_drv1 *)dev->si_drv1;
984263bc 216
78748771
JS
217 if (d->ir != NULL) {
218 struct fw_xferq *ir = d->ir;
219
220 if ((ir->flag & FWXFERQ_OPEN) == 0)
221 return (EINVAL);
222 if (ir->flag & FWXFERQ_RUNNING) {
223 ir->flag &= ~FWXFERQ_RUNNING;
224 fc->irx_disable(fc, ir->dmach);
225 }
226 /* free extbuf */
227 fwdev_freebuf(ir);
228 /* drain receiving buffer */
229 for (xfer = STAILQ_FIRST(&ir->q);
230 xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) {
231 ir->queued --;
232 STAILQ_REMOVE_HEAD(&ir->q, link);
233
234 xfer->resp = 0;
235 fw_xfer_done(xfer);
236 }
237 /* remove binding */
238 for (fwb = STAILQ_FIRST(&ir->binds); fwb != NULL;
239 fwb = STAILQ_FIRST(&ir->binds)) {
240 STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist);
241 STAILQ_REMOVE_HEAD(&ir->binds, chlist);
efda3bd0 242 kfree(fwb, M_FW);
78748771
JS
243 }
244 ir->flag &= ~(FWXFERQ_OPEN |
245 FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
246 d->ir = NULL;
984263bc 247
984263bc 248 }
78748771
JS
249 if (d->it != NULL) {
250 struct fw_xferq *it = d->it;
251
252 if ((it->flag & FWXFERQ_OPEN) == 0)
253 return (EINVAL);
254 if (it->flag & FWXFERQ_RUNNING) {
255 it->flag &= ~FWXFERQ_RUNNING;
256 fc->itx_disable(fc, it->dmach);
257 }
258 /* free extbuf */
259 fwdev_freebuf(it);
260 it->flag &= ~(FWXFERQ_OPEN |
261 FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
262 d->it = NULL;
984263bc 263 }
efda3bd0 264 kfree(dev->si_drv1, M_FW);
78748771
JS
265 dev->si_drv1 = NULL;
266
984263bc
MD
267 return err;
268}
269
270/*
271 * read request.
272 */
273static int
fef8985e 274fw_read (struct dev_read_args *ap)
984263bc 275{
b13267a5 276 cdev_t dev = ap->a_head.a_dev;
fef8985e 277 struct uio *uio = ap->a_uio;
984263bc
MD
278 struct firewire_softc *sc;
279 struct fw_xferq *ir;
280 struct fw_xfer *xfer;
4e01b467 281 int err = 0, slept = 0;
984263bc 282 int unit = DEV2UNIT(dev);
984263bc
MD
283 struct fw_pkt *fp;
284
285 if (DEV_FWMEM(dev))
fef8985e 286 return physread(ap);
984263bc
MD
287
288 sc = devclass_get_softc(firewire_devclass, unit);
289
78748771
JS
290 ir = ((struct fw_drv1 *)dev->si_drv1)->ir;
291 if (ir == NULL || ir->buf == NULL)
292 return (EIO);
984263bc
MD
293
294readloop:
295 xfer = STAILQ_FIRST(&ir->q);
296 if (ir->stproc == NULL) {
297 /* iso bulkxfer */
298 ir->stproc = STAILQ_FIRST(&ir->stvalid);
299 if (ir->stproc != NULL) {
4e01b467 300 crit_enter();
984263bc 301 STAILQ_REMOVE_HEAD(&ir->stvalid, link);
4e01b467 302 crit_exit();
984263bc
MD
303 ir->queued = 0;
304 }
305 }
306 if (xfer == NULL && ir->stproc == NULL) {
307 /* no data avaliable */
308 if (slept == 0) {
309 slept = 1;
310 ir->flag |= FWXFERQ_WAKEUP;
311 err = tsleep(ir, FWPRI, "fw_read", hz);
312 ir->flag &= ~FWXFERQ_WAKEUP;
313 if (err == 0)
314 goto readloop;
315 } else if (slept == 1)
316 err = EIO;
317 return err;
318 } else if(xfer != NULL) {
78748771 319#if 0 /* XXX broken */
984263bc 320 /* per packet mode or FWACT_CH bind?*/
4e01b467 321 crit_enter();
984263bc
MD
322 ir->queued --;
323 STAILQ_REMOVE_HEAD(&ir->q, link);
4e01b467 324 crit_exit();
78748771
JS
325 fp = &xfer->recv.hdr;
326 if (sc->fc->irx_post != NULL)
984263bc 327 sc->fc->irx_post(sc->fc, fp->mode.ld);
78748771
JS
328 err = uiomove((void *)fp, 1 /* XXX header size */, uio);
329 /* XXX copy payload too */
984263bc 330 /* XXX we should recycle this xfer */
78748771 331#endif
984263bc
MD
332 fw_xfer_free( xfer);
333 } else if(ir->stproc != NULL) {
334 /* iso bulkxfer */
335 fp = (struct fw_pkt *)fwdma_v_addr(ir->buf,
336 ir->stproc->poffset + ir->queued);
337 if(sc->fc->irx_post != NULL)
338 sc->fc->irx_post(sc->fc, fp->mode.ld);
339 if(fp->mode.stream.len == 0){
340 err = EIO;
341 return err;
342 }
343 err = uiomove((caddr_t)fp,
344 fp->mode.stream.len + sizeof(u_int32_t), uio);
345 ir->queued ++;
346 if(ir->queued >= ir->bnpacket){
4e01b467 347 crit_enter();
984263bc 348 STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
4e01b467 349 crit_exit();
78748771 350 sc->fc->irx_enable(sc->fc, ir->dmach);
984263bc
MD
351 ir->stproc = NULL;
352 }
353 if (uio->uio_resid >= ir->psize) {
354 slept = -1;
355 goto readloop;
356 }
357 }
358 return err;
359}
360
361static int
fef8985e 362fw_write (struct dev_write_args *ap)
984263bc 363{
b13267a5 364 cdev_t dev = ap->a_head.a_dev;
fef8985e 365 struct uio *uio = ap->a_uio;
984263bc
MD
366 int err = 0;
367 struct firewire_softc *sc;
368 int unit = DEV2UNIT(dev);
4e01b467 369 int slept = 0;
984263bc
MD
370 struct fw_pkt *fp;
371 struct firewire_comm *fc;
372 struct fw_xferq *it;
373
374 if (DEV_FWMEM(dev))
fef8985e 375 return physwrite(ap);
984263bc
MD
376
377 sc = devclass_get_softc(firewire_devclass, unit);
378 fc = sc->fc;
78748771
JS
379 it = ((struct fw_drv1 *)dev->si_drv1)->it;
380 if (it == NULL || it->buf == NULL)
381 return (EIO);
984263bc
MD
382isoloop:
383 if (it->stproc == NULL) {
384 it->stproc = STAILQ_FIRST(&it->stfree);
385 if (it->stproc != NULL) {
4e01b467 386 crit_enter();
984263bc 387 STAILQ_REMOVE_HEAD(&it->stfree, link);
4e01b467 388 crit_exit();
984263bc
MD
389 it->queued = 0;
390 } else if (slept == 0) {
391 slept = 1;
78748771 392 err = sc->fc->itx_enable(sc->fc, it->dmach);
984263bc
MD
393 if (err)
394 return err;
395 err = tsleep(it, FWPRI, "fw_write", hz);
396 if (err)
397 return err;
398 goto isoloop;
399 } else {
400 err = EIO;
401 return err;
402 }
403 }
404 fp = (struct fw_pkt *)fwdma_v_addr(it->buf,
405 it->stproc->poffset + it->queued);
406 err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio);
407 err = uiomove((caddr_t)fp->mode.stream.payload,
408 fp->mode.stream.len, uio);
409 it->queued ++;
410 if (it->queued >= it->bnpacket) {
4e01b467 411 crit_enter();
984263bc 412 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
4e01b467 413 crit_exit();
984263bc 414 it->stproc = NULL;
78748771 415 err = sc->fc->itx_enable(sc->fc, it->dmach);
984263bc
MD
416 }
417 if (uio->uio_resid >= sizeof(struct fw_isohdr)) {
418 slept = 0;
419 goto isoloop;
420 }
421 return err;
422}
984263bc
MD
423/*
424 * ioctl support.
425 */
426int
fef8985e 427fw_ioctl (struct dev_ioctl_args *ap)
984263bc 428{
b13267a5 429 cdev_t dev = ap->a_head.a_dev;
984263bc 430 struct firewire_softc *sc;
78748771
JS
431 struct firewire_comm *fc;
432 struct fw_drv1 *d;
984263bc 433 int unit = DEV2UNIT(dev);
4e01b467 434 int i, len, err = 0;
984263bc
MD
435 struct fw_device *fwdev;
436 struct fw_bind *fwb;
437 struct fw_xferq *ir, *it;
438 struct fw_xfer *xfer;
439 struct fw_pkt *fp;
440 struct fw_devinfo *devinfo;
78748771 441 void *ptr;
984263bc 442
fef8985e
MD
443 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)ap->a_data;
444 struct fw_asyreq *asyreq = (struct fw_asyreq *)ap->a_data;
445 struct fw_isochreq *ichreq = (struct fw_isochreq *)ap->a_data;
446 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)ap->a_data;
447 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)ap->a_data;
448 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)ap->a_data;
984263bc
MD
449
450 if (DEV_FWMEM(dev))
fef8985e 451 return fwmem_ioctl(ap);
984263bc 452
fef8985e 453 if (!ap->a_data)
984263bc
MD
454 return(EINVAL);
455
78748771
JS
456 sc = devclass_get_softc(firewire_devclass, unit);
457 fc = sc->fc;
458 d = (struct fw_drv1 *)dev->si_drv1;
459 ir = d->ir;
460 it = d->it;
461
fef8985e 462 switch (ap->a_cmd) {
984263bc 463 case FW_STSTREAM:
78748771
JS
464 if (it == NULL) {
465 for (i = 0; i < fc->nisodma; i ++) {
466 it = fc->it[i];
467 if ((it->flag & FWXFERQ_OPEN) == 0)
468 break;
469 }
470 if (i >= fc->nisodma) {
471 err = EBUSY;
472 break;
473 }
474 err = fwdev_allocbuf(fc, it, &d->bufreq.tx);
475 if (err)
476 break;
477 it->flag |= FWXFERQ_OPEN;
478 }
479 it->flag &= ~0xff;
480 it->flag |= (0x3f & ichreq->ch);
481 it->flag |= ((0x3 & ichreq->tag) << 6);
482 d->it = it;
984263bc
MD
483 break;
484 case FW_GTSTREAM:
78748771
JS
485 if (it != NULL) {
486 ichreq->ch = it->flag & 0x3f;
487 ichreq->tag = it->flag >> 2 & 0x3;
488 } else
489 err = EINVAL;
984263bc
MD
490 break;
491 case FW_SRSTREAM:
78748771
JS
492 if (ir == NULL) {
493 for (i = 0; i < fc->nisodma; i ++) {
494 ir = fc->ir[i];
495 if ((ir->flag & FWXFERQ_OPEN) == 0)
496 break;
497 }
498 if (i >= fc->nisodma) {
499 err = EBUSY;
500 break;
501 }
502 err = fwdev_allocbuf(fc, ir, &d->bufreq.rx);
503 if (err)
504 break;
505 ir->flag |= FWXFERQ_OPEN;
506 }
507 ir->flag &= ~0xff;
508 ir->flag |= (0x3f & ichreq->ch);
509 ir->flag |= ((0x3 & ichreq->tag) << 6);
510 d->ir = ir;
511 err = fc->irx_enable(fc, ir->dmach);
984263bc
MD
512 break;
513 case FW_GRSTREAM:
78748771
JS
514 if (d->ir != NULL) {
515 ichreq->ch = ir->flag & 0x3f;
516 ichreq->tag = ir->flag >> 2 & 0x3;
517 } else
518 err = EINVAL;
984263bc
MD
519 break;
520 case FW_SSTBUF:
78748771
JS
521 bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq));
522 break;
523 case FW_GSTBUF:
524 bzero(&ibufreq->rx, sizeof(ibufreq->rx));
525 if (ir != NULL) {
526 ibufreq->rx.nchunk = ir->bnchunk;
527 ibufreq->rx.npacket = ir->bnpacket;
528 ibufreq->rx.psize = ir->psize;
984263bc 529 }
78748771
JS
530 bzero(&ibufreq->tx, sizeof(ibufreq->tx));
531 if (it != NULL) {
532 ibufreq->tx.nchunk = it->bnchunk;
533 ibufreq->tx.npacket = it->bnpacket;
534 ibufreq->tx.psize = it->psize;
984263bc 535 }
78748771
JS
536 break;
537 case FW_ASYREQ:
538 {
539 struct tcode_info *tinfo;
540 int pay_len = 0;
984263bc 541
78748771
JS
542 fp = &asyreq->pkt;
543 tinfo = &sc->fc->tcode[fp->mode.hdr.tcode];
984263bc 544
78748771
JS
545 if ((tinfo->flag & FWTI_BLOCK_ASY) != 0)
546 pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len);
984263bc 547
78748771
JS
548 xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/);
549 if (xfer == NULL)
550 return (ENOMEM);
984263bc 551
984263bc
MD
552 switch (asyreq->req.type) {
553 case FWASREQNODE:
984263bc
MD
554 break;
555 case FWASREQEUI:
556 fwdev = fw_noderesolve_eui64(sc->fc,
557 &asyreq->req.dst.eui);
558 if (fwdev == NULL) {
559 device_printf(sc->fc->bdev,
560 "cannot find node\n");
561 err = EINVAL;
78748771 562 goto out;
984263bc 563 }
78748771 564 fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst;
984263bc
MD
565 break;
566 case FWASRESTL:
567 /* XXX what's this? */
568 break;
569 case FWASREQSTREAM:
570 /* nothing to do */
571 break;
572 }
78748771
JS
573
574 bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len);
575 if (pay_len > 0)
576 bcopy((char *)fp + tinfo->hdr_len,
577 (void *)&xfer->send.payload, pay_len);
578 xfer->send.spd = asyreq->req.sped;
984263bc 579 xfer->act.hand = fw_asy_callback;
78748771
JS
580
581 if ((err = fw_asyreq(sc->fc, -1, xfer)) != 0)
582 goto out;
583 if ((err = tsleep(xfer, FWPRI, "asyreq", hz)) != 0)
584 goto out;
585 if (xfer->resp != 0) {
586 err = EIO;
587 goto out;
984263bc 588 }
78748771
JS
589 if ((tinfo->flag & FWTI_TLABEL) == 0)
590 goto out;
591
592 /* copy response */
593 tinfo = &sc->fc->tcode[xfer->recv.hdr.mode.hdr.tcode];
594 if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len)
595 asyreq->req.len = xfer->recv.pay_len;
596 else
597 err = EINVAL;
598 bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len);
599 bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len,
600 MAX(0, asyreq->req.len - tinfo->hdr_len));
601out:
602 fw_xfer_free_buf(xfer);
984263bc 603 break;
78748771 604 }
984263bc
MD
605 case FW_IBUSRST:
606 sc->fc->ibr(sc->fc);
607 break;
608 case FW_CBINDADDR:
609 fwb = fw_bindlookup(sc->fc,
610 bindreq->start.hi, bindreq->start.lo);
611 if(fwb == NULL){
612 err = EINVAL;
613 break;
614 }
615 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
78748771 616 STAILQ_REMOVE(&ir->binds, fwb, fw_bind, chlist);
efda3bd0 617 kfree(fwb, M_FW);
984263bc
MD
618 break;
619 case FW_SBINDADDR:
620 if(bindreq->len <= 0 ){
621 err = EINVAL;
622 break;
623 }
624 if(bindreq->start.hi > 0xffff ){
625 err = EINVAL;
626 break;
627 }
efda3bd0 628 fwb = kmalloc(sizeof (struct fw_bind), M_FW, M_WAITOK);
78748771
JS
629 fwb->start = ((u_int64_t)bindreq->start.hi << 32) |
630 bindreq->start.lo;
631 fwb->end = fwb->start + bindreq->len;
632 /* XXX */
633 fwb->sub = ir->dmach;
984263bc
MD
634 fwb->act_type = FWACT_CH;
635
78748771 636 /* XXX alloc buf */
984263bc
MD
637 xfer = fw_xfer_alloc(M_FWXFER);
638 if(xfer == NULL){
efda3bd0 639 kfree(fwb, M_FW);
78748771 640 return (ENOMEM);
984263bc
MD
641 }
642 xfer->fc = sc->fc;
643
4e01b467 644 crit_enter();
984263bc
MD
645 /* XXX broken. need multiple xfer */
646 STAILQ_INIT(&fwb->xferlist);
647 STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link);
4e01b467 648 crit_exit();
984263bc
MD
649 err = fw_bindadd(sc->fc, fwb);
650 break;
651 case FW_GDEVLST:
652 i = len = 1;
653 /* myself */
654 devinfo = &fwdevlst->dev[0];
655 devinfo->dst = sc->fc->nodeid;
656 devinfo->status = 0; /* XXX */
657 devinfo->eui.hi = sc->fc->eui.hi;
658 devinfo->eui.lo = sc->fc->eui.lo;
659 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) {
660 if(len < FW_MAX_DEVLST){
661 devinfo = &fwdevlst->dev[len++];
662 devinfo->dst = fwdev->dst;
663 devinfo->status =
664 (fwdev->status == FWDEVINVAL)?0:1;
665 devinfo->eui.hi = fwdev->eui.hi;
666 devinfo->eui.lo = fwdev->eui.lo;
667 }
668 i++;
669 }
670 fwdevlst->n = i;
671 fwdevlst->info_len = len;
672 break;
673 case FW_GTPMAP:
fef8985e 674 bcopy(sc->fc->topology_map, ap->a_data,
984263bc
MD
675 (sc->fc->topology_map->crc_len + 1) * 4);
676 break;
677 case FW_GCROM:
678 STAILQ_FOREACH(fwdev, &sc->fc->devices, link)
679 if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui))
680 break;
681 if (fwdev == NULL) {
78748771
JS
682 if (!FW_EUI64_EQUAL(sc->fc->eui, crom_buf->eui)) {
683 err = FWNODE_INVAL;
684 break;
685 }
686 /* myself */
efda3bd0 687 ptr = kmalloc(CROMSIZE, M_FW, M_WAITOK);
78748771
JS
688 len = CROMSIZE;
689 for (i = 0; i < CROMSIZE/4; i++)
690 ((u_int32_t *)ptr)[i]
691 = ntohl(sc->fc->config_rom[i]);
692 } else {
693 /* found */
694 ptr = (void *)&fwdev->csrrom[0];
695 if (fwdev->rommax < CSRROMOFF)
696 len = 0;
697 else
698 len = fwdev->rommax - CSRROMOFF + 4;
984263bc 699 }
984263bc
MD
700 if (crom_buf->len < len)
701 len = crom_buf->len;
702 else
703 crom_buf->len = len;
78748771
JS
704 err = copyout(ptr, crom_buf->ptr, len);
705 if (fwdev == NULL)
706 /* myself */
efda3bd0 707 kfree(ptr, M_FW);
984263bc
MD
708 break;
709 default:
fef8985e 710 sc->fc->ioctl(ap);
984263bc
MD
711 break;
712 }
713 return err;
714}
715int
fef8985e 716fw_poll(struct dev_poll_args *ap)
984263bc 717{
b13267a5 718 cdev_t dev = ap->a_head.a_dev;
78748771
JS
719 struct firewire_softc *sc;
720 struct fw_xferq *ir;
984263bc
MD
721 int revents;
722 int tmp;
723 int unit = DEV2UNIT(dev);
984263bc
MD
724
725 if (DEV_FWMEM(dev))
fef8985e 726 return fwmem_poll(ap);
984263bc
MD
727
728 sc = devclass_get_softc(firewire_devclass, unit);
78748771 729 ir = ((struct fw_drv1 *)dev->si_drv1)->ir;
984263bc
MD
730 revents = 0;
731 tmp = POLLIN | POLLRDNORM;
fef8985e 732 if (ap->a_events & tmp) {
78748771 733 if (STAILQ_FIRST(&ir->q) != NULL)
984263bc
MD
734 revents |= tmp;
735 else
fef8985e 736 selrecord(curthread, &ir->rsel);
984263bc
MD
737 }
738 tmp = POLLOUT | POLLWRNORM;
fef8985e 739 if (ap->a_events & tmp) {
984263bc
MD
740 /* XXX should be fixed */
741 revents |= tmp;
742 }
fef8985e
MD
743 ap->a_events = revents;
744 return(0);
984263bc
MD
745}
746
747static int
fef8985e 748fw_mmap (struct dev_mmap_args *ap)
984263bc 749{
b13267a5 750 cdev_t dev = ap->a_head.a_dev;
78748771 751 struct firewire_softc *sc;
984263bc
MD
752 int unit = DEV2UNIT(dev);
753
754 if (DEV_FWMEM(dev))
fef8985e 755 return fwmem_mmap(ap);
78748771 756 sc = devclass_get_softc(firewire_devclass, unit);
984263bc
MD
757
758 return EINVAL;
759}
78748771 760
fef8985e
MD
761static int
762fw_strategy(struct dev_strategy_args *ap)
78748771 763{
b13267a5 764 cdev_t dev = ap->a_head.a_dev;
fef8985e 765 struct bio *bio = ap->a_bio;
81b5c339 766 struct buf *bp = bio->bio_buf;
78748771 767
78748771 768 if (DEV_FWMEM(dev)) {
fef8985e
MD
769 fwmem_strategy(ap);
770 return(0);
78748771 771 }
81b5c339
MD
772 bp->b_error = EOPNOTSUPP;
773 bp->b_flags |= B_ERROR;
774 bp->b_resid = bp->b_bcount;
775 biodone(bio);
fef8985e 776 return(0);
78748771
JS
777}
778
779int
780fwdev_makedev(struct firewire_softc *sc)
781{
78748771
JS
782 int unit;
783
784 unit = device_get_unit(sc->fc->bdev);
fef8985e 785 dev_ops_add(&firewire_ops, FW_UNITMASK, FW_UNIT(unit));
e4c9c0c8 786 return(0);
78748771
JS
787}
788
789int
790fwdev_destroydev(struct firewire_softc *sc)
791{
e4c9c0c8 792 int unit;
78748771 793
e4c9c0c8 794 unit = device_get_unit(sc->fc->bdev);
fef8985e 795 dev_ops_remove(&firewire_ops, FW_UNITMASK, FW_UNIT(unit));
e4c9c0c8 796 return(0);
78748771
JS
797}
798
90dec0df 799#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
78748771
JS
800#define NDEVTYPE 2
801void
b13267a5 802fwdev_clone(void *arg, char *name, int namelen, cdev_t *dev)
78748771
JS
803{
804 struct firewire_softc *sc;
805 char *devnames[NDEVTYPE] = {"fw", "fwmem"};
806 char *subp = NULL;
807 int devflag[NDEVTYPE] = {0, FWMEM_FLAG};
808 int i, unit = 0, sub = 0;
809
5711af4f 810 if (*dev != NOCDEV)
78748771
JS
811 return;
812
813 for (i = 0; i < NDEVTYPE; i++)
814 if (dev_stdclone(name, &subp, devnames[i], &unit) == 2)
815 goto found;
816 /* not match */
817 return;
818found:
819
820 if (subp == NULL || *subp++ != '.')
821 return;
822
823 /* /dev/fwU.S */
824 while (isdigit(*subp)) {
825 sub *= 10;
826 sub += *subp++ - '0';
827 }
828 if (*subp != '\0')
829 return;
830
831 sc = devclass_get_softc(firewire_devclass, unit);
832 if (sc == NULL)
833 return;
fef8985e 834 *dev = make_dev(&firewire_ops, MAKEMINOR(devflag[i], unit, sub),
78748771
JS
835 UID_ROOT, GID_OPERATOR, 0660,
836 "%s%d.%d", devnames[i], unit, sub);
837 (*dev)->si_flags |= SI_CHEAPCLONE;
838 dev_depends(sc->dev, *dev);
839 return;
840}
841#endif