Deleted Added
sdiff udiff text old ( 111753 ) new ( 111815 )
full compact
1/*
2 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the acknowledgement as bellow:
15 *
16 * This product includes software developed by K. Kobayashi and H. Shimokawa
17 *
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $FreeBSD: head/sys/dev/firewire/fwdev.c 111815 2003-03-03 12:15:54Z phk $
34 *
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/types.h>
40#include <sys/mbuf.h>
41
42#include <sys/kernel.h>
43#include <sys/malloc.h>
44#include <sys/conf.h>
45#include <sys/uio.h>
46#include <sys/poll.h>
47
48#include <sys/bus.h>
49
50#include <sys/ioccom.h>
51
52#include <dev/firewire/firewire.h>
53#include <dev/firewire/firewirereg.h>
54#include <dev/firewire/fwmem.h>
55#include <dev/firewire/iec68113.h>
56
57#define CDEV_MAJOR 127
58#define FWNODE_INVAL 0xffff
59
60static d_open_t fw_open;
61static d_close_t fw_close;
62static d_ioctl_t fw_ioctl;
63static d_poll_t fw_poll;
64static d_read_t fw_read; /* for Isochronous packet */
65static d_write_t fw_write;
66static d_mmap_t fw_mmap;
67
68struct cdevsw firewire_cdevsw =
69{
70 .d_open = fw_open,
71 .d_close = fw_close,
72 .d_read = fw_read,
73 .d_write = fw_write,
74 .d_ioctl = fw_ioctl,
75 .d_poll = fw_poll,
76 .d_mmap = fw_mmap,
77 .d_name = "fw",
78 .d_maj = CDEV_MAJOR,
79 .d_flags = D_MEM
80};
81
82static int
83fw_open (dev_t dev, int flags, int fmt, fw_proc *td)
84{
85 struct firewire_softc *sc;
86 int unit = DEV2UNIT(dev);
87 int sub = DEV2DMACH(dev);
88
89 int err = 0;
90
91 if (DEV_FWMEM(dev))
92 return fwmem_open(dev, flags, fmt, td);
93
94 sc = devclass_get_softc(firewire_devclass, unit);
95 if(sc->fc->ir[sub]->flag & FWXFERQ_OPEN){
96 err = EBUSY;
97 return err;
98 }
99 if(sc->fc->it[sub]->flag & FWXFERQ_OPEN){
100 err = EBUSY;
101 return err;
102 }
103 if(sc->fc->ir[sub]->flag & FWXFERQ_MODEMASK){
104 err = EBUSY;
105 return err;
106 }
107/* Default is per packet mode */
108 sc->fc->ir[sub]->flag |= FWXFERQ_OPEN;
109 sc->fc->it[sub]->flag |= FWXFERQ_OPEN;
110 sc->fc->ir[sub]->flag |= FWXFERQ_PACKET;
111 return err;
112}
113
114static int
115fw_close (dev_t dev, int flags, int fmt, fw_proc *td)
116{
117 struct firewire_softc *sc;
118 int unit = DEV2UNIT(dev);
119 int sub = DEV2DMACH(dev);
120 struct fw_xfer *xfer;
121 struct fw_bind *fwb;
122 int err = 0;
123
124 if (DEV_FWMEM(dev))
125 return fwmem_close(dev, flags, fmt, td);
126
127 sc = devclass_get_softc(firewire_devclass, unit);
128 if(!(sc->fc->ir[sub]->flag & FWXFERQ_OPEN)){
129 err = EINVAL;
130 return err;
131 }
132 sc->fc->ir[sub]->flag &= ~FWXFERQ_OPEN;
133 if(!(sc->fc->it[sub]->flag & FWXFERQ_OPEN)){
134 err = EINVAL;
135 return err;
136 }
137 sc->fc->it[sub]->flag &= ~FWXFERQ_OPEN;
138
139 if(sc->fc->ir[sub]->flag & FWXFERQ_RUNNING){
140 sc->fc->irx_disable(sc->fc, sub);
141 }
142 if(sc->fc->it[sub]->flag & FWXFERQ_RUNNING){
143 sc->fc->it[sub]->flag &= ~FWXFERQ_RUNNING;
144 sc->fc->itx_disable(sc->fc, sub);
145 }
146#ifdef FWXFERQ_DV
147 if(sc->fc->it[sub]->flag & FWXFERQ_DV){
148 struct fw_dvbuf *dvbuf;
149
150 if((dvbuf = sc->fc->it[sub]->dvproc) != NULL){
151 free(dvbuf->buf, M_FW);
152 sc->fc->it[sub]->dvproc = NULL;
153 }
154 if((dvbuf = sc->fc->it[sub]->dvdma) != NULL){
155 free(dvbuf->buf, M_FW);
156 sc->fc->it[sub]->dvdma = NULL;
157 }
158 while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvvalid)) != NULL){
159 STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvvalid, link);
160 free(dvbuf->buf, M_FW);
161 }
162 while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvfree)) != NULL){
163 STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvfree, link);
164 free(dvbuf->buf, M_FW);
165 }
166 free(sc->fc->it[sub]->dvbuf, M_FW);
167 sc->fc->it[sub]->dvbuf = NULL;
168 }
169#endif
170 if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){
171 free(sc->fc->ir[sub]->buf, M_FW);
172 sc->fc->ir[sub]->buf = NULL;
173 free(sc->fc->ir[sub]->bulkxfer, M_FW);
174 sc->fc->ir[sub]->bulkxfer = NULL;
175 sc->fc->ir[sub]->flag &= ~FWXFERQ_EXTBUF;
176 sc->fc->ir[sub]->psize = PAGE_SIZE;
177 sc->fc->ir[sub]->maxq = FWMAXQUEUE;
178 }
179 if(sc->fc->it[sub]->flag & FWXFERQ_EXTBUF){
180 free(sc->fc->it[sub]->buf, M_FW);
181 sc->fc->it[sub]->buf = NULL;
182 free(sc->fc->it[sub]->bulkxfer, M_FW);
183 sc->fc->it[sub]->bulkxfer = NULL;
184#ifdef FWXFERQ_DV
185 sc->fc->it[sub]->dvbuf = NULL;
186#endif
187 sc->fc->it[sub]->flag &= ~FWXFERQ_EXTBUF;
188 sc->fc->it[sub]->psize = 0;
189 sc->fc->it[sub]->maxq = FWMAXQUEUE;
190 }
191 for(xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q);
192 xfer != NULL; xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q)){
193 sc->fc->ir[sub]->queued--;
194 STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->q, link);
195
196 xfer->resp = 0;
197 switch(xfer->act_type){
198 case FWACT_XFER:
199 fw_xfer_done(xfer);
200 break;
201 default:
202 break;
203 }
204 fw_xfer_free(xfer);
205 }
206 for(fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds); fwb != NULL;
207 fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds)){
208 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
209 STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->binds, chlist);
210 free(fwb, M_FW);
211 }
212 sc->fc->ir[sub]->flag &= ~FWXFERQ_MODEMASK;
213 sc->fc->it[sub]->flag &= ~FWXFERQ_MODEMASK;
214 return err;
215}
216
217/*
218 * read request.
219 */
220static int
221fw_read (dev_t dev, struct uio *uio, int ioflag)
222{
223 struct firewire_softc *sc;
224 struct fw_xferq *ir;
225 struct fw_xfer *xfer;
226 int err = 0, s, slept = 0;
227 int unit = DEV2UNIT(dev);
228 int sub = DEV2DMACH(dev);
229 struct fw_pkt *fp;
230
231 if (DEV_FWMEM(dev))
232 return fwmem_read(dev, uio, ioflag);
233
234 sc = devclass_get_softc(firewire_devclass, unit);
235
236 ir = sc->fc->ir[sub];
237
238 if (ir->flag & FWXFERQ_PACKET) {
239 ir->stproc = NULL;
240 }
241readloop:
242 xfer = STAILQ_FIRST(&ir->q);
243 if ((ir->flag & FWXFERQ_PACKET) == 0 && ir->stproc == NULL) {
244 /* iso bulkxfer */
245 ir->stproc = STAILQ_FIRST(&ir->stvalid);
246 if (ir->stproc != NULL) {
247 s = splfw();
248 STAILQ_REMOVE_HEAD(&ir->stvalid, link);
249 splx(s);
250 ir->queued = 0;
251 }
252 }
253 if (xfer == NULL && ir->stproc == NULL) {
254 /* no data avaliable */
255 if (slept == 0) {
256 slept = 1;
257 if ((ir->flag & FWXFERQ_RUNNING) == 0
258 && (ir->flag & FWXFERQ_PACKET)) {
259 err = sc->fc->irx_enable(sc->fc, sub);
260 if (err)
261 return err;
262 }
263 ir->flag |= FWXFERQ_WAKEUP;
264 err = tsleep(ir, FWPRI, "fw_read", hz);
265 ir->flag &= ~FWXFERQ_WAKEUP;
266 if (err == 0)
267 goto readloop;
268 } else if (slept == 1)
269 err = EIO;
270 return err;
271 } else if(xfer != NULL) {
272 /* per packet mode */
273 s = splfw();
274 ir->queued --;
275 STAILQ_REMOVE_HEAD(&ir->q, link);
276 splx(s);
277 fp = (struct fw_pkt *)(xfer->recv.buf + xfer->recv.off);
278 if(sc->fc->irx_post != NULL)
279 sc->fc->irx_post(sc->fc, fp->mode.ld);
280 err = uiomove(xfer->recv.buf + xfer->recv.off, xfer->recv.len, uio);
281 fw_xfer_free( xfer);
282 } else if(ir->stproc != NULL) {
283 /* iso bulkxfer */
284 fp = (struct fw_pkt *)(ir->stproc->buf + ir->queued * ir->psize);
285 if(sc->fc->irx_post != NULL)
286 sc->fc->irx_post(sc->fc, fp->mode.ld);
287 if(ntohs(fp->mode.stream.len) == 0){
288 err = EIO;
289 return err;
290 }
291 err = uiomove((caddr_t)fp,
292 ntohs(fp->mode.stream.len) + sizeof(u_int32_t), uio);
293#if 0
294 fp->mode.stream.len = 0;
295#endif
296 ir->queued ++;
297 if(ir->queued >= ir->bnpacket){
298 s = splfw();
299 STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
300 splx(s);
301 sc->fc->irx_enable(sc->fc, sub);
302 ir->stproc = NULL;
303 }
304 if (uio->uio_resid >= ir->psize) {
305 slept = -1;
306 goto readloop;
307 }
308 }
309 return err;
310}
311
312static int
313fw_write (dev_t dev, struct uio *uio, int ioflag)
314{
315 int err = 0;
316 struct firewire_softc *sc;
317 int unit = DEV2UNIT(dev);
318 int sub = DEV2DMACH(dev);
319 int s, slept = 0;
320 struct fw_pkt *fp;
321 struct fw_xfer *xfer;
322 struct fw_xferq *xferq;
323 struct firewire_comm *fc;
324 struct fw_xferq *it;
325
326 if (DEV_FWMEM(dev))
327 return fwmem_write(dev, uio, ioflag);
328
329 sc = devclass_get_softc(firewire_devclass, unit);
330 fc = sc->fc;
331 it = sc->fc->it[sub];
332
333 fp = (struct fw_pkt *)uio->uio_iov->iov_base;
334 switch(fp->mode.common.tcode){
335 case FWTCODE_RREQQ:
336 case FWTCODE_RREQB:
337 case FWTCODE_LREQ:
338 err = EINVAL;
339 return err;
340 case FWTCODE_WREQQ:
341 case FWTCODE_WREQB:
342 xferq = fc->atq;
343 break;
344 case FWTCODE_STREAM:
345 if(it->flag & FWXFERQ_PACKET){
346 xferq = fc->atq;
347 }else{
348 xferq = NULL;
349 }
350 break;
351 case FWTCODE_WRES:
352 case FWTCODE_RRESQ:
353 case FWTCODE_RRESB:
354 case FWTCODE_LRES:
355 xferq = fc->ats;
356 break;
357 default:
358 err = EINVAL;
359 return err;
360 }
361 /* Discard unsent buffered stream packet, when sending Asyrequrst */
362 if(xferq != NULL && it->stproc != NULL){
363 s = splfw();
364 STAILQ_INSERT_TAIL(&it->stfree, it->stproc, link);
365 splx(s);
366 it->stproc = NULL;
367 }
368#ifdef FWXFERQ_DV
369 if(xferq == NULL && !(it->flag & FWXFERQ_DV)){
370#else
371 if (xferq == NULL) {
372#endif
373isoloop:
374 if (it->stproc == NULL) {
375 it->stproc = STAILQ_FIRST(&it->stfree);
376 if (it->stproc != NULL) {
377 s = splfw();
378 STAILQ_REMOVE_HEAD(&it->stfree, link);
379 splx(s);
380 it->queued = 0;
381 } else if (slept == 0) {
382 slept = 1;
383 err = sc->fc->itx_enable(sc->fc, sub);
384 if (err)
385 return err;
386 err = tsleep(it, FWPRI,
387 "fw_write", hz);
388 if (err)
389 return err;
390 goto isoloop;
391 } else {
392 err = EIO;
393 return err;
394 }
395 }
396 fp = (struct fw_pkt *)
397 (it->stproc->buf + it->queued * it->psize);
398 err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio);
399 err = uiomove((caddr_t)fp->mode.stream.payload,
400 ntohs(fp->mode.stream.len), uio);
401 it->queued ++;
402 if (it->queued >= it->bnpacket) {
403 s = splfw();
404 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
405 splx(s);
406 it->stproc = NULL;
407 err = sc->fc->itx_enable(sc->fc, sub);
408 }
409 if (uio->uio_resid >= sizeof(struct fw_isohdr)) {
410 slept = 0;
411 goto isoloop;
412 }
413 return err;
414 }
415#ifdef FWXFERQ_DV
416 if(xferq == NULL && it->flag & FWXFERQ_DV){
417dvloop:
418 if(it->dvproc == NULL){
419 it->dvproc = STAILQ_FIRST(&it->dvfree);
420 if(it->dvproc != NULL){
421 s = splfw();
422 STAILQ_REMOVE_HEAD(&it->dvfree, link);
423 splx(s);
424 it->dvptr = 0;
425 }else if(slept == 0){
426 slept = 1;
427 err = sc->fc->itx_enable(sc->fc, sub);
428 if(err){
429 return err;
430 }
431 err = tsleep(it, FWPRI, "fw_write", hz);
432 if(err){
433 return err;
434 }
435 goto dvloop;
436 }else{
437 err = EIO;
438 return err;
439 }
440 }
441#if 0 /* What's this for? (it->dvptr? overwritten by the following uiomove)*/
442 fp = (struct fw_pkt *)(it->dvproc->buf + it->queued * it->psize);
443 fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t));
444#endif
445 err = uiomove(it->dvproc->buf + it->dvptr,
446 uio->uio_resid, uio);
447 it->dvptr += it->psize;
448 if(err){
449 return err;
450 }
451 if(it->dvptr >= it->psize * it->dvpacket){
452 s = splfw();
453 STAILQ_INSERT_TAIL(&it->dvvalid, it->dvproc, link);
454 splx(s);
455 it->dvproc = NULL;
456 err = fw_tbuf_update(sc->fc, sub, 0);
457 if(err){
458 return err;
459 }
460 err = sc->fc->itx_enable(sc->fc, sub);
461 }
462 return err;
463 }
464#endif
465 if(xferq != NULL){
466 xfer = fw_xfer_alloc(M_FWXFER);
467 if(xfer == NULL){
468 err = ENOMEM;
469 return err;
470 }
471 xfer->send.buf = malloc(uio->uio_resid, M_FW, M_NOWAIT);
472 if(xfer->send.buf == NULL){
473 fw_xfer_free( xfer);
474 err = ENOBUFS;
475 return err;
476 }
477 xfer->dst = ntohs(fp->mode.hdr.dst);
478#if 0
479 switch(fp->mode.common.tcode){
480 case FWTCODE_WREQQ:
481 case FWTCODE_WREQB:
482 if((tl = fw_get_tlabel(fc, xfer)) == -1 ){
483 fw_xfer_free( xfer);
484 err = EAGAIN;
485 return err;
486 }
487 fp->mode.hdr.tlrt = tl << 2;
488 default:
489 break;
490 }
491
492 xfer->tl = fp->mode.hdr.tlrt >> 2;
493 xfer->tcode = fp->mode.common.tcode;
494 xfer->fc = fc;
495 xfer->q = xferq;
496 xfer->act_type = FWACT_XFER;
497 xfer->retry_req = fw_asybusy;
498#endif
499 xfer->send.len = uio->uio_resid;
500 xfer->send.off = 0;
501 xfer->spd = 0;/* XXX: how to setup it */
502 xfer->act.hand = fw_asy_callback;
503
504 err = uiomove(xfer->send.buf, uio->uio_resid, uio);
505 if(err){
506 fw_xfer_free( xfer);
507 return err;
508 }
509#if 0
510 fw_asystart(xfer);
511#else
512 fw_asyreq(fc, -1, xfer);
513#endif
514 err = tsleep(xfer, FWPRI, "fw_write", hz);
515 if(xfer->resp == EBUSY)
516 return EBUSY;
517 fw_xfer_free( xfer);
518 return err;
519 }
520 return EINVAL;
521}
522
523/*
524 * ioctl support.
525 */
526int
527fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
528{
529 struct firewire_softc *sc;
530 int unit = DEV2UNIT(dev);
531 int sub = DEV2DMACH(dev);
532 int i, len, err = 0;
533 struct fw_device *fwdev;
534 struct fw_bind *fwb;
535 struct fw_xferq *ir, *it;
536 struct fw_xfer *xfer;
537 struct fw_pkt *fp;
538 struct fw_devinfo *devinfo;
539
540 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data;
541 struct fw_asyreq *asyreq = (struct fw_asyreq *)data;
542 struct fw_isochreq *ichreq = (struct fw_isochreq *)data;
543 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data;
544 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data;
545 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data;
546
547 if (DEV_FWMEM(dev))
548 return fwmem_ioctl(dev, cmd, data, flag, td);
549
550 sc = devclass_get_softc(firewire_devclass, unit);
551 if (!data)
552 return(EINVAL);
553
554 switch (cmd) {
555 case FW_STSTREAM:
556 sc->fc->it[sub]->flag &= ~0xff;
557 sc->fc->it[sub]->flag |= (0x3f & ichreq->ch);
558 sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6);
559 err = 0;
560 break;
561 case FW_GTSTREAM:
562 ichreq->ch = sc->fc->it[sub]->flag & 0x3f;
563 ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3;
564 err = 0;
565 break;
566 case FW_SRSTREAM:
567 sc->fc->ir[sub]->flag &= ~0xff;
568 sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch);
569 sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6);
570 err = sc->fc->irx_enable(sc->fc, sub);
571 break;
572 case FW_GRSTREAM:
573 ichreq->ch = sc->fc->ir[sub]->flag & 0x3f;
574 ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3;
575 err = 0;
576 break;
577#ifdef FWXFERQ_DV
578 case FW_SSTDV:
579 ibufreq = (struct fw_isobufreq *)
580 malloc(sizeof(struct fw_isobufreq), M_FW, M_NOWAIT);
581 if(ibufreq == NULL){
582 err = ENOMEM;
583 break;
584 }
585#if DV_PAL
586#define FWDVPACKET 300
587#else
588#define FWDVPACKET 250
589#endif
590#define FWDVPMAX 512
591 ibufreq->rx.nchunk = 8;
592 ibufreq->rx.npacket = 50;
593 ibufreq->rx.psize = FWDVPMAX;
594
595 ibufreq->tx.nchunk = 5;
596 ibufreq->tx.npacket = FWDVPACKET + 30; /* > 320 or 267 */
597 ibufreq->tx.psize = FWDVPMAX;
598
599 err = fw_ioctl(dev, FW_SSTBUF, (caddr_t)ibufreq, flag, td);
600 sc->fc->it[sub]->dvpacket = FWDVPACKET;
601 free(ibufreq, M_FW);
602/* reserve a buffer space */
603#define NDVCHUNK 8
604 sc->fc->it[sub]->dvproc = NULL;
605 sc->fc->it[sub]->dvdma = NULL;
606 sc->fc->it[sub]->flag |= FWXFERQ_DV;
607 /* XXX check malloc failure */
608 sc->fc->it[sub]->dvbuf
609 = (struct fw_dvbuf *)malloc(sizeof(struct fw_dvbuf) * NDVCHUNK, M_FW, M_NOWAIT);
610 STAILQ_INIT(&sc->fc->it[sub]->dvvalid);
611 STAILQ_INIT(&sc->fc->it[sub]->dvfree);
612 for( i = 0 ; i < NDVCHUNK ; i++){
613 /* XXX check malloc failure */
614 sc->fc->it[sub]->dvbuf[i].buf
615 = malloc(FWDVPMAX * sc->fc->it[sub]->dvpacket, M_FW, M_NOWAIT);
616 STAILQ_INSERT_TAIL(&sc->fc->it[sub]->dvfree,
617 &sc->fc->it[sub]->dvbuf[i], link);
618 }
619 break;
620#endif
621 case FW_SSTBUF:
622 ir = sc->fc->ir[sub];
623 it = sc->fc->it[sub];
624
625 if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){
626 return(EBUSY);
627 }
628 if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){
629 return(EBUSY);
630 }
631 if((ibufreq->rx.nchunk *
632 ibufreq->rx.psize * ibufreq->rx.npacket) +
633 (ibufreq->tx.nchunk *
634 ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){
635 return(EINVAL);
636 }
637 if(ibufreq->rx.nchunk > FWSTMAXCHUNK ||
638 ibufreq->tx.nchunk > FWSTMAXCHUNK){
639 return(EINVAL);
640 }
641 ir->bulkxfer
642 = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_FW, 0);
643 if(ir->bulkxfer == NULL){
644 return(ENOMEM);
645 }
646 it->bulkxfer
647 = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_FW, 0);
648 if(it->bulkxfer == NULL){
649 return(ENOMEM);
650 }
651 ir->buf = malloc(
652 ibufreq->rx.nchunk * ibufreq->rx.npacket
653 /* XXX psize must be 2^n and less or
654 equal to PAGE_SIZE */
655 * ((ibufreq->rx.psize + 3) &~3),
656 M_FW, 0);
657 if(ir->buf == NULL){
658 free(ir->bulkxfer, M_FW);
659 free(it->bulkxfer, M_FW);
660 ir->bulkxfer = NULL;
661 it->bulkxfer = NULL;
662 it->buf = NULL;
663 return(ENOMEM);
664 }
665 it->buf = malloc(
666 ibufreq->tx.nchunk * ibufreq->tx.npacket
667 /* XXX psize must be 2^n and less or
668 equal to PAGE_SIZE */
669 * ((ibufreq->tx.psize + 3) &~3),
670 M_FW, 0);
671 if(it->buf == NULL){
672 free(ir->bulkxfer, M_FW);
673 free(it->bulkxfer, M_FW);
674 free(ir->buf, M_FW);
675 ir->bulkxfer = NULL;
676 it->bulkxfer = NULL;
677 it->buf = NULL;
678 return(ENOMEM);
679 }
680
681 ir->bnchunk = ibufreq->rx.nchunk;
682 ir->bnpacket = ibufreq->rx.npacket;
683 ir->psize = (ibufreq->rx.psize + 3) & ~3;
684 ir->queued = 0;
685
686 it->bnchunk = ibufreq->tx.nchunk;
687 it->bnpacket = ibufreq->tx.npacket;
688 it->psize = (ibufreq->tx.psize + 3) & ~3;
689 it->queued = 0;
690
691#ifdef FWXFERQ_DV
692 it->dvdbc = 0;
693 it->dvdiff = 0;
694 it->dvsync = 0;
695 it->dvoffset = 0;
696#endif
697
698 STAILQ_INIT(&ir->stvalid);
699 STAILQ_INIT(&ir->stfree);
700 STAILQ_INIT(&ir->stdma);
701 ir->stproc = NULL;
702
703 STAILQ_INIT(&it->stvalid);
704 STAILQ_INIT(&it->stfree);
705 STAILQ_INIT(&it->stdma);
706 it->stproc = NULL;
707
708 for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){
709 ir->bulkxfer[i].buf =
710 ir->buf +
711 i * sc->fc->ir[sub]->bnpacket *
712 sc->fc->ir[sub]->psize;
713 STAILQ_INSERT_TAIL(&ir->stfree,
714 &ir->bulkxfer[i], link);
715 ir->bulkxfer[i].npacket = ir->bnpacket;
716 }
717 for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){
718 it->bulkxfer[i].buf =
719 it->buf +
720 i * sc->fc->it[sub]->bnpacket *
721 sc->fc->it[sub]->psize;
722 STAILQ_INSERT_TAIL(&it->stfree,
723 &it->bulkxfer[i], link);
724 it->bulkxfer[i].npacket = it->bnpacket;
725 }
726 ir->flag &= ~FWXFERQ_MODEMASK;
727 ir->flag |= FWXFERQ_STREAM;
728 ir->flag |= FWXFERQ_EXTBUF;
729
730 it->flag &= ~FWXFERQ_MODEMASK;
731 it->flag |= FWXFERQ_STREAM;
732 it->flag |= FWXFERQ_EXTBUF;
733 err = 0;
734 break;
735 case FW_GSTBUF:
736 ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk;
737 ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket;
738 ibufreq->rx.psize = sc->fc->ir[sub]->psize;
739
740 ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk;
741 ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket;
742 ibufreq->tx.psize = sc->fc->it[sub]->psize;
743 break;
744 case FW_ASYREQ:
745 xfer = fw_xfer_alloc(M_FWXFER);
746 if(xfer == NULL){
747 err = ENOMEM;
748 return err;
749 }
750 fp = &asyreq->pkt;
751 switch (asyreq->req.type) {
752 case FWASREQNODE:
753 xfer->dst = ntohs(fp->mode.hdr.dst);
754 break;
755 case FWASREQEUI:
756 fwdev = fw_noderesolve_eui64(sc->fc,
757 &asyreq->req.dst.eui);
758 if (fwdev == NULL) {
759 device_printf(sc->fc->bdev,
760 "cannot find node\n");
761 err = EINVAL;
762 goto error;
763 }
764 xfer->dst = fwdev->dst;
765 fp->mode.hdr.dst = htons(FWLOCALBUS | xfer->dst);
766 break;
767 case FWASRESTL:
768 /* XXX what's this? */
769 break;
770 case FWASREQSTREAM:
771 /* nothing to do */
772 break;
773 }
774 xfer->spd = asyreq->req.sped;
775 xfer->send.len = asyreq->req.len;
776 xfer->send.buf = malloc(xfer->send.len, M_FW, M_NOWAIT);
777 if(xfer->send.buf == NULL){
778 return ENOMEM;
779 }
780 xfer->send.off = 0;
781 bcopy(fp, xfer->send.buf, xfer->send.len);
782 xfer->act.hand = fw_asy_callback;
783 err = fw_asyreq(sc->fc, sub, xfer);
784 if(err){
785 fw_xfer_free( xfer);
786 return err;
787 }
788 err = tsleep(xfer, FWPRI, "asyreq", hz);
789 if(err == 0){
790 if(asyreq->req.len >= xfer->recv.len){
791 asyreq->req.len = xfer->recv.len;
792 }else{
793 err = EINVAL;
794 }
795 bcopy(xfer->recv.buf + xfer->recv.off, fp, asyreq->req.len);
796 }
797error:
798 fw_xfer_free( xfer);
799 break;
800 case FW_IBUSRST:
801 sc->fc->ibr(sc->fc);
802 break;
803 case FW_CBINDADDR:
804 fwb = fw_bindlookup(sc->fc,
805 bindreq->start.hi, bindreq->start.lo);
806 if(fwb == NULL){
807 err = EINVAL;
808 break;
809 }
810 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist);
811 STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist);
812 free(fwb, M_FW);
813 break;
814 case FW_SBINDADDR:
815 if(bindreq->len <= 0 ){
816 err = EINVAL;
817 break;
818 }
819 if(bindreq->start.hi > 0xffff ){
820 err = EINVAL;
821 break;
822 }
823 fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT);
824 if(fwb == NULL){
825 err = ENOMEM;
826 break;
827 }
828 fwb->start_hi = bindreq->start.hi;
829 fwb->start_lo = bindreq->start.lo;
830 fwb->addrlen = bindreq->len;
831
832 xfer = fw_xfer_alloc(M_FWXFER);
833 if(xfer == NULL){
834 err = ENOMEM;
835 return err;
836 }
837 xfer->act_type = FWACT_CH;
838 xfer->sub = sub;
839 xfer->fc = sc->fc;
840
841 fwb->xfer = xfer;
842 err = fw_bindadd(sc->fc, fwb);
843 break;
844 case FW_GDEVLST:
845 i = len = 1;
846 /* myself */
847 devinfo = &fwdevlst->dev[0];
848 devinfo->dst = sc->fc->nodeid;
849 devinfo->status = 0; /* XXX */
850 devinfo->eui.hi = sc->fc->eui.hi;
851 devinfo->eui.lo = sc->fc->eui.lo;
852 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) {
853 if(len < FW_MAX_DEVLST){
854 devinfo = &fwdevlst->dev[len++];
855 devinfo->dst = fwdev->dst;
856 devinfo->status =
857 (fwdev->status == FWDEVINVAL)?0:1;
858 devinfo->eui.hi = fwdev->eui.hi;
859 devinfo->eui.lo = fwdev->eui.lo;
860 }
861 i++;
862 }
863 fwdevlst->n = i;
864 fwdevlst->info_len = len;
865 break;
866 case FW_GTPMAP:
867 bcopy(sc->fc->topology_map, data,
868 (sc->fc->topology_map->crc_len + 1) * 4);
869 break;
870 case FW_GCROM:
871 STAILQ_FOREACH(fwdev, &sc->fc->devices, link)
872 if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui))
873 break;
874 if (fwdev == NULL) {
875 err = FWNODE_INVAL;
876 break;
877 }
878#if 0
879 if (fwdev->csrrom[0] >> 24 == 1)
880 len = 4;
881 else
882 len = (1 + ((fwdev->csrrom[0] >> 16) & 0xff)) * 4;
883#else
884 if (fwdev->rommax < CSRROMOFF)
885 len = 0;
886 else
887 len = fwdev->rommax - CSRROMOFF + 4;
888#endif
889 if (crom_buf->len < len)
890 len = crom_buf->len;
891 else
892 crom_buf->len = len;
893 err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len);
894 break;
895 default:
896 sc->fc->ioctl (dev, cmd, data, flag, td);
897 break;
898 }
899 return err;
900}
901int
902fw_poll(dev_t dev, int events, fw_proc *td)
903{
904 int revents;
905 int tmp;
906 int unit = DEV2UNIT(dev);
907 int sub = DEV2DMACH(dev);
908 struct firewire_softc *sc;
909
910 if (DEV_FWMEM(dev))
911 return fwmem_poll(dev, events, td);
912
913 sc = devclass_get_softc(firewire_devclass, unit);
914 revents = 0;
915 tmp = POLLIN | POLLRDNORM;
916 if (events & tmp) {
917 if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL)
918 revents |= tmp;
919 else
920 selrecord(td, &sc->fc->ir[sub]->rsel);
921 }
922 tmp = POLLOUT | POLLWRNORM;
923 if (events & tmp) {
924 /* XXX should be fixed */
925 revents |= tmp;
926 }
927
928 return revents;
929}
930
931static int
932#if __FreeBSD_version < 500000
933fw_mmap (dev_t dev, vm_offset_t offset, int nproto)
934#else
935fw_mmap (dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nproto)
936#endif
937{
938 struct firewire_softc *fc;
939 int unit = DEV2UNIT(dev);
940
941 if (DEV_FWMEM(dev))
942#if __FreeBSD_version < 500000
943 return fwmem_mmap(dev, offset, nproto);
944#else
945 return fwmem_mmap(dev, offset, paddr, nproto);
946#endif
947
948 fc = devclass_get_softc(firewire_devclass, unit);
949
950 return EINVAL;
951}