1 /* 2 * Copyright 2007, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * JiSheng Zhang 7 * Jérôme DUVAL 8 */ 9 /*- 10 * Copyright (c) 2003 Hidetoshi Shimokawa 11 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 12 * All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the acknowledgement as bellow: 24 * 25 * This product includes software developed by K. Kobayashi and H. Shimokawa 26 * 27 * 4. The name of the author may not be used to endorse or promote products 28 * derived from this software without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 31 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 33 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 34 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 35 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 36 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 38 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 39 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 40 * POSSIBILITY OF SUCH DAMAGE. 41 * 42 * $FreeBSD: src/sys/dev/firewire/fwdev.c,v 1.52 2007/06/06 14:31:36 simokawa Exp $ 43 * 44 */ 45 46 #include <sys/param.h> 47 #include <sys/types.h> 48 49 #include <Drivers.h> 50 #include <OS.h> 51 #include <KernelExport.h> 52 #include <malloc.h> 53 #include <module.h> 54 #include <stdio.h> 55 #include <ByteOrder.h> 56 #include <string.h> 57 #include <sys/ioccom.h> 58 59 #include "queue.h" 60 #include "firewire.h" 61 #include "iec13213.h" 62 #include "firewirereg.h" 63 #include "fwdma.h" 64 //#include "fwmem.h" 65 #include "iec68113.h" 66 67 #define TRACE(x...) 68 //#define TRACE(x...) dprintf(x) 69 70 #include "firewire_module.h" 71 72 #define FWNODE_INVAL 0xffff 73 74 int32 api_version = B_CUR_DRIVER_API_VERSION; 75 struct fw_module_info *gFirewire; 76 const char fwname[] = "bus/fw/%ld"; 77 #define FWNAMEMAX 9 78 static char ** devices; 79 uint32 devices_count = 0; 80 81 82 struct fw_drv1 { 83 struct firewire_comm *fc; 84 struct fw_xferq *ir; 85 struct fw_xferq *it; 86 struct fw_isobufreq bufreq; 87 STAILQ_HEAD(, fw_bind) binds; 88 STAILQ_HEAD(, fw_xfer) rq; 89 sem_id rqSem; 90 }; 91 92 static int 93 fwdev_allocbuf(struct fw_xferq *q, 94 struct fw_bufspec *b) 95 { 96 int i; 97 98 if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF)) 99 return(EBUSY); 100 101 q->bulkxfer = (struct fw_bulkxfer *) malloc( 102 sizeof(struct fw_bulkxfer) * b->nchunk); 103 if (q->bulkxfer == NULL) 104 return(ENOMEM); 105 106 b->psize = roundup2(b->psize, sizeof(uint32_t)); 107 q->buf = gFirewire->fwdma_malloc_multiseg(sizeof(uint32_t), 108 b->psize, b->nchunk * b->npacket); 109 TRACE("fwdev_allocbuf %d\n", b->psize*b->nchunk*b->npacket); 110 if (q->buf == NULL) { 111 free(q->bulkxfer); 112 q->bulkxfer = NULL; 113 return(ENOMEM); 114 } 115 q->bnchunk = b->nchunk; 116 q->bnpacket = b->npacket; 117 q->psize = (b->psize + 3) & ~3; 118 q->queued = 0; 119 120 STAILQ_INIT(&q->stvalid); 121 STAILQ_INIT(&q->stfree); 122 STAILQ_INIT(&q->stdma); 123 q->stproc = NULL; 124 125 for (i = 0 ; i < q->bnchunk; i++) { 126 q->bulkxfer[i].poffset = i * q->bnpacket; 127 //q->bulkxfer[i].mbuf = NULL; //to be completed when find mbuf's counterpart 128 STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link); 129 } 130 131 q->flag &= ~FWXFERQ_MODEMASK; 132 q->flag |= FWXFERQ_STREAM; 133 q->flag |= FWXFERQ_EXTBUF; 134 135 return (0); 136 } 137 138 static int 139 fwdev_freebuf(struct fw_xferq *q) 140 { 141 if (q->flag & FWXFERQ_EXTBUF) { 142 if (q->buf != NULL) 143 gFirewire->fwdma_free_multiseg(q->buf); 144 q->buf = NULL; 145 free(q->bulkxfer); 146 q->bulkxfer = NULL; 147 q->flag &= ~FWXFERQ_EXTBUF; 148 q->psize = 0; 149 q->maxq = FWMAXQUEUE; 150 } 151 return (0); 152 } 153 154 155 static status_t 156 fw_open (const char *name, uint32 flags, void **cookie) 157 { 158 int32 count = -1; 159 int32 i; 160 struct fw_drv1 *d; 161 struct firewire_softc *sc = NULL; 162 163 *cookie = NULL; 164 for (i = 0; i < devices_count; i++) { 165 if (strcmp(name, devices[i]) == 0) { 166 count = i; 167 break; 168 } 169 } 170 171 if (count < 0) { 172 return B_BAD_VALUE; 173 } 174 175 if (gFirewire->get_handle(count, &sc) != B_OK) { 176 return ENODEV; 177 } 178 179 if (sc == NULL) 180 return (ENXIO); 181 182 FW_GLOCK(sc->fc); 183 if (*cookie != NULL) { 184 FW_GUNLOCK(sc->fc); 185 return (EBUSY); 186 } 187 /* set dummy value for allocation */ 188 *cookie = (void *)-1; 189 FW_GUNLOCK(sc->fc); 190 191 *cookie = malloc(sizeof(struct fw_drv1)); 192 if (*cookie == NULL) 193 return (ENOMEM); 194 memset(*cookie, 0, sizeof(struct fw_drv1)); 195 196 d = (struct fw_drv1 *)(*cookie); 197 d->fc = sc->fc; 198 STAILQ_INIT(&d->binds); 199 STAILQ_INIT(&d->rq); 200 d->rqSem = create_sem(0, "fw_raw rq"); 201 if (d->rqSem < B_OK) { 202 dprintf("fwraw: failed creating rq semaphore\n"); 203 free(*cookie); 204 return B_ERROR; 205 } 206 207 return B_OK; 208 } 209 210 211 static status_t 212 fw_close (void *cookie) 213 { 214 return B_OK; 215 } 216 217 218 static status_t 219 fw_free(void *cookie) 220 { 221 struct firewire_comm *fc; 222 struct fw_drv1 *d; 223 struct fw_xfer *xfer; 224 struct fw_bind *fwb; 225 226 TRACE("fw_free\n"); 227 d = (struct fw_drv1 *)cookie; 228 delete_sem(d->rqSem); 229 fc = d->fc; 230 231 /* remove binding */ 232 for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL; 233 fwb = STAILQ_FIRST(&d->binds)) { 234 gFirewire->fw_bindremove(fc, fwb); 235 STAILQ_REMOVE_HEAD(&d->binds, chlist); 236 gFirewire->fw_xferlist_remove(&fwb->xferlist); 237 free(fwb); 238 } 239 if (d->ir != NULL) { 240 struct fw_xferq *ir = d->ir; 241 242 if ((ir->flag & FWXFERQ_OPEN) == 0) 243 return (EINVAL); 244 if (ir->flag & FWXFERQ_RUNNING) { 245 ir->flag &= ~FWXFERQ_RUNNING; 246 fc->irx_disable(fc, ir->dmach); 247 } 248 /* free extbuf */ 249 fwdev_freebuf(ir); 250 /* drain receiving buffer */ 251 for (xfer = STAILQ_FIRST(&ir->q); 252 xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) { 253 ir->queued --; 254 STAILQ_REMOVE_HEAD(&ir->q, link); 255 256 xfer->resp = 0; 257 gFirewire->fw_xfer_done(xfer); 258 } 259 ir->flag &= ~(FWXFERQ_OPEN | 260 FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 261 d->ir = NULL; 262 263 } 264 if (d->it != NULL) { 265 struct fw_xferq *it = d->it; 266 267 if ((it->flag & FWXFERQ_OPEN) == 0) 268 return (EINVAL); 269 if (it->flag & FWXFERQ_RUNNING) { 270 it->flag &= ~FWXFERQ_RUNNING; 271 fc->itx_disable(fc, it->dmach); 272 } 273 /* free extbuf */ 274 fwdev_freebuf(it); 275 it->flag &= ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 276 d->it = NULL; 277 } 278 free(d); 279 d = NULL; 280 281 return B_OK; 282 } 283 284 285 static int 286 fw_read_async(struct fw_drv1 *d, off_t position, void *buf, size_t *num_bytes) 287 { 288 int err = 0; 289 struct fw_xfer *xfer; 290 struct fw_bind *fwb; 291 struct fw_pkt *fp; 292 struct tcode_info *tinfo; 293 cpu_status s; 294 295 int len, pbytes = (int)*num_bytes;//pbytes:to be processed bytes 296 *num_bytes = 0; 297 298 FW_GLOCK(d->fc); 299 while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == B_OK) { 300 //err = msleep(&d->rq, FW_GMTX(d->fc), FWPRI, "fwra", 0); 301 FW_GUNLOCK(d->fc); 302 err = acquire_sem_etc(d->rqSem, 1, B_CAN_INTERRUPT | B_TIMEOUT, 303 B_INFINITE_TIMEOUT);//B_INFINITE_TIMEOUT means no timeout? 304 FW_GLOCK(d->fc); 305 } 306 307 // if (err != 0) { 308 if (err != B_OK) { 309 310 FW_GUNLOCK(d->fc); 311 return (err); 312 } 313 314 s = splfw(); 315 STAILQ_REMOVE_HEAD(&d->rq, link); 316 FW_GUNLOCK(xfer->fc); 317 splx(s); 318 fp = &xfer->recv.hdr; 319 #if 0 /* for GASP ?? */ 320 if (fc->irx_post != NULL) 321 fc->irx_post(fc, fp->mode.ld); 322 #endif 323 tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode]; 324 // err = uiomove((void *)fp, tinfo->hdr_len, uio); 325 len = tinfo->hdr_len; 326 len = MIN(len, pbytes); 327 err = user_memcpy(buf, fp, len); 328 pbytes -= len; 329 *num_bytes += len; 330 buf = (void *)((caddr_t)buf + len); 331 332 // if (err) 333 if (err < B_OK) { 334 goto out; 335 } 336 337 // err = uiomove((void *)xfer->recv.payload, xfer->recv.pay_len, uio); 338 len = xfer->recv.pay_len; 339 len = MIN(len, pbytes); 340 err = user_memcpy(buf, (void *)xfer->recv.payload, len); 341 pbytes -= len; 342 *num_bytes += len;//get have been processed bytes num 343 buf = (void *)((caddr_t)buf + len); 344 345 out: 346 /* recycle this xfer */ 347 fwb = (struct fw_bind *)xfer->sc; 348 gFirewire->fw_xfer_unload(xfer); 349 xfer->recv.pay_len = B_PAGE_SIZE; 350 FW_GLOCK(xfer->fc); 351 STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 352 FW_GUNLOCK(xfer->fc); 353 return (err); 354 } 355 356 357 /* 358 * read request. 359 */ 360 static status_t 361 fw_read (void *cookie, off_t position, void *buf, size_t *num_bytes) 362 { 363 struct fw_drv1 *d; 364 struct fw_xferq *ir; 365 struct firewire_comm *fc; 366 int err = 0, slept = 0; 367 struct fw_pkt *fp; 368 cpu_status s; 369 370 int len, pbytes = (int)*num_bytes; 371 *num_bytes = 0; 372 373 d = (struct fw_drv1 *)cookie; 374 fc = d->fc; 375 ir = d->ir; 376 377 if (ir == NULL) 378 return (fw_read_async(d, position, buf, num_bytes)); 379 380 if (ir->buf == NULL) 381 return (EIO); 382 383 FW_GLOCK(fc); 384 readloop: 385 if (ir->stproc == NULL) { 386 /* iso bulkxfer */ 387 ir->stproc = STAILQ_FIRST(&ir->stvalid); 388 if (ir->stproc != NULL) { 389 s = splfw(); 390 STAILQ_REMOVE_HEAD(&ir->stvalid, link); 391 splx(s); 392 ir->queued = 0; 393 } 394 } 395 if (ir->stproc == NULL) { 396 /* no data avaliable */ 397 if (slept == 0) { 398 slept = 1; 399 ir->flag |= FWXFERQ_WAKEUP; 400 //err = msleep(ir, FW_GMTX(fc), FWPRI, "fw_read", hz); 401 FW_GUNLOCK(fc); 402 err = acquire_sem_etc(ir->Sem, 1, B_CAN_INTERRUPT | B_TIMEOUT, 1000000); 403 FW_GLOCK(fc); 404 405 ir->flag &= ~FWXFERQ_WAKEUP; 406 if (err == B_OK) 407 goto readloop; 408 } else if (slept == 1) 409 err = EIO; 410 FW_GUNLOCK(fc); 411 return err; 412 } else if (ir->stproc != NULL) { 413 /* iso bulkxfer */ 414 FW_GUNLOCK(fc); 415 fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 416 ir->stproc->poffset + ir->queued); 417 if (fc->irx_post != NULL) 418 fc->irx_post(fc, fp->mode.ld); 419 if (fp->mode.stream.len == 0) { 420 err = EIO; 421 return err; 422 } 423 // err = uiomove((caddr_t)fp, 424 // fp->mode.stream.len + sizeof(uint32_t), uio); 425 len = fp->mode.stream.len + sizeof(uint32_t); 426 len = MIN(len, pbytes); 427 err = user_memcpy(buf, (void *)fp, len); 428 pbytes -= len; 429 *num_bytes += len; 430 buf = (void *)((caddr_t)buf + len); 431 432 ir->queued ++; 433 if (ir->queued >= ir->bnpacket) { 434 s = splfw(); 435 STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 436 splx(s); 437 fc->irx_enable(fc, ir->dmach); 438 ir->stproc = NULL; 439 } 440 if (pbytes >= ir->psize) { 441 slept = -1; 442 FW_GLOCK(fc); 443 goto readloop; 444 } 445 } 446 return err; 447 } 448 449 450 static int 451 fw_write_async(struct fw_drv1 *d, off_t position, const void *buf, 452 size_t *num_bytes) 453 { 454 struct fw_xfer *xfer; 455 struct fw_pkt pkt; 456 struct tcode_info *tinfo; 457 int err; 458 459 int len, pbytes = (int)*num_bytes; 460 *num_bytes = 0; 461 462 bzero(&pkt, sizeof(struct fw_pkt)); 463 // if ((err = uiomove((caddr_t)&pkt, sizeof(uint32_t), uio))) 464 len = sizeof(uint32_t); 465 len = MIN(len, pbytes); 466 err = user_memcpy(&pkt, buf, len); 467 pbytes -= len; 468 *num_bytes += len; 469 buf = (void *)((caddr_t)buf + len); 470 if (err < B_OK) 471 return (err); 472 473 tinfo = &d->fc->tcode[pkt.mode.hdr.tcode]; 474 // if ((err = uiomove((caddr_t)&pkt + sizeof(uint32_t), 475 // tinfo->hdr_len - sizeof(uint32_t), uio))) 476 len = tinfo->hdr_len - sizeof(uint32_t); 477 len = MIN(len, pbytes); 478 err = user_memcpy((void*)((caddr_t)&pkt + sizeof(uint32_t)), 479 buf, len); 480 pbytes -= len; 481 *num_bytes += len; 482 buf = (void *)((caddr_t)buf + len); 483 484 if (err < B_OK) 485 return (err); 486 487 if ((xfer = gFirewire->fw_xfer_alloc_buf(pbytes, 488 B_PAGE_SIZE/*XXX*/)) == NULL) 489 return (ENOMEM); 490 491 bcopy(&pkt, &xfer->send.hdr, sizeof(struct fw_pkt)); 492 // xfer->send.pay_len = uio->uio_resid; 493 xfer->send.pay_len = pbytes; 494 495 /* if (uio->uio_resid > 0) { 496 if ((err = uiomove((caddr_t)&xfer->send.payload[0], 497 uio->uio_resid, uio)));// here the FreeBSD's stack author may be careless? 498 goto out; 499 }*/ 500 if (pbytes > 0) { 501 len = pbytes; 502 err = user_memcpy((void*)&xfer->send.payload[0], 503 buf, len); 504 pbytes -= len; 505 *num_bytes += len; 506 buf = (void *)((caddr_t)buf + len); 507 if (err < B_OK) 508 goto out; 509 } 510 511 xfer->fc = d->fc; 512 xfer->sc = NULL; 513 xfer->hand = gFirewire->fw_xferwake; 514 xfer->send.spd = 2 /* XXX */; 515 516 if ((err = gFirewire->fw_asyreq(xfer->fc, -1, xfer))) 517 goto out; 518 519 if ((err = gFirewire->fw_xferwait(xfer))) 520 goto out; 521 522 if (xfer->resp != 0) { 523 err = xfer->resp; 524 goto out; 525 } 526 527 if (xfer->flag & FWXF_RCVD) { 528 FW_GLOCK(xfer->fc); 529 STAILQ_INSERT_TAIL(&d->rq, xfer, link); 530 FW_GUNLOCK(xfer->fc); 531 return B_OK; 532 } 533 534 out: 535 gFirewire->fw_xfer_free(xfer); 536 return (err); 537 } 538 539 540 static status_t 541 fw_write (void *cookie, off_t position, const void *buf, size_t *num_bytes) 542 { 543 int err = 0; 544 int slept = 0; 545 struct fw_drv1 *d; 546 struct fw_pkt *fp; 547 struct firewire_comm *fc; 548 struct fw_xferq *it; 549 cpu_status s; 550 551 int len, pbytes = (int)*num_bytes; 552 *num_bytes = 0; 553 554 d = (struct fw_drv1 *)cookie; 555 fc = d->fc; 556 it = d->it; 557 558 if (it == NULL) 559 return (fw_write_async(d, position, buf, num_bytes)); 560 561 if (it->buf == NULL) 562 return (EIO); 563 564 FW_GLOCK(fc); 565 isoloop: 566 if (it->stproc == NULL) { 567 it->stproc = STAILQ_FIRST(&it->stfree); 568 if (it->stproc != NULL) { 569 s = splfw(); 570 STAILQ_REMOVE_HEAD(&it->stfree, link); 571 splx(s); 572 it->queued = 0; 573 } else if (slept == 0) { 574 slept = 1; 575 #if 0 /* XXX to avoid lock recursion */ 576 err = fc->itx_enable(fc, it->dmach); 577 if (err) 578 goto out; 579 #endif 580 // err = msleep(it, FW_GMTX(fc), FWPRI, "fw_write", hz); 581 FW_GUNLOCK(fc); 582 err = acquire_sem_etc(it->Sem, 1, B_CAN_INTERRUPT | B_TIMEOUT, 1000000); 583 FW_GLOCK(fc); 584 585 // if (err) 586 if (err < B_OK) 587 goto out; 588 goto isoloop; 589 } else { 590 err = EIO; 591 goto out; 592 } 593 } 594 FW_GUNLOCK(fc); 595 fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 596 it->stproc->poffset + it->queued); 597 // err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 598 len = sizeof(struct fw_isohdr); 599 len = MIN(len, pbytes); 600 err = user_memcpy(fp, buf, len); 601 pbytes -= len; 602 *num_bytes += len; 603 buf = (void *)((caddr_t)buf + len); 604 605 // err = uiomove((caddr_t)fp->mode.stream.payload, 606 // fp->mode.stream.len, uio); 607 len = fp->mode.stream.len; 608 len = MIN(len, pbytes); 609 err = user_memcpy(fp->mode.stream.payload, buf, len); 610 pbytes -= len; 611 *num_bytes += len; 612 buf = (void *)((caddr_t)buf + len); 613 614 it->queued ++; 615 if (it->queued >= it->bnpacket) { 616 s = splfw(); 617 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 618 splx(s); 619 it->stproc = NULL; 620 err = fc->itx_enable(fc, it->dmach); 621 } 622 // if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 623 if (pbytes >= sizeof(struct fw_isohdr)) { 624 slept = 0; 625 FW_GLOCK(fc); 626 goto isoloop; 627 } 628 return err; 629 630 out: 631 FW_GUNLOCK(fc); 632 return err; 633 } 634 635 636 static void 637 fw_hand(struct fw_xfer *xfer) 638 { 639 struct fw_bind *fwb; 640 struct fw_drv1 *d; 641 642 fwb = (struct fw_bind *)xfer->sc; 643 d = (struct fw_drv1 *)fwb->sc; 644 FW_GLOCK(xfer->fc); 645 STAILQ_INSERT_TAIL(&d->rq, xfer, link); 646 FW_GUNLOCK(xfer->fc); 647 // wakeup(&d->rq); 648 release_sem_etc(d->rqSem, 1, B_DO_NOT_RESCHEDULE); 649 } 650 651 652 /* 653 * ioctl support. 654 */ 655 static status_t 656 fw_ioctl (void *cookie, uint32 cmd, void *data, size_t length) 657 { 658 struct firewire_comm *fc; 659 struct fw_drv1 *d; 660 int i, len, err = 0; 661 struct fw_device *fwdev; 662 struct fw_bind *fwb; 663 struct fw_xferq *ir, *it; 664 struct fw_xfer *xfer; 665 struct fw_pkt *fp; 666 struct fw_devinfo *devinfo; 667 void *ptr; 668 669 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 670 struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 671 struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 672 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 673 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 674 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 675 676 if (!data) 677 return(EINVAL); 678 679 d = (struct fw_drv1 *)cookie; 680 fc = d->fc; 681 ir = d->ir; 682 it = d->it; 683 684 switch (cmd) { 685 case FW_STSTREAM: 686 if (it == NULL) { 687 i = gFirewire->fw_open_isodma(fc, /* tx */1); 688 if (i < 0) { 689 err = EBUSY; 690 break; 691 } 692 it = fc->it[i]; 693 err = fwdev_allocbuf(it, &d->bufreq.tx); 694 if (err) { 695 it->flag &= ~FWXFERQ_OPEN; 696 break; 697 } 698 } 699 it->flag &= ~0xff; 700 it->flag |= (0x3f & ichreq->ch); 701 it->flag |= ((0x3 & ichreq->tag) << 6); 702 d->it = it; 703 break; 704 case FW_GTSTREAM: 705 if (it != NULL) { 706 ichreq->ch = it->flag & 0x3f; 707 ichreq->tag = it->flag >> 2 & 0x3; 708 } else 709 err = EINVAL; 710 break; 711 case FW_SRSTREAM: 712 if (ir == NULL) { 713 i = gFirewire->fw_open_isodma(fc, /* tx */0); 714 if (i < 0) { 715 err = EBUSY; 716 break; 717 } 718 ir = fc->ir[i]; 719 err = fwdev_allocbuf(ir, &d->bufreq.rx); 720 if (err) { 721 ir->flag &= ~FWXFERQ_OPEN; 722 break; 723 } 724 } 725 ir->flag &= ~0xff; 726 ir->flag |= (0x3f & ichreq->ch); 727 ir->flag |= ((0x3 & ichreq->tag) << 6); 728 d->ir = ir; 729 err = fc->irx_enable(fc, ir->dmach); 730 break; 731 case FW_GRSTREAM: 732 if (d->ir != NULL) { 733 ichreq->ch = ir->flag & 0x3f; 734 ichreq->tag = ir->flag >> 2 & 0x3; 735 } else 736 err = EINVAL; 737 break; 738 case FW_SSTBUF: 739 bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq)); 740 break; 741 case FW_GSTBUF: 742 bzero(&ibufreq->rx, sizeof(ibufreq->rx)); 743 if (ir != NULL) { 744 ibufreq->rx.nchunk = ir->bnchunk; 745 ibufreq->rx.npacket = ir->bnpacket; 746 ibufreq->rx.psize = ir->psize; 747 } 748 bzero(&ibufreq->tx, sizeof(ibufreq->tx)); 749 if (it != NULL) { 750 ibufreq->tx.nchunk = it->bnchunk; 751 ibufreq->tx.npacket = it->bnpacket; 752 ibufreq->tx.psize = it->psize; 753 } 754 break; 755 case FW_ASYREQ: 756 { 757 struct tcode_info *tinfo; 758 int pay_len = 0; 759 760 fp = &asyreq->pkt; 761 tinfo = &fc->tcode[fp->mode.hdr.tcode]; 762 763 if ((tinfo->flag & FWTI_BLOCK_ASY) != 0) 764 pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len); 765 766 xfer = gFirewire->fw_xfer_alloc_buf(pay_len, B_PAGE_SIZE/*XXX*/); 767 if (xfer == NULL) 768 return (ENOMEM); 769 770 switch (asyreq->req.type) { 771 case FWASREQNODE: 772 break; 773 case FWASREQEUI: 774 fwdev = gFirewire->fw_noderesolve_eui64(fc, 775 &asyreq->req.dst.eui); 776 if (fwdev == NULL) { 777 dprintf("FWASREQEUI cannot find node\n"); 778 err = EINVAL; 779 goto out; 780 } 781 fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst; 782 break; 783 case FWASRESTL: 784 /* XXX what's this? */ 785 break; 786 case FWASREQSTREAM: 787 /* nothing to do */ 788 break; 789 } 790 791 bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len); 792 if (pay_len > 0) 793 bcopy((char *)fp + tinfo->hdr_len, 794 (void *)xfer->send.payload, pay_len); 795 xfer->send.spd = asyreq->req.sped; 796 xfer->hand = gFirewire->fw_xferwake; 797 798 if ((err = gFirewire->fw_asyreq(fc, -1, xfer)) != 0) 799 goto out; 800 if ((err = gFirewire->fw_xferwait(xfer)) != 0) 801 goto out; 802 if (xfer->resp != 0) { 803 err = EIO; 804 goto out; 805 } 806 if ((tinfo->flag & FWTI_TLABEL) == 0) 807 goto out; 808 809 /* copy response */ 810 tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode]; 811 if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB || 812 xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) { 813 pay_len = xfer->recv.pay_len; 814 if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) { 815 asyreq->req.len = xfer->recv.pay_len + 816 tinfo->hdr_len; 817 } else { 818 err = EINVAL; 819 pay_len = 0; 820 } 821 } else { 822 pay_len = 0; 823 } 824 bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len); 825 bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, pay_len); 826 out: 827 gFirewire->fw_xfer_free_buf(xfer); 828 break; 829 } 830 case FW_IBUSRST: 831 fc->ibr(fc); 832 break; 833 case FW_CBINDADDR: 834 fwb = gFirewire->fw_bindlookup(fc, 835 bindreq->start.hi, bindreq->start.lo); 836 if (fwb == NULL) { 837 err = EINVAL; 838 break; 839 } 840 gFirewire->fw_bindremove(fc, fwb); 841 STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist); 842 gFirewire->fw_xferlist_remove(&fwb->xferlist); 843 free(fwb); 844 break; 845 case FW_SBINDADDR: 846 if (bindreq->len <= 0) { 847 err = EINVAL; 848 break; 849 } 850 if (bindreq->start.hi > 0xffff) { 851 err = EINVAL; 852 break; 853 } 854 fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind)); 855 if (fwb == NULL) { 856 err = ENOMEM; 857 break; 858 } 859 fwb->start = ((u_int64_t)bindreq->start.hi << 32) | 860 bindreq->start.lo; 861 fwb->end = fwb->start + bindreq->len; 862 fwb->sc = (void *)d; 863 STAILQ_INIT(&fwb->xferlist); 864 err = gFirewire->fw_bindadd(fc, fwb); 865 if (err == 0) { 866 gFirewire->fw_xferlist_add(&fwb->xferlist, 867 /* XXX */ 868 B_PAGE_SIZE, B_PAGE_SIZE, 5, 869 fc, (void *)fwb, fw_hand); 870 STAILQ_INSERT_TAIL(&d->binds, fwb, chlist); 871 } 872 break; 873 case FW_GDEVLST: 874 i = len = 1; 875 /* myself */ 876 devinfo = &fwdevlst->dev[0]; 877 devinfo->dst = fc->nodeid; 878 devinfo->status = 0; /* XXX */ 879 devinfo->eui.hi = fc->eui.hi; 880 devinfo->eui.lo = fc->eui.lo; 881 STAILQ_FOREACH(fwdev, &fc->devices, link) { 882 if (len < FW_MAX_DEVLST) { 883 devinfo = &fwdevlst->dev[len++]; 884 devinfo->dst = fwdev->dst; 885 devinfo->status = 886 (fwdev->status == FWDEVINVAL) ? 0 : 1; 887 devinfo->eui.hi = fwdev->eui.hi; 888 devinfo->eui.lo = fwdev->eui.lo; 889 } 890 i++; 891 } 892 fwdevlst->n = i; 893 fwdevlst->info_len = len; 894 break; 895 case FW_GTPMAP: 896 bcopy(fc->topology_map, data, 897 (fc->topology_map->crc_len + 1) * 4); 898 break; 899 case FW_GCROM: 900 STAILQ_FOREACH(fwdev, &fc->devices, link) 901 if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 902 break; 903 if (fwdev == NULL) { 904 if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) { 905 err = FWNODE_INVAL; 906 break; 907 } 908 /* myself */ 909 ptr = malloc(CROMSIZE); 910 len = CROMSIZE; 911 for (i = 0; i < CROMSIZE / 4; i++) 912 ((uint32_t *)ptr)[i] 913 = B_BENDIAN_TO_HOST_INT32(fc->config_rom[i]); 914 } else { 915 /* found */ 916 ptr = (void *)&fwdev->csrrom[0]; 917 if (fwdev->rommax < CSRROMOFF) 918 len = 0; 919 else 920 len = fwdev->rommax - CSRROMOFF + 4; 921 } 922 if (crom_buf->len < len) 923 len = crom_buf->len; 924 else 925 crom_buf->len = len; 926 // err = copyout(ptr, crom_buf->ptr, len);//to be completed 927 err = user_memcpy(crom_buf->ptr, ptr, len); 928 if (fwdev == NULL) 929 /* myself */ 930 free(ptr); 931 break; 932 default: 933 fc->ioctl (fc, cmd, data, length); 934 break; 935 } 936 return err; 937 } 938 939 940 status_t 941 init_hardware() 942 { 943 return B_OK; 944 } 945 946 947 const char ** 948 publish_devices(void) 949 { 950 return (const char **)devices; 951 } 952 953 954 static device_hooks hooks = { 955 &fw_open, 956 &fw_close, 957 &fw_free, 958 &fw_ioctl, 959 &fw_read, 960 &fw_write, 961 NULL, 962 NULL, 963 NULL, 964 NULL 965 }; 966 967 device_hooks * 968 find_device(const char *name) 969 { 970 return &hooks; 971 } 972 973 974 status_t 975 init_driver() 976 { 977 status_t err; 978 struct firewire_softc *sc = NULL; 979 uint32 i; 980 981 #if DEBUG && !defined(__HAIKU__) 982 load_driver_symbols("fw_raw"); 983 #endif 984 985 if ((err = get_module(FIREWIRE_MODULE_NAME, (module_info **)&gFirewire)) != B_OK) { 986 dprintf("fw_raw: couldn't load "FIREWIRE_MODULE_NAME"\n"); 987 return err; 988 } 989 990 devices_count = 0; 991 while (gFirewire->get_handle(devices_count, &sc) == B_OK) { 992 devices_count++; 993 } 994 995 if (devices_count <= 0) { 996 put_module(FIREWIRE_MODULE_NAME); 997 return ENODEV; 998 } 999 1000 devices = malloc(sizeof(char *) * (devices_count + 1)); 1001 if (!devices) { 1002 put_module(FIREWIRE_MODULE_NAME); 1003 return ENOMEM; 1004 } 1005 for (i = 0; i < devices_count; i++) { 1006 devices[i] = strdup(fwname); 1007 snprintf(devices[i], FWNAMEMAX, fwname, i); 1008 } 1009 devices[devices_count] = NULL; 1010 1011 TRACE("fw_raw init_driver returns OK\n"); 1012 return B_OK; 1013 } 1014 1015 1016 void 1017 uninit_driver() 1018 { 1019 int32 i = 0; 1020 for (i = 0; i < devices_count; i++) { 1021 free(devices[i]); 1022 } 1023 free(devices); 1024 devices = NULL; 1025 1026 put_module(FIREWIRE_MODULE_NAME); 1027 } 1028