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 | 276 FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 277 d->it = NULL; 278 } 279 free(d); 280 d = NULL; 281 282 return B_OK; 283 } 284 285 286 static int 287 fw_read_async(struct fw_drv1 *d, off_t position, void *buf, size_t *num_bytes) 288 { 289 int err = 0; 290 struct fw_xfer *xfer; 291 struct fw_bind *fwb; 292 struct fw_pkt *fp; 293 struct tcode_info *tinfo; 294 cpu_status s; 295 296 int len, pbytes = (int)*num_bytes;//pbytes:to be processed bytes 297 *num_bytes = 0; 298 299 FW_GLOCK(d->fc); 300 while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == B_OK){ 301 //err = msleep(&d->rq, FW_GMTX(d->fc), FWPRI, "fwra", 0); 302 FW_GUNLOCK(d->fc); 303 err = acquire_sem_etc(d->rqSem, 1, B_CAN_INTERRUPT | B_TIMEOUT, 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, size_t *num_bytes) 452 { 453 struct fw_xfer *xfer; 454 struct fw_pkt pkt; 455 struct tcode_info *tinfo; 456 int err; 457 458 int len, pbytes = (int)*num_bytes; 459 *num_bytes = 0; 460 461 bzero(&pkt, sizeof(struct fw_pkt)); 462 // if ((err = uiomove((caddr_t)&pkt, sizeof(uint32_t), uio))) 463 len = sizeof(uint32_t); 464 len = MIN(len, pbytes); 465 err = user_memcpy(&pkt, buf, len); 466 pbytes -= len; 467 *num_bytes += len; 468 buf = (void *)((caddr_t)buf + len); 469 if (err < B_OK) 470 return (err); 471 472 tinfo = &d->fc->tcode[pkt.mode.hdr.tcode]; 473 // if ((err = uiomove((caddr_t)&pkt + sizeof(uint32_t), 474 // tinfo->hdr_len - sizeof(uint32_t), uio))) 475 len = tinfo->hdr_len - sizeof(uint32_t); 476 len = MIN(len, pbytes); 477 err = user_memcpy((void*)((caddr_t)&pkt + sizeof(uint32_t)), 478 buf, len); 479 pbytes -= len; 480 *num_bytes += len; 481 buf = (void *)((caddr_t)buf + len); 482 483 if (err < B_OK) 484 return (err); 485 486 if ((xfer = gFirewire->fw_xfer_alloc_buf(pbytes, 487 B_PAGE_SIZE/*XXX*/)) == NULL) 488 return (ENOMEM); 489 490 bcopy(&pkt, &xfer->send.hdr, sizeof(struct fw_pkt)); 491 // xfer->send.pay_len = uio->uio_resid; 492 xfer->send.pay_len = pbytes; 493 494 /* if (uio->uio_resid > 0) { 495 if ((err = uiomove((caddr_t)&xfer->send.payload[0], 496 uio->uio_resid, uio)));// here the FreeBSD's stack author may be careless? 497 goto out; 498 }*/ 499 if (pbytes > 0) { 500 len = pbytes; 501 err = user_memcpy((void*)&xfer->send.payload[0], 502 buf, len); 503 pbytes -= len; 504 *num_bytes += len; 505 buf = (void *)((caddr_t)buf + len); 506 if (err < B_OK) 507 goto out; 508 } 509 510 xfer->fc = d->fc; 511 xfer->sc = NULL; 512 xfer->hand = gFirewire->fw_xferwake; 513 xfer->send.spd = 2 /* XXX */; 514 515 if ((err = gFirewire->fw_asyreq(xfer->fc, -1, xfer))) 516 goto out; 517 518 if ((err = gFirewire->fw_xferwait(xfer))) 519 goto out; 520 521 if (xfer->resp != 0) { 522 err = xfer->resp; 523 goto out; 524 } 525 526 if (xfer->flag & FWXF_RCVD) { 527 FW_GLOCK(xfer->fc); 528 STAILQ_INSERT_TAIL(&d->rq, xfer, link); 529 FW_GUNLOCK(xfer->fc); 530 return B_OK; 531 } 532 533 out: 534 gFirewire->fw_xfer_free(xfer); 535 return (err); 536 } 537 538 539 static status_t 540 fw_write (void *cookie, off_t position, const void *buf, size_t *num_bytes) 541 { 542 int err = 0; 543 int slept = 0; 544 struct fw_drv1 *d; 545 struct fw_pkt *fp; 546 struct firewire_comm *fc; 547 struct fw_xferq *it; 548 cpu_status s; 549 550 int len, pbytes = (int)*num_bytes; 551 *num_bytes = 0; 552 553 d = (struct fw_drv1 *)cookie; 554 fc = d->fc; 555 it = d->it; 556 557 if (it == NULL) 558 return (fw_write_async(d, position, buf, num_bytes)); 559 560 if (it->buf == NULL) 561 return (EIO); 562 563 FW_GLOCK(fc); 564 isoloop: 565 if (it->stproc == NULL) { 566 it->stproc = STAILQ_FIRST(&it->stfree); 567 if (it->stproc != NULL) { 568 s = splfw(); 569 STAILQ_REMOVE_HEAD(&it->stfree, link); 570 splx(s); 571 it->queued = 0; 572 } else if (slept == 0) { 573 slept = 1; 574 #if 0 /* XXX to avoid lock recursion */ 575 err = fc->itx_enable(fc, it->dmach); 576 if (err) 577 goto out; 578 #endif 579 // err = msleep(it, FW_GMTX(fc), FWPRI, "fw_write", hz); 580 FW_GUNLOCK(fc); 581 acquire_sem_etc(it->Sem, 1, B_CAN_INTERRUPT | B_TIMEOUT, 1000000); 582 FW_GLOCK(fc); 583 584 // if (err) 585 if (err < B_OK) 586 goto out; 587 goto isoloop; 588 } else { 589 err = EIO; 590 goto out; 591 } 592 } 593 FW_GUNLOCK(fc); 594 fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 595 it->stproc->poffset + it->queued); 596 // err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 597 len = sizeof(struct fw_isohdr); 598 len = MIN(len, pbytes); 599 err = user_memcpy(fp, buf, len); 600 pbytes -= len; 601 *num_bytes += len; 602 buf = (void *)((caddr_t)buf + len); 603 604 // err = uiomove((caddr_t)fp->mode.stream.payload, 605 // fp->mode.stream.len, uio); 606 len = fp->mode.stream.len; 607 len = MIN(len, pbytes); 608 err = user_memcpy(fp->mode.stream.payload, buf, len); 609 pbytes -= len; 610 *num_bytes += len; 611 buf = (void *)((caddr_t)buf + len); 612 613 it->queued ++; 614 if (it->queued >= it->bnpacket) { 615 s = splfw(); 616 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 617 splx(s); 618 it->stproc = NULL; 619 err = fc->itx_enable(fc, it->dmach); 620 } 621 // if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 622 if (pbytes >= sizeof(struct fw_isohdr)) { 623 slept = 0; 624 FW_GLOCK(fc); 625 goto isoloop; 626 } 627 return err; 628 629 out: 630 FW_GUNLOCK(fc); 631 return err; 632 } 633 634 635 static void 636 fw_hand(struct fw_xfer *xfer) 637 { 638 struct fw_bind *fwb; 639 struct fw_drv1 *d; 640 641 fwb = (struct fw_bind *)xfer->sc; 642 d = (struct fw_drv1 *)fwb->sc; 643 FW_GLOCK(xfer->fc); 644 STAILQ_INSERT_TAIL(&d->rq, xfer, link); 645 FW_GUNLOCK(xfer->fc); 646 // wakeup(&d->rq); 647 release_sem_etc(d->rqSem, 1, B_DO_NOT_RESCHEDULE); 648 } 649 650 651 /* 652 * ioctl support. 653 */ 654 static status_t 655 fw_ioctl (void *cookie, uint32 cmd, void *data, size_t length) 656 { 657 struct firewire_comm *fc; 658 struct fw_drv1 *d; 659 int i, len, err = 0; 660 struct fw_device *fwdev; 661 struct fw_bind *fwb; 662 struct fw_xferq *ir, *it; 663 struct fw_xfer *xfer; 664 struct fw_pkt *fp; 665 struct fw_devinfo *devinfo; 666 void *ptr; 667 668 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 669 struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 670 struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 671 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 672 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 673 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 674 675 if (!data) 676 return(EINVAL); 677 678 d = (struct fw_drv1 *)cookie; 679 fc = d->fc; 680 ir = d->ir; 681 it = d->it; 682 683 switch (cmd) { 684 case FW_STSTREAM: 685 if (it == NULL) { 686 i = gFirewire->fw_open_isodma(fc, /* tx */1); 687 if (i < 0) { 688 err = EBUSY; 689 break; 690 } 691 it = fc->it[i]; 692 err = fwdev_allocbuf(it, &d->bufreq.tx); 693 if (err) { 694 it->flag &= ~FWXFERQ_OPEN; 695 break; 696 } 697 } 698 it->flag &= ~0xff; 699 it->flag |= (0x3f & ichreq->ch); 700 it->flag |= ((0x3 & ichreq->tag) << 6); 701 d->it = it; 702 break; 703 case FW_GTSTREAM: 704 if (it != NULL) { 705 ichreq->ch = it->flag & 0x3f; 706 ichreq->tag = it->flag >> 2 & 0x3; 707 } else 708 err = EINVAL; 709 break; 710 case FW_SRSTREAM: 711 if (ir == NULL) { 712 i = gFirewire->fw_open_isodma(fc, /* tx */0); 713 if (i < 0) { 714 err = EBUSY; 715 break; 716 } 717 ir = fc->ir[i]; 718 err = fwdev_allocbuf(ir, &d->bufreq.rx); 719 if (err) { 720 ir->flag &= ~FWXFERQ_OPEN; 721 break; 722 } 723 } 724 ir->flag &= ~0xff; 725 ir->flag |= (0x3f & ichreq->ch); 726 ir->flag |= ((0x3 & ichreq->tag) << 6); 727 d->ir = ir; 728 err = fc->irx_enable(fc, ir->dmach); 729 break; 730 case FW_GRSTREAM: 731 if (d->ir != NULL) { 732 ichreq->ch = ir->flag & 0x3f; 733 ichreq->tag = ir->flag >> 2 & 0x3; 734 } else 735 err = EINVAL; 736 break; 737 case FW_SSTBUF: 738 bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq)); 739 break; 740 case FW_GSTBUF: 741 bzero(&ibufreq->rx, sizeof(ibufreq->rx)); 742 if (ir != NULL) { 743 ibufreq->rx.nchunk = ir->bnchunk; 744 ibufreq->rx.npacket = ir->bnpacket; 745 ibufreq->rx.psize = ir->psize; 746 } 747 bzero(&ibufreq->tx, sizeof(ibufreq->tx)); 748 if (it != NULL) { 749 ibufreq->tx.nchunk = it->bnchunk; 750 ibufreq->tx.npacket = it->bnpacket; 751 ibufreq->tx.psize = it->psize; 752 } 753 break; 754 case FW_ASYREQ: 755 { 756 struct tcode_info *tinfo; 757 int pay_len = 0; 758 759 fp = &asyreq->pkt; 760 tinfo = &fc->tcode[fp->mode.hdr.tcode]; 761 762 if ((tinfo->flag & FWTI_BLOCK_ASY) != 0) 763 pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len); 764 765 xfer = gFirewire->fw_xfer_alloc_buf(pay_len, B_PAGE_SIZE/*XXX*/); 766 if (xfer == NULL) 767 return (ENOMEM); 768 769 switch (asyreq->req.type) { 770 case FWASREQNODE: 771 break; 772 case FWASREQEUI: 773 fwdev = gFirewire->fw_noderesolve_eui64(fc, 774 &asyreq->req.dst.eui); 775 if (fwdev == NULL) { 776 dprintf("FWASREQEUI cannot find node\n"); 777 err = EINVAL; 778 goto out; 779 } 780 fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst; 781 break; 782 case FWASRESTL: 783 /* XXX what's this? */ 784 break; 785 case FWASREQSTREAM: 786 /* nothing to do */ 787 break; 788 } 789 790 bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len); 791 if (pay_len > 0) 792 bcopy((char *)fp + tinfo->hdr_len, 793 (void *)xfer->send.payload, pay_len); 794 xfer->send.spd = asyreq->req.sped; 795 xfer->hand = gFirewire->fw_xferwake; 796 797 if ((err = gFirewire->fw_asyreq(fc, -1, xfer)) != 0) 798 goto out; 799 if ((err = gFirewire->fw_xferwait(xfer)) != 0) 800 goto out; 801 if (xfer->resp != 0) { 802 err = EIO; 803 goto out; 804 } 805 if ((tinfo->flag & FWTI_TLABEL) == 0) 806 goto out; 807 808 /* copy response */ 809 tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode]; 810 if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB || 811 xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) { 812 pay_len = xfer->recv.pay_len; 813 if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) { 814 asyreq->req.len = xfer->recv.pay_len + 815 tinfo->hdr_len; 816 } else { 817 err = EINVAL; 818 pay_len = 0; 819 } 820 } else { 821 pay_len = 0; 822 } 823 bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len); 824 bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, pay_len); 825 out: 826 gFirewire->fw_xfer_free_buf(xfer); 827 break; 828 } 829 case FW_IBUSRST: 830 fc->ibr(fc); 831 break; 832 case FW_CBINDADDR: 833 fwb = gFirewire->fw_bindlookup(fc, 834 bindreq->start.hi, bindreq->start.lo); 835 if(fwb == NULL){ 836 err = EINVAL; 837 break; 838 } 839 gFirewire->fw_bindremove(fc, fwb); 840 STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist); 841 gFirewire->fw_xferlist_remove(&fwb->xferlist); 842 free(fwb); 843 break; 844 case FW_SBINDADDR: 845 if(bindreq->len <= 0 ){ 846 err = EINVAL; 847 break; 848 } 849 if(bindreq->start.hi > 0xffff ){ 850 err = EINVAL; 851 break; 852 } 853 fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind)); 854 if(fwb == NULL){ 855 err = ENOMEM; 856 break; 857 } 858 fwb->start = ((u_int64_t)bindreq->start.hi << 32) | 859 bindreq->start.lo; 860 fwb->end = fwb->start + bindreq->len; 861 fwb->sc = (void *)d; 862 STAILQ_INIT(&fwb->xferlist); 863 err = gFirewire->fw_bindadd(fc, fwb); 864 if (err == 0) { 865 gFirewire->fw_xferlist_add(&fwb->xferlist, 866 /* XXX */ 867 B_PAGE_SIZE, B_PAGE_SIZE, 5, 868 fc, (void *)fwb, fw_hand); 869 STAILQ_INSERT_TAIL(&d->binds, fwb, chlist); 870 } 871 break; 872 case FW_GDEVLST: 873 i = len = 1; 874 /* myself */ 875 devinfo = &fwdevlst->dev[0]; 876 devinfo->dst = fc->nodeid; 877 devinfo->status = 0; /* XXX */ 878 devinfo->eui.hi = fc->eui.hi; 879 devinfo->eui.lo = fc->eui.lo; 880 STAILQ_FOREACH(fwdev, &fc->devices, link) { 881 if(len < FW_MAX_DEVLST){ 882 devinfo = &fwdevlst->dev[len++]; 883 devinfo->dst = fwdev->dst; 884 devinfo->status = 885 (fwdev->status == FWDEVINVAL)?0:1; 886 devinfo->eui.hi = fwdev->eui.hi; 887 devinfo->eui.lo = fwdev->eui.lo; 888 } 889 i++; 890 } 891 fwdevlst->n = i; 892 fwdevlst->info_len = len; 893 break; 894 case FW_GTPMAP: 895 bcopy(fc->topology_map, data, 896 (fc->topology_map->crc_len + 1) * 4); 897 break; 898 case FW_GCROM: 899 STAILQ_FOREACH(fwdev, &fc->devices, link) 900 if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 901 break; 902 if (fwdev == NULL) { 903 if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) { 904 err = FWNODE_INVAL; 905 break; 906 } 907 /* myself */ 908 ptr = malloc(CROMSIZE); 909 len = CROMSIZE; 910 for (i = 0; i < CROMSIZE/4; i++) 911 ((uint32_t *)ptr)[i] 912 = B_BENDIAN_TO_HOST_INT32(fc->config_rom[i]); 913 } else { 914 /* found */ 915 ptr = (void *)&fwdev->csrrom[0]; 916 if (fwdev->rommax < CSRROMOFF) 917 len = 0; 918 else 919 len = fwdev->rommax - CSRROMOFF + 4; 920 } 921 if (crom_buf->len < len) 922 len = crom_buf->len; 923 else 924 crom_buf->len = len; 925 // err = copyout(ptr, crom_buf->ptr, len);//to be completed 926 err = user_memcpy(crom_buf->ptr, ptr, len); 927 if (fwdev == NULL) 928 /* myself */ 929 free(ptr); 930 break; 931 default: 932 fc->ioctl (fc, cmd, data, length); 933 break; 934 } 935 return err; 936 } 937 938 939 status_t 940 init_hardware() 941 { 942 return B_OK; 943 } 944 945 946 const char ** 947 publish_devices(void) 948 { 949 return (const char **)devices; 950 } 951 952 953 static device_hooks hooks = { 954 &fw_open, 955 &fw_close, 956 &fw_free, 957 &fw_ioctl, 958 &fw_read, 959 &fw_write, 960 NULL, 961 NULL, 962 NULL, 963 NULL 964 }; 965 966 device_hooks * 967 find_device(const char *name) 968 { 969 return &hooks; 970 } 971 972 973 status_t 974 init_driver() 975 { 976 status_t err; 977 struct firewire_softc *sc = NULL; 978 uint32 i; 979 980 #if DEBUG && !defined(__HAIKU__) 981 load_driver_symbols("fw_raw"); 982 #endif 983 984 if ((err = get_module(FIREWIRE_MODULE_NAME, (module_info **)&gFirewire)) != B_OK) { 985 dprintf("fw_raw: couldn't load "FIREWIRE_MODULE_NAME"\n"); 986 return err; 987 } 988 989 devices_count = 0; 990 while (gFirewire->get_handle(devices_count, &sc)==B_OK) { 991 devices_count++; 992 } 993 994 if (devices_count <= 0) { 995 put_module(FIREWIRE_MODULE_NAME); 996 return ENODEV; 997 } 998 999 devices = malloc(sizeof(char *) * (devices_count+1)); 1000 if (!devices) { 1001 put_module(FIREWIRE_MODULE_NAME); 1002 return ENOMEM; 1003 } 1004 for (i=0; i<devices_count; i++) { 1005 devices[i] = strdup(fwname); 1006 snprintf(devices[i], FWNAMEMAX, fwname, i); 1007 } 1008 devices[devices_count] = NULL; 1009 1010 TRACE("fw_raw init_driver returns OK\n"); 1011 return B_OK; 1012 } 1013 1014 1015 void 1016 uninit_driver() 1017 { 1018 int32 i = 0; 1019 for (i=0; i<devices_count; i++) { 1020 free(devices[i]); 1021 } 1022 free(devices); 1023 devices = NULL; 1024 1025 put_module(FIREWIRE_MODULE_NAME); 1026 } 1027