1 1.33 msaitoh /* $NetBSD: fwdev.c,v 1.33 2021/11/10 16:08:17 msaitoh Exp $ */ 2 1.1 kiyohara /*- 3 1.1 kiyohara * Copyright (c) 2003 Hidetoshi Shimokawa 4 1.1 kiyohara * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 5 1.1 kiyohara * All rights reserved. 6 1.1 kiyohara * 7 1.1 kiyohara * Redistribution and use in source and binary forms, with or without 8 1.1 kiyohara * modification, are permitted provided that the following conditions 9 1.1 kiyohara * are met: 10 1.1 kiyohara * 1. Redistributions of source code must retain the above copyright 11 1.1 kiyohara * notice, this list of conditions and the following disclaimer. 12 1.1 kiyohara * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 kiyohara * notice, this list of conditions and the following disclaimer in the 14 1.1 kiyohara * documentation and/or other materials provided with the distribution. 15 1.1 kiyohara * 3. All advertising materials mentioning features or use of this software 16 1.1 kiyohara * must display the acknowledgement as bellow: 17 1.1 kiyohara * 18 1.1 kiyohara * This product includes software developed by K. Kobayashi and H. Shimokawa 19 1.1 kiyohara * 20 1.1 kiyohara * 4. The name of the author may not be used to endorse or promote products 21 1.1 kiyohara * derived from this software without specific prior written permission. 22 1.1 kiyohara * 23 1.1 kiyohara * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 1.1 kiyohara * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 1.1 kiyohara * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 1.1 kiyohara * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27 1.1 kiyohara * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 1.1 kiyohara * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 1.1 kiyohara * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 1.1 kiyohara * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31 1.1 kiyohara * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 1.1 kiyohara * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 1.1 kiyohara * POSSIBILITY OF SUCH DAMAGE. 34 1.18 kiyohara * 35 1.13 kiyohara * $FreeBSD: src/sys/dev/firewire/fwdev.c,v 1.52 2007/06/06 14:31:36 simokawa Exp $ 36 1.1 kiyohara * 37 1.1 kiyohara */ 38 1.1 kiyohara 39 1.14 lukem #include <sys/cdefs.h> 40 1.33 msaitoh __KERNEL_RCSID(0, "$NetBSD: fwdev.c,v 1.33 2021/11/10 16:08:17 msaitoh Exp $"); 41 1.14 lukem 42 1.1 kiyohara #include <sys/param.h> 43 1.1 kiyohara #include <sys/device.h> 44 1.1 kiyohara #include <sys/errno.h> 45 1.1 kiyohara #include <sys/buf.h> 46 1.18 kiyohara #include <sys/bus.h> 47 1.1 kiyohara #include <sys/conf.h> 48 1.1 kiyohara #include <sys/kernel.h> 49 1.22 christos #include <sys/malloc.h> 50 1.1 kiyohara #include <sys/mbuf.h> 51 1.1 kiyohara #include <sys/poll.h> 52 1.1 kiyohara #include <sys/proc.h> 53 1.18 kiyohara #include <sys/select.h> 54 1.1 kiyohara 55 1.1 kiyohara #include <dev/ieee1394/firewire.h> 56 1.1 kiyohara #include <dev/ieee1394/firewirereg.h> 57 1.1 kiyohara #include <dev/ieee1394/fwdma.h> 58 1.1 kiyohara #include <dev/ieee1394/fwmem.h> 59 1.1 kiyohara #include <dev/ieee1394/iec68113.h> 60 1.18 kiyohara 61 1.26 uebayasi #include "ioconf.h" 62 1.26 uebayasi 63 1.1 kiyohara #define FWNODE_INVAL 0xffff 64 1.1 kiyohara 65 1.1 kiyohara dev_type_open(fw_open); 66 1.1 kiyohara dev_type_close(fw_close); 67 1.1 kiyohara dev_type_read(fw_read); 68 1.1 kiyohara dev_type_write(fw_write); 69 1.1 kiyohara dev_type_ioctl(fw_ioctl); 70 1.1 kiyohara dev_type_poll(fw_poll); 71 1.1 kiyohara dev_type_mmap(fw_mmap); 72 1.1 kiyohara dev_type_strategy(fw_strategy); 73 1.1 kiyohara 74 1.1 kiyohara const struct bdevsw fw_bdevsw = { 75 1.28 dholland .d_open = fw_open, 76 1.28 dholland .d_close = fw_close, 77 1.28 dholland .d_strategy = fw_strategy, 78 1.28 dholland .d_ioctl = fw_ioctl, 79 1.28 dholland .d_dump = nodump, 80 1.28 dholland .d_psize = nosize, 81 1.29 dholland .d_discard = nodiscard, 82 1.28 dholland .d_flag = D_OTHER 83 1.1 kiyohara }; 84 1.1 kiyohara 85 1.1 kiyohara const struct cdevsw fw_cdevsw = { 86 1.28 dholland .d_open = fw_open, 87 1.28 dholland .d_close = fw_close, 88 1.28 dholland .d_read = fw_read, 89 1.28 dholland .d_write = fw_write, 90 1.28 dholland .d_ioctl = fw_ioctl, 91 1.28 dholland .d_stop = nostop, 92 1.28 dholland .d_tty = notty, 93 1.28 dholland .d_poll = fw_poll, 94 1.28 dholland .d_mmap = fw_mmap, 95 1.28 dholland .d_kqfilter = nokqfilter, 96 1.30 dholland .d_discard = nodiscard, 97 1.28 dholland .d_flag = D_OTHER 98 1.1 kiyohara }; 99 1.1 kiyohara 100 1.1 kiyohara struct fw_drv1 { 101 1.1 kiyohara struct firewire_comm *fc; 102 1.1 kiyohara struct fw_xferq *ir; 103 1.1 kiyohara struct fw_xferq *it; 104 1.1 kiyohara struct fw_isobufreq bufreq; 105 1.1 kiyohara STAILQ_HEAD(, fw_bind) binds; 106 1.1 kiyohara STAILQ_HEAD(, fw_xfer) rq; 107 1.31 riastrad kcondvar_t cv; 108 1.1 kiyohara }; 109 1.1 kiyohara 110 1.18 kiyohara static int fwdev_allocbuf(struct firewire_comm *, struct fw_xferq *, 111 1.18 kiyohara struct fw_bufspec *); 112 1.22 christos static int fwdev_freebuf(struct fw_xferq *); 113 1.18 kiyohara static int fw_read_async(struct fw_drv1 *, struct uio *, int); 114 1.18 kiyohara static int fw_write_async(struct fw_drv1 *, struct uio *, int); 115 1.18 kiyohara static void fw_hand(struct fw_xfer *); 116 1.1 kiyohara 117 1.1 kiyohara 118 1.18 kiyohara int 119 1.18 kiyohara fw_open(dev_t dev, int flags, int fmt, struct lwp *td) 120 1.1 kiyohara { 121 1.18 kiyohara struct firewire_softc *sc; 122 1.18 kiyohara struct fw_drv1 *d; 123 1.18 kiyohara int err = 0; 124 1.1 kiyohara 125 1.18 kiyohara sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 126 1.18 kiyohara if (sc == NULL) 127 1.18 kiyohara return ENXIO; 128 1.1 kiyohara 129 1.18 kiyohara if (DEV_FWMEM(dev)) 130 1.18 kiyohara return fwmem_open(dev, flags, fmt, td); 131 1.1 kiyohara 132 1.18 kiyohara mutex_enter(&sc->fc->fc_mtx); 133 1.18 kiyohara if (sc->si_drv1 != NULL) { 134 1.18 kiyohara mutex_exit(&sc->fc->fc_mtx); 135 1.18 kiyohara return EBUSY; 136 1.13 kiyohara } 137 1.13 kiyohara /* set dummy value for allocation */ 138 1.18 kiyohara sc->si_drv1 = (void *)-1; 139 1.18 kiyohara mutex_exit(&sc->fc->fc_mtx); 140 1.13 kiyohara 141 1.22 christos sc->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); 142 1.18 kiyohara if (sc->si_drv1 == NULL) 143 1.18 kiyohara return ENOMEM; 144 1.1 kiyohara 145 1.18 kiyohara d = (struct fw_drv1 *)sc->si_drv1; 146 1.1 kiyohara d->fc = sc->fc; 147 1.1 kiyohara STAILQ_INIT(&d->binds); 148 1.1 kiyohara STAILQ_INIT(&d->rq); 149 1.31 riastrad cv_init(&d->cv, "fwra"); 150 1.1 kiyohara 151 1.1 kiyohara return err; 152 1.1 kiyohara } 153 1.1 kiyohara 154 1.18 kiyohara int 155 1.18 kiyohara fw_close(dev_t dev, int flags, int fmt, struct lwp *td) 156 1.1 kiyohara { 157 1.18 kiyohara struct firewire_softc *sc; 158 1.1 kiyohara struct firewire_comm *fc; 159 1.1 kiyohara struct fw_drv1 *d; 160 1.1 kiyohara struct fw_xfer *xfer; 161 1.1 kiyohara struct fw_bind *fwb; 162 1.18 kiyohara int err = 0; 163 1.18 kiyohara 164 1.18 kiyohara sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 165 1.18 kiyohara if (sc == NULL) 166 1.18 kiyohara return ENXIO; 167 1.1 kiyohara 168 1.18 kiyohara if (DEV_FWMEM(dev)) 169 1.18 kiyohara return fwmem_close(dev, flags, fmt, td); 170 1.1 kiyohara 171 1.18 kiyohara d = (struct fw_drv1 *)sc->si_drv1; 172 1.1 kiyohara fc = d->fc; 173 1.1 kiyohara 174 1.1 kiyohara /* remove binding */ 175 1.1 kiyohara for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL; 176 1.18 kiyohara fwb = STAILQ_FIRST(&d->binds)) { 177 1.1 kiyohara fw_bindremove(fc, fwb); 178 1.1 kiyohara STAILQ_REMOVE_HEAD(&d->binds, chlist); 179 1.1 kiyohara fw_xferlist_remove(&fwb->xferlist); 180 1.1 kiyohara free(fwb, M_FW); 181 1.1 kiyohara } 182 1.1 kiyohara if (d->ir != NULL) { 183 1.1 kiyohara struct fw_xferq *ir = d->ir; 184 1.1 kiyohara 185 1.1 kiyohara if ((ir->flag & FWXFERQ_OPEN) == 0) 186 1.18 kiyohara return EINVAL; 187 1.1 kiyohara if (ir->flag & FWXFERQ_RUNNING) { 188 1.1 kiyohara ir->flag &= ~FWXFERQ_RUNNING; 189 1.1 kiyohara fc->irx_disable(fc, ir->dmach); 190 1.1 kiyohara } 191 1.1 kiyohara /* free extbuf */ 192 1.22 christos fwdev_freebuf(ir); 193 1.1 kiyohara /* drain receiving buffer */ 194 1.18 kiyohara for (xfer = STAILQ_FIRST(&ir->q); xfer != NULL; 195 1.18 kiyohara xfer = STAILQ_FIRST(&ir->q)) { 196 1.18 kiyohara ir->queued--; 197 1.1 kiyohara STAILQ_REMOVE_HEAD(&ir->q, link); 198 1.1 kiyohara 199 1.1 kiyohara xfer->resp = 0; 200 1.1 kiyohara fw_xfer_done(xfer); 201 1.1 kiyohara } 202 1.18 kiyohara ir->flag &= 203 1.18 kiyohara ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 204 1.1 kiyohara d->ir = NULL; 205 1.1 kiyohara 206 1.1 kiyohara } 207 1.1 kiyohara if (d->it != NULL) { 208 1.1 kiyohara struct fw_xferq *it = d->it; 209 1.1 kiyohara 210 1.1 kiyohara if ((it->flag & FWXFERQ_OPEN) == 0) 211 1.18 kiyohara return EINVAL; 212 1.1 kiyohara if (it->flag & FWXFERQ_RUNNING) { 213 1.1 kiyohara it->flag &= ~FWXFERQ_RUNNING; 214 1.1 kiyohara fc->itx_disable(fc, it->dmach); 215 1.1 kiyohara } 216 1.1 kiyohara /* free extbuf */ 217 1.22 christos fwdev_freebuf(it); 218 1.18 kiyohara it->flag &= 219 1.18 kiyohara ~(FWXFERQ_OPEN | FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 220 1.1 kiyohara d->it = NULL; 221 1.1 kiyohara } 222 1.31 riastrad cv_destroy(&d->cv); 223 1.22 christos free(sc->si_drv1, M_FW); 224 1.18 kiyohara sc->si_drv1 = NULL; 225 1.1 kiyohara 226 1.1 kiyohara return err; 227 1.1 kiyohara } 228 1.1 kiyohara 229 1.18 kiyohara int 230 1.18 kiyohara fw_read(dev_t dev, struct uio *uio, int ioflag) 231 1.1 kiyohara { 232 1.18 kiyohara struct firewire_softc *sc; 233 1.18 kiyohara struct firewire_comm *fc; 234 1.1 kiyohara struct fw_drv1 *d; 235 1.1 kiyohara struct fw_xferq *ir; 236 1.1 kiyohara struct fw_pkt *fp; 237 1.18 kiyohara int err = 0, slept = 0; 238 1.1 kiyohara 239 1.18 kiyohara sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 240 1.18 kiyohara if (sc == NULL) 241 1.18 kiyohara return ENXIO; 242 1.18 kiyohara 243 1.18 kiyohara if (DEV_FWMEM(dev)) 244 1.18 kiyohara return physio(fw_strategy, NULL, dev, ioflag, minphys, uio); 245 1.1 kiyohara 246 1.18 kiyohara d = (struct fw_drv1 *)sc->si_drv1; 247 1.1 kiyohara fc = d->fc; 248 1.1 kiyohara ir = d->ir; 249 1.1 kiyohara 250 1.1 kiyohara if (ir == NULL) 251 1.18 kiyohara return fw_read_async(d, uio, ioflag); 252 1.1 kiyohara 253 1.1 kiyohara if (ir->buf == NULL) 254 1.18 kiyohara return EIO; 255 1.1 kiyohara 256 1.18 kiyohara mutex_enter(&fc->fc_mtx); 257 1.1 kiyohara readloop: 258 1.1 kiyohara if (ir->stproc == NULL) { 259 1.1 kiyohara /* iso bulkxfer */ 260 1.1 kiyohara ir->stproc = STAILQ_FIRST(&ir->stvalid); 261 1.1 kiyohara if (ir->stproc != NULL) { 262 1.1 kiyohara STAILQ_REMOVE_HEAD(&ir->stvalid, link); 263 1.1 kiyohara ir->queued = 0; 264 1.1 kiyohara } 265 1.1 kiyohara } 266 1.1 kiyohara if (ir->stproc == NULL) { 267 1.33 msaitoh /* no data available */ 268 1.1 kiyohara if (slept == 0) { 269 1.1 kiyohara slept = 1; 270 1.1 kiyohara ir->flag |= FWXFERQ_WAKEUP; 271 1.31 riastrad err = cv_timedwait_sig(&ir->cv, &fc->fc_mtx, hz); 272 1.1 kiyohara ir->flag &= ~FWXFERQ_WAKEUP; 273 1.1 kiyohara if (err == 0) 274 1.1 kiyohara goto readloop; 275 1.1 kiyohara } else if (slept == 1) 276 1.1 kiyohara err = EIO; 277 1.18 kiyohara mutex_exit(&fc->fc_mtx); 278 1.1 kiyohara return err; 279 1.18 kiyohara } else if (ir->stproc != NULL) { 280 1.1 kiyohara /* iso bulkxfer */ 281 1.18 kiyohara mutex_exit(&fc->fc_mtx); 282 1.18 kiyohara fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 283 1.18 kiyohara ir->stproc->poffset + ir->queued); 284 1.18 kiyohara if (fc->irx_post != NULL) 285 1.1 kiyohara fc->irx_post(fc, fp->mode.ld); 286 1.18 kiyohara if (fp->mode.stream.len == 0) 287 1.18 kiyohara return EIO; 288 1.9 christos err = uiomove((void *)fp, 289 1.18 kiyohara fp->mode.stream.len + sizeof(uint32_t), uio); 290 1.18 kiyohara ir->queued++; 291 1.18 kiyohara if (ir->queued >= ir->bnpacket) { 292 1.1 kiyohara STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 293 1.1 kiyohara fc->irx_enable(fc, ir->dmach); 294 1.1 kiyohara ir->stproc = NULL; 295 1.1 kiyohara } 296 1.1 kiyohara if (uio->uio_resid >= ir->psize) { 297 1.1 kiyohara slept = -1; 298 1.18 kiyohara mutex_enter(&fc->fc_mtx); 299 1.1 kiyohara goto readloop; 300 1.1 kiyohara } 301 1.18 kiyohara } else 302 1.18 kiyohara mutex_exit(&fc->fc_mtx); 303 1.1 kiyohara return err; 304 1.1 kiyohara } 305 1.1 kiyohara 306 1.18 kiyohara int 307 1.18 kiyohara fw_write(dev_t dev, struct uio *uio, int ioflag) 308 1.1 kiyohara { 309 1.18 kiyohara struct firewire_softc *sc; 310 1.18 kiyohara struct firewire_comm *fc; 311 1.1 kiyohara struct fw_drv1 *d; 312 1.1 kiyohara struct fw_pkt *fp; 313 1.1 kiyohara struct fw_xferq *it; 314 1.18 kiyohara int slept = 0, err = 0; 315 1.18 kiyohara 316 1.18 kiyohara sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 317 1.18 kiyohara if (sc == NULL) 318 1.18 kiyohara return ENXIO; 319 1.18 kiyohara 320 1.18 kiyohara if (DEV_FWMEM(dev)) 321 1.18 kiyohara return physio(fw_strategy, NULL, dev, ioflag, minphys, uio); 322 1.1 kiyohara 323 1.18 kiyohara d = (struct fw_drv1 *)sc->si_drv1; 324 1.1 kiyohara fc = d->fc; 325 1.1 kiyohara it = d->it; 326 1.1 kiyohara 327 1.1 kiyohara if (it == NULL) 328 1.18 kiyohara return fw_write_async(d, uio, ioflag); 329 1.1 kiyohara 330 1.1 kiyohara if (it->buf == NULL) 331 1.18 kiyohara return EIO; 332 1.13 kiyohara 333 1.18 kiyohara mutex_enter(&fc->fc_mtx); 334 1.1 kiyohara isoloop: 335 1.1 kiyohara if (it->stproc == NULL) { 336 1.1 kiyohara it->stproc = STAILQ_FIRST(&it->stfree); 337 1.1 kiyohara if (it->stproc != NULL) { 338 1.1 kiyohara STAILQ_REMOVE_HEAD(&it->stfree, link); 339 1.1 kiyohara it->queued = 0; 340 1.1 kiyohara } else if (slept == 0) { 341 1.1 kiyohara slept = 1; 342 1.13 kiyohara #if 0 /* XXX to avoid lock recursion */ 343 1.1 kiyohara err = fc->itx_enable(fc, it->dmach); 344 1.1 kiyohara if (err) 345 1.13 kiyohara goto out; 346 1.13 kiyohara #endif 347 1.31 riastrad err = cv_timedwait_sig(&it->cv, &fc->fc_mtx, hz); 348 1.1 kiyohara if (err) 349 1.13 kiyohara goto out; 350 1.1 kiyohara goto isoloop; 351 1.1 kiyohara } else { 352 1.1 kiyohara err = EIO; 353 1.13 kiyohara goto out; 354 1.1 kiyohara } 355 1.1 kiyohara } 356 1.18 kiyohara mutex_exit(&fc->fc_mtx); 357 1.1 kiyohara fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 358 1.18 kiyohara it->stproc->poffset + it->queued); 359 1.9 christos err = uiomove((void *)fp, sizeof(struct fw_isohdr), uio); 360 1.18 kiyohara if (err != 0) 361 1.18 kiyohara return err; 362 1.18 kiyohara err = 363 1.18 kiyohara uiomove((void *)fp->mode.stream.payload, fp->mode.stream.len, uio); 364 1.18 kiyohara it->queued++; 365 1.1 kiyohara if (it->queued >= it->bnpacket) { 366 1.1 kiyohara STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 367 1.1 kiyohara it->stproc = NULL; 368 1.1 kiyohara err = fc->itx_enable(fc, it->dmach); 369 1.1 kiyohara } 370 1.1 kiyohara if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 371 1.1 kiyohara slept = 0; 372 1.18 kiyohara mutex_enter(&fc->fc_mtx); 373 1.1 kiyohara goto isoloop; 374 1.1 kiyohara } 375 1.1 kiyohara return err; 376 1.13 kiyohara 377 1.13 kiyohara out: 378 1.18 kiyohara mutex_exit(&fc->fc_mtx); 379 1.13 kiyohara return err; 380 1.1 kiyohara } 381 1.1 kiyohara 382 1.18 kiyohara int 383 1.18 kiyohara fw_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *td) 384 1.1 kiyohara { 385 1.18 kiyohara struct firewire_softc *sc; 386 1.1 kiyohara struct firewire_comm *fc; 387 1.1 kiyohara struct fw_drv1 *d; 388 1.1 kiyohara struct fw_device *fwdev; 389 1.1 kiyohara struct fw_bind *fwb; 390 1.1 kiyohara struct fw_xferq *ir, *it; 391 1.1 kiyohara struct fw_xfer *xfer; 392 1.1 kiyohara struct fw_pkt *fp; 393 1.1 kiyohara struct fw_devinfo *devinfo; 394 1.1 kiyohara struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 395 1.1 kiyohara struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 396 1.1 kiyohara struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 397 1.1 kiyohara struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 398 1.1 kiyohara struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 399 1.1 kiyohara struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 400 1.18 kiyohara int i, len, err = 0; 401 1.18 kiyohara void *ptr; 402 1.1 kiyohara 403 1.18 kiyohara sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 404 1.18 kiyohara if (sc == NULL) 405 1.18 kiyohara return ENXIO; 406 1.18 kiyohara 407 1.18 kiyohara if (DEV_FWMEM(dev)) 408 1.18 kiyohara return fwmem_ioctl(dev, cmd, data, flag, td); 409 1.1 kiyohara 410 1.1 kiyohara if (!data) 411 1.18 kiyohara return EINVAL; 412 1.1 kiyohara 413 1.18 kiyohara d = (struct fw_drv1 *)sc->si_drv1; 414 1.1 kiyohara fc = d->fc; 415 1.1 kiyohara ir = d->ir; 416 1.1 kiyohara it = d->it; 417 1.1 kiyohara 418 1.1 kiyohara switch (cmd) { 419 1.1 kiyohara case FW_STSTREAM: 420 1.1 kiyohara if (it == NULL) { 421 1.13 kiyohara i = fw_open_isodma(fc, /* tx */1); 422 1.13 kiyohara if (i < 0) { 423 1.1 kiyohara err = EBUSY; 424 1.1 kiyohara break; 425 1.1 kiyohara } 426 1.13 kiyohara it = fc->it[i]; 427 1.1 kiyohara err = fwdev_allocbuf(fc, it, &d->bufreq.tx); 428 1.13 kiyohara if (err) { 429 1.13 kiyohara it->flag &= ~FWXFERQ_OPEN; 430 1.1 kiyohara break; 431 1.13 kiyohara } 432 1.1 kiyohara } 433 1.1 kiyohara it->flag &= ~0xff; 434 1.1 kiyohara it->flag |= (0x3f & ichreq->ch); 435 1.1 kiyohara it->flag |= ((0x3 & ichreq->tag) << 6); 436 1.1 kiyohara d->it = it; 437 1.1 kiyohara break; 438 1.18 kiyohara 439 1.1 kiyohara case FW_GTSTREAM: 440 1.1 kiyohara if (it != NULL) { 441 1.1 kiyohara ichreq->ch = it->flag & 0x3f; 442 1.1 kiyohara ichreq->tag = it->flag >> 2 & 0x3; 443 1.1 kiyohara } else 444 1.1 kiyohara err = EINVAL; 445 1.1 kiyohara break; 446 1.18 kiyohara 447 1.1 kiyohara case FW_SRSTREAM: 448 1.1 kiyohara if (ir == NULL) { 449 1.13 kiyohara i = fw_open_isodma(fc, /* tx */0); 450 1.13 kiyohara if (i < 0) { 451 1.1 kiyohara err = EBUSY; 452 1.1 kiyohara break; 453 1.1 kiyohara } 454 1.13 kiyohara ir = fc->ir[i]; 455 1.1 kiyohara err = fwdev_allocbuf(fc, ir, &d->bufreq.rx); 456 1.13 kiyohara if (err) { 457 1.13 kiyohara ir->flag &= ~FWXFERQ_OPEN; 458 1.1 kiyohara break; 459 1.13 kiyohara } 460 1.1 kiyohara } 461 1.1 kiyohara ir->flag &= ~0xff; 462 1.1 kiyohara ir->flag |= (0x3f & ichreq->ch); 463 1.1 kiyohara ir->flag |= ((0x3 & ichreq->tag) << 6); 464 1.1 kiyohara d->ir = ir; 465 1.1 kiyohara err = fc->irx_enable(fc, ir->dmach); 466 1.1 kiyohara break; 467 1.18 kiyohara 468 1.1 kiyohara case FW_GRSTREAM: 469 1.1 kiyohara if (d->ir != NULL) { 470 1.1 kiyohara ichreq->ch = ir->flag & 0x3f; 471 1.1 kiyohara ichreq->tag = ir->flag >> 2 & 0x3; 472 1.1 kiyohara } else 473 1.1 kiyohara err = EINVAL; 474 1.1 kiyohara break; 475 1.18 kiyohara 476 1.1 kiyohara case FW_SSTBUF: 477 1.17 tsutsui memcpy(&d->bufreq, ibufreq, sizeof(d->bufreq)); 478 1.1 kiyohara break; 479 1.18 kiyohara 480 1.1 kiyohara case FW_GSTBUF: 481 1.15 cegger memset(&ibufreq->rx, 0, sizeof(ibufreq->rx)); 482 1.1 kiyohara if (ir != NULL) { 483 1.1 kiyohara ibufreq->rx.nchunk = ir->bnchunk; 484 1.1 kiyohara ibufreq->rx.npacket = ir->bnpacket; 485 1.1 kiyohara ibufreq->rx.psize = ir->psize; 486 1.1 kiyohara } 487 1.15 cegger memset(&ibufreq->tx, 0, sizeof(ibufreq->tx)); 488 1.1 kiyohara if (it != NULL) { 489 1.1 kiyohara ibufreq->tx.nchunk = it->bnchunk; 490 1.1 kiyohara ibufreq->tx.npacket = it->bnpacket; 491 1.1 kiyohara ibufreq->tx.psize = it->psize; 492 1.1 kiyohara } 493 1.1 kiyohara break; 494 1.18 kiyohara 495 1.1 kiyohara case FW_ASYREQ: 496 1.1 kiyohara { 497 1.2 drochner const struct tcode_info *tinfo; 498 1.1 kiyohara int pay_len = 0; 499 1.1 kiyohara 500 1.1 kiyohara fp = &asyreq->pkt; 501 1.1 kiyohara tinfo = &fc->tcode[fp->mode.hdr.tcode]; 502 1.1 kiyohara 503 1.1 kiyohara if ((tinfo->flag & FWTI_BLOCK_ASY) != 0) 504 1.1 kiyohara pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len); 505 1.1 kiyohara 506 1.27 dsl xfer = fw_xfer_alloc_buf(M_FW, pay_len, PAGE_SIZE/*XXX*/); 507 1.1 kiyohara if (xfer == NULL) 508 1.18 kiyohara return ENOMEM; 509 1.1 kiyohara 510 1.1 kiyohara switch (asyreq->req.type) { 511 1.1 kiyohara case FWASREQNODE: 512 1.1 kiyohara break; 513 1.18 kiyohara 514 1.1 kiyohara case FWASREQEUI: 515 1.18 kiyohara fwdev = fw_noderesolve_eui64(fc, &asyreq->req.dst.eui); 516 1.1 kiyohara if (fwdev == NULL) { 517 1.18 kiyohara aprint_error_dev(fc->bdev, 518 1.18 kiyohara "cannot find node\n"); 519 1.1 kiyohara err = EINVAL; 520 1.1 kiyohara goto out; 521 1.1 kiyohara } 522 1.1 kiyohara fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst; 523 1.1 kiyohara break; 524 1.18 kiyohara 525 1.1 kiyohara case FWASRESTL: 526 1.1 kiyohara /* XXX what's this? */ 527 1.1 kiyohara break; 528 1.18 kiyohara 529 1.1 kiyohara case FWASREQSTREAM: 530 1.1 kiyohara /* nothing to do */ 531 1.1 kiyohara break; 532 1.1 kiyohara } 533 1.1 kiyohara 534 1.19 kiyohara memcpy(&xfer->send.hdr, fp, tinfo->hdr_len); 535 1.1 kiyohara if (pay_len > 0) 536 1.19 kiyohara memcpy(xfer->send.payload, (char *)fp + tinfo->hdr_len, 537 1.19 kiyohara pay_len); 538 1.1 kiyohara xfer->send.spd = asyreq->req.sped; 539 1.13 kiyohara xfer->hand = fw_xferwake; 540 1.1 kiyohara 541 1.1 kiyohara if ((err = fw_asyreq(fc, -1, xfer)) != 0) 542 1.1 kiyohara goto out; 543 1.13 kiyohara if ((err = fw_xferwait(xfer)) != 0) 544 1.1 kiyohara goto out; 545 1.1 kiyohara if (xfer->resp != 0) { 546 1.1 kiyohara err = EIO; 547 1.1 kiyohara goto out; 548 1.1 kiyohara } 549 1.1 kiyohara if ((tinfo->flag & FWTI_TLABEL) == 0) 550 1.1 kiyohara goto out; 551 1.1 kiyohara 552 1.1 kiyohara /* copy response */ 553 1.1 kiyohara tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode]; 554 1.1 kiyohara if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB || 555 1.1 kiyohara xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) { 556 1.1 kiyohara pay_len = xfer->recv.pay_len; 557 1.18 kiyohara if (asyreq->req.len >= 558 1.18 kiyohara xfer->recv.pay_len + tinfo->hdr_len) 559 1.18 kiyohara asyreq->req.len = 560 1.18 kiyohara xfer->recv.pay_len + tinfo->hdr_len; 561 1.18 kiyohara else { 562 1.1 kiyohara err = EINVAL; 563 1.1 kiyohara pay_len = 0; 564 1.1 kiyohara } 565 1.18 kiyohara } else 566 1.1 kiyohara pay_len = 0; 567 1.17 tsutsui memcpy(fp, &xfer->recv.hdr, tinfo->hdr_len); 568 1.18 kiyohara memcpy((char *)fp + tinfo->hdr_len, xfer->recv.payload, 569 1.18 kiyohara pay_len); 570 1.1 kiyohara out: 571 1.1 kiyohara fw_xfer_free_buf(xfer); 572 1.1 kiyohara break; 573 1.1 kiyohara } 574 1.18 kiyohara 575 1.1 kiyohara case FW_IBUSRST: 576 1.1 kiyohara fc->ibr(fc); 577 1.1 kiyohara break; 578 1.18 kiyohara 579 1.1 kiyohara case FW_CBINDADDR: 580 1.18 kiyohara fwb = fw_bindlookup(fc, bindreq->start.hi, bindreq->start.lo); 581 1.18 kiyohara if (fwb == NULL) { 582 1.1 kiyohara err = EINVAL; 583 1.1 kiyohara break; 584 1.1 kiyohara } 585 1.1 kiyohara fw_bindremove(fc, fwb); 586 1.1 kiyohara STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist); 587 1.1 kiyohara fw_xferlist_remove(&fwb->xferlist); 588 1.1 kiyohara free(fwb, M_FW); 589 1.1 kiyohara break; 590 1.18 kiyohara 591 1.1 kiyohara case FW_SBINDADDR: 592 1.18 kiyohara if (bindreq->len <= 0 ) { 593 1.1 kiyohara err = EINVAL; 594 1.1 kiyohara break; 595 1.1 kiyohara } 596 1.18 kiyohara if (bindreq->start.hi > 0xffff ) { 597 1.1 kiyohara err = EINVAL; 598 1.1 kiyohara break; 599 1.1 kiyohara } 600 1.22 christos fwb = (struct fw_bind *)malloc(sizeof(struct fw_bind), 601 1.22 christos M_FW, M_WAITOK); 602 1.18 kiyohara if (fwb == NULL) { 603 1.1 kiyohara err = ENOMEM; 604 1.1 kiyohara break; 605 1.1 kiyohara } 606 1.1 kiyohara fwb->start = ((u_int64_t)bindreq->start.hi << 32) | 607 1.1 kiyohara bindreq->start.lo; 608 1.1 kiyohara fwb->end = fwb->start + bindreq->len; 609 1.1 kiyohara fwb->sc = (void *)d; 610 1.1 kiyohara STAILQ_INIT(&fwb->xferlist); 611 1.1 kiyohara err = fw_bindadd(fc, fwb); 612 1.1 kiyohara if (err == 0) { 613 1.27 dsl fw_xferlist_add(&fwb->xferlist, M_FW, 614 1.1 kiyohara /* XXX */ 615 1.18 kiyohara PAGE_SIZE, PAGE_SIZE, 5, fc, (void *)fwb, fw_hand); 616 1.1 kiyohara STAILQ_INSERT_TAIL(&d->binds, fwb, chlist); 617 1.32 maxv } else { 618 1.32 maxv free(fwb, M_FW); 619 1.1 kiyohara } 620 1.1 kiyohara break; 621 1.18 kiyohara 622 1.1 kiyohara case FW_GDEVLST: 623 1.1 kiyohara i = len = 1; 624 1.1 kiyohara /* myself */ 625 1.18 kiyohara devinfo = fwdevlst->dev; 626 1.1 kiyohara devinfo->dst = fc->nodeid; 627 1.1 kiyohara devinfo->status = 0; /* XXX */ 628 1.1 kiyohara devinfo->eui.hi = fc->eui.hi; 629 1.1 kiyohara devinfo->eui.lo = fc->eui.lo; 630 1.1 kiyohara STAILQ_FOREACH(fwdev, &fc->devices, link) { 631 1.18 kiyohara if (len < FW_MAX_DEVLST) { 632 1.1 kiyohara devinfo = &fwdevlst->dev[len++]; 633 1.1 kiyohara devinfo->dst = fwdev->dst; 634 1.18 kiyohara devinfo->status = 635 1.18 kiyohara (fwdev->status == FWDEVINVAL) ? 0 : 1; 636 1.1 kiyohara devinfo->eui.hi = fwdev->eui.hi; 637 1.1 kiyohara devinfo->eui.lo = fwdev->eui.lo; 638 1.1 kiyohara } 639 1.1 kiyohara i++; 640 1.1 kiyohara } 641 1.1 kiyohara fwdevlst->n = i; 642 1.1 kiyohara fwdevlst->info_len = len; 643 1.1 kiyohara break; 644 1.18 kiyohara 645 1.1 kiyohara case FW_GTPMAP: 646 1.17 tsutsui memcpy(data, fc->topology_map, 647 1.18 kiyohara (fc->topology_map->crc_len + 1) * 4); 648 1.1 kiyohara break; 649 1.18 kiyohara 650 1.1 kiyohara case FW_GCROM: 651 1.1 kiyohara STAILQ_FOREACH(fwdev, &fc->devices, link) 652 1.1 kiyohara if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 653 1.1 kiyohara break; 654 1.1 kiyohara if (fwdev == NULL) { 655 1.1 kiyohara if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) { 656 1.1 kiyohara err = FWNODE_INVAL; 657 1.1 kiyohara break; 658 1.1 kiyohara } 659 1.1 kiyohara /* myself */ 660 1.22 christos ptr = malloc(CROMSIZE, M_FW, M_WAITOK); 661 1.1 kiyohara len = CROMSIZE; 662 1.1 kiyohara for (i = 0; i < CROMSIZE/4; i++) 663 1.18 kiyohara ((uint32_t *)ptr)[i] = ntohl(fc->config_rom[i]); 664 1.1 kiyohara } else { 665 1.1 kiyohara /* found */ 666 1.18 kiyohara ptr = (void *)fwdev->csrrom; 667 1.1 kiyohara if (fwdev->rommax < CSRROMOFF) 668 1.1 kiyohara len = 0; 669 1.1 kiyohara else 670 1.1 kiyohara len = fwdev->rommax - CSRROMOFF + 4; 671 1.1 kiyohara } 672 1.8 jdolecek if (crom_buf->len < len) 673 1.1 kiyohara len = crom_buf->len; 674 1.1 kiyohara else 675 1.1 kiyohara crom_buf->len = len; 676 1.1 kiyohara err = copyout(ptr, crom_buf->ptr, len); 677 1.1 kiyohara if (fwdev == NULL) 678 1.1 kiyohara /* myself */ 679 1.22 christos free(ptr, M_FW); 680 1.1 kiyohara break; 681 1.18 kiyohara 682 1.1 kiyohara default: 683 1.18 kiyohara fc->ioctl(dev, cmd, data, flag, td); 684 1.1 kiyohara break; 685 1.1 kiyohara } 686 1.1 kiyohara return err; 687 1.1 kiyohara } 688 1.1 kiyohara 689 1.18 kiyohara int 690 1.18 kiyohara fw_poll(dev_t dev, int events, struct lwp *td) 691 1.1 kiyohara { 692 1.18 kiyohara struct firewire_softc *sc; 693 1.1 kiyohara struct fw_xferq *ir; 694 1.18 kiyohara int revents, tmp; 695 1.1 kiyohara 696 1.18 kiyohara sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 697 1.18 kiyohara if (sc == NULL) 698 1.18 kiyohara return ENXIO; 699 1.1 kiyohara 700 1.18 kiyohara ir = ((struct fw_drv1 *)sc->si_drv1)->ir; 701 1.1 kiyohara revents = 0; 702 1.1 kiyohara tmp = POLLIN | POLLRDNORM; 703 1.1 kiyohara if (events & tmp) { 704 1.1 kiyohara if (STAILQ_FIRST(&ir->q) != NULL) 705 1.1 kiyohara revents |= tmp; 706 1.1 kiyohara else 707 1.1 kiyohara selrecord(td, &ir->rsel); 708 1.1 kiyohara } 709 1.1 kiyohara tmp = POLLOUT | POLLWRNORM; 710 1.18 kiyohara if (events & tmp) 711 1.18 kiyohara /* XXX should be fixed */ 712 1.1 kiyohara revents |= tmp; 713 1.1 kiyohara 714 1.1 kiyohara return revents; 715 1.1 kiyohara } 716 1.1 kiyohara 717 1.18 kiyohara paddr_t 718 1.18 kiyohara fw_mmap(dev_t dev, off_t offset, int nproto) 719 1.18 kiyohara { 720 1.18 kiyohara struct firewire_softc *sc; 721 1.1 kiyohara 722 1.18 kiyohara sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 723 1.18 kiyohara if (sc == NULL) 724 1.18 kiyohara return ENXIO; 725 1.1 kiyohara 726 1.1 kiyohara return EINVAL; 727 1.1 kiyohara } 728 1.1 kiyohara 729 1.1 kiyohara void 730 1.1 kiyohara fw_strategy(struct bio *bp) 731 1.1 kiyohara { 732 1.18 kiyohara struct firewire_softc *sc; 733 1.18 kiyohara dev_t dev = bp->bio_dev; 734 1.18 kiyohara 735 1.18 kiyohara sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev)); 736 1.18 kiyohara if (sc == NULL) 737 1.18 kiyohara return; 738 1.1 kiyohara 739 1.18 kiyohara if (DEV_FWMEM(dev)) { 740 1.18 kiyohara fwmem_strategy(bp); 741 1.18 kiyohara return; 742 1.18 kiyohara } 743 1.1 kiyohara 744 1.1 kiyohara bp->bio_error = EOPNOTSUPP; 745 1.1 kiyohara bp->bio_resid = bp->bio_bcount; 746 1.1 kiyohara biodone(bp); 747 1.1 kiyohara } 748 1.1 kiyohara 749 1.18 kiyohara 750 1.18 kiyohara static int 751 1.18 kiyohara fwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q, 752 1.18 kiyohara struct fw_bufspec *b) 753 1.1 kiyohara { 754 1.18 kiyohara int i; 755 1.18 kiyohara 756 1.18 kiyohara if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF)) 757 1.18 kiyohara return EBUSY; 758 1.18 kiyohara 759 1.18 kiyohara q->bulkxfer = 760 1.22 christos (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * b->nchunk, 761 1.22 christos M_FW, M_WAITOK); 762 1.18 kiyohara if (q->bulkxfer == NULL) 763 1.18 kiyohara return ENOMEM; 764 1.18 kiyohara 765 1.18 kiyohara b->psize = roundup2(b->psize, sizeof(uint32_t)); 766 1.18 kiyohara q->buf = fwdma_malloc_multiseg(fc, sizeof(uint32_t), b->psize, 767 1.18 kiyohara b->nchunk * b->npacket, BUS_DMA_WAITOK); 768 1.18 kiyohara 769 1.18 kiyohara if (q->buf == NULL) { 770 1.22 christos free(q->bulkxfer, M_FW); 771 1.18 kiyohara q->bulkxfer = NULL; 772 1.18 kiyohara return ENOMEM; 773 1.18 kiyohara } 774 1.18 kiyohara q->bnchunk = b->nchunk; 775 1.18 kiyohara q->bnpacket = b->npacket; 776 1.18 kiyohara q->psize = (b->psize + 3) & ~3; 777 1.18 kiyohara q->queued = 0; 778 1.18 kiyohara 779 1.18 kiyohara STAILQ_INIT(&q->stvalid); 780 1.18 kiyohara STAILQ_INIT(&q->stfree); 781 1.18 kiyohara STAILQ_INIT(&q->stdma); 782 1.18 kiyohara q->stproc = NULL; 783 1.18 kiyohara 784 1.18 kiyohara for (i = 0 ; i < q->bnchunk; i++) { 785 1.18 kiyohara q->bulkxfer[i].poffset = i * q->bnpacket; 786 1.18 kiyohara q->bulkxfer[i].mbuf = NULL; 787 1.18 kiyohara STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link); 788 1.18 kiyohara } 789 1.18 kiyohara 790 1.18 kiyohara q->flag &= ~FWXFERQ_MODEMASK; 791 1.18 kiyohara q->flag |= FWXFERQ_STREAM; 792 1.18 kiyohara q->flag |= FWXFERQ_EXTBUF; 793 1.1 kiyohara 794 1.18 kiyohara return 0; 795 1.18 kiyohara } 796 1.1 kiyohara 797 1.18 kiyohara static int 798 1.22 christos fwdev_freebuf(struct fw_xferq *q) 799 1.18 kiyohara { 800 1.1 kiyohara 801 1.18 kiyohara if (q->flag & FWXFERQ_EXTBUF) { 802 1.18 kiyohara if (q->buf != NULL) 803 1.18 kiyohara fwdma_free_multiseg(q->buf); 804 1.18 kiyohara q->buf = NULL; 805 1.22 christos free(q->bulkxfer, M_FW); 806 1.18 kiyohara q->bulkxfer = NULL; 807 1.18 kiyohara q->flag &= ~FWXFERQ_EXTBUF; 808 1.18 kiyohara q->psize = 0; 809 1.18 kiyohara q->maxq = FWMAXQUEUE; 810 1.18 kiyohara } 811 1.18 kiyohara return 0; 812 1.1 kiyohara } 813 1.1 kiyohara 814 1.18 kiyohara static int 815 1.18 kiyohara fw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 816 1.1 kiyohara { 817 1.18 kiyohara struct fw_xfer *xfer; 818 1.18 kiyohara struct fw_bind *fwb; 819 1.18 kiyohara struct fw_pkt *fp; 820 1.18 kiyohara const struct tcode_info *tinfo; 821 1.1 kiyohara int err = 0; 822 1.1 kiyohara 823 1.18 kiyohara mutex_enter(&d->fc->fc_mtx); 824 1.18 kiyohara 825 1.24 cegger for (;;) { 826 1.24 cegger xfer = STAILQ_FIRST(&d->rq); 827 1.24 cegger if (xfer == NULL && err == 0) { 828 1.31 riastrad err = cv_wait_sig(&d->cv, &d->fc->fc_mtx); 829 1.31 riastrad if (err) { 830 1.31 riastrad mutex_exit(&d->fc->fc_mtx); 831 1.24 cegger return err; 832 1.31 riastrad } 833 1.24 cegger continue; 834 1.24 cegger } 835 1.24 cegger break; 836 1.18 kiyohara } 837 1.1 kiyohara 838 1.18 kiyohara STAILQ_REMOVE_HEAD(&d->rq, link); 839 1.18 kiyohara mutex_exit(&d->fc->fc_mtx); 840 1.18 kiyohara fp = &xfer->recv.hdr; 841 1.18 kiyohara #if 0 /* for GASP ?? */ 842 1.18 kiyohara if (fc->irx_post != NULL) 843 1.18 kiyohara fc->irx_post(fc, fp->mode.ld); 844 1.1 kiyohara #endif 845 1.18 kiyohara tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode]; 846 1.18 kiyohara err = uiomove((void *)fp, tinfo->hdr_len, uio); 847 1.18 kiyohara if (err) 848 1.18 kiyohara goto out; 849 1.18 kiyohara err = uiomove((void *)xfer->recv.payload, xfer->recv.pay_len, uio); 850 1.18 kiyohara 851 1.18 kiyohara out: 852 1.18 kiyohara /* recycle this xfer */ 853 1.18 kiyohara fwb = (struct fw_bind *)xfer->sc; 854 1.18 kiyohara fw_xfer_unload(xfer); 855 1.18 kiyohara xfer->recv.pay_len = PAGE_SIZE; 856 1.18 kiyohara mutex_enter(&d->fc->fc_mtx); 857 1.18 kiyohara STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 858 1.18 kiyohara mutex_exit(&d->fc->fc_mtx); 859 1.18 kiyohara return err; 860 1.1 kiyohara } 861 1.1 kiyohara 862 1.18 kiyohara static int 863 1.18 kiyohara fw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag) 864 1.1 kiyohara { 865 1.18 kiyohara struct fw_xfer *xfer; 866 1.18 kiyohara struct fw_pkt pkt; 867 1.18 kiyohara const struct tcode_info *tinfo; 868 1.18 kiyohara int err; 869 1.18 kiyohara 870 1.18 kiyohara memset(&pkt, 0, sizeof(struct fw_pkt)); 871 1.18 kiyohara if ((err = uiomove((void *)&pkt, sizeof(uint32_t), uio))) 872 1.18 kiyohara return err; 873 1.18 kiyohara tinfo = &d->fc->tcode[pkt.mode.hdr.tcode]; 874 1.18 kiyohara if ((err = uiomove((char *)&pkt + sizeof(uint32_t), 875 1.18 kiyohara tinfo->hdr_len - sizeof(uint32_t), uio))) 876 1.18 kiyohara return err; 877 1.18 kiyohara 878 1.27 dsl if ((xfer = fw_xfer_alloc_buf(M_FW, uio->uio_resid, 879 1.18 kiyohara PAGE_SIZE/*XXX*/)) == NULL) 880 1.18 kiyohara return ENOMEM; 881 1.18 kiyohara 882 1.18 kiyohara memcpy(&xfer->send.hdr, &pkt, sizeof(struct fw_pkt)); 883 1.18 kiyohara xfer->send.pay_len = uio->uio_resid; 884 1.18 kiyohara if (uio->uio_resid > 0) { 885 1.18 kiyohara if ((err = 886 1.18 kiyohara uiomove((void *)xfer->send.payload, uio->uio_resid, uio))) 887 1.18 kiyohara goto out; 888 1.18 kiyohara } 889 1.18 kiyohara 890 1.18 kiyohara xfer->fc = d->fc; 891 1.18 kiyohara xfer->sc = NULL; 892 1.18 kiyohara xfer->hand = fw_xferwake; 893 1.18 kiyohara xfer->send.spd = 2 /* XXX */; 894 1.1 kiyohara 895 1.18 kiyohara if ((err = fw_asyreq(xfer->fc, -1, xfer))) 896 1.18 kiyohara goto out; 897 1.1 kiyohara 898 1.18 kiyohara if ((err = fw_xferwait(xfer))) 899 1.18 kiyohara goto out; 900 1.1 kiyohara 901 1.18 kiyohara if (xfer->resp != 0) { 902 1.18 kiyohara err = xfer->resp; 903 1.18 kiyohara goto out; 904 1.18 kiyohara } 905 1.1 kiyohara 906 1.18 kiyohara if (xfer->flag == FWXF_RCVD) { 907 1.18 kiyohara mutex_enter(&xfer->fc->fc_mtx); 908 1.18 kiyohara STAILQ_INSERT_TAIL(&d->rq, xfer, link); 909 1.18 kiyohara mutex_exit(&xfer->fc->fc_mtx); 910 1.18 kiyohara return 0; 911 1.1 kiyohara } 912 1.1 kiyohara 913 1.18 kiyohara out: 914 1.18 kiyohara fw_xfer_free(xfer); 915 1.18 kiyohara return err; 916 1.18 kiyohara } 917 1.18 kiyohara 918 1.18 kiyohara static void 919 1.18 kiyohara fw_hand(struct fw_xfer *xfer) 920 1.18 kiyohara { 921 1.18 kiyohara struct fw_bind *fwb; 922 1.18 kiyohara struct fw_drv1 *d; 923 1.18 kiyohara 924 1.18 kiyohara fwb = (struct fw_bind *)xfer->sc; 925 1.18 kiyohara d = (struct fw_drv1 *)fwb->sc; 926 1.18 kiyohara mutex_enter(&xfer->fc->fc_mtx); 927 1.18 kiyohara STAILQ_INSERT_TAIL(&d->rq, xfer, link); 928 1.31 riastrad cv_broadcast(&d->cv); 929 1.18 kiyohara mutex_exit(&xfer->fc->fc_mtx); 930 1.1 kiyohara } 931