2 * Copyright (c) 2003 Hidetoshi Shimokawa
3 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the acknowledgement as bellow:
17 * This product includes software developed by K. Kobayashi and H. Shimokawa
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
34 * $FreeBSD: src/sys/dev/firewire/fwdev.c,v 1.36 2004/01/22 14:41:17 simokawa Exp $
35 * $DragonFly: src/sys/bus/firewire/fwdev.c,v 1.20 2008/01/06 16:55:49 swildner Exp $
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/types.h>
43 #if defined(__DragonFly__) || __FreeBSD_version < 500000
49 #include <sys/kernel.h>
50 #include <sys/malloc.h>
55 #include <sys/ctype.h>
57 #include <sys/thread2.h>
61 #include "firewirereg.h"
66 #include <dev/firewire/firewire.h>
67 #include <dev/firewire/firewirereg.h>
68 #include <dev/firewire/fwdma.h>
69 #include <dev/firewire/fwmem.h>
70 #include <dev/firewire/iec68113.h>
73 #define CDEV_MAJOR 127
74 #define FWNODE_INVAL 0xffff
76 static d_open_t fw_open
;
77 static d_close_t fw_close
;
78 static d_ioctl_t fw_ioctl
;
79 static d_poll_t fw_poll
;
80 static d_read_t fw_read
; /* for Isochronous packet */
81 static d_write_t fw_write
;
82 static d_mmap_t fw_mmap
;
83 static d_strategy_t fw_strategy
;
85 struct dev_ops firewire_ops
=
87 { "fw", CDEV_MAJOR
, D_MEM
},
95 .d_strategy
= fw_strategy
,
101 struct fw_isobufreq bufreq
;
105 fwdev_allocbuf(struct firewire_comm
*fc
, struct fw_xferq
*q
,
106 struct fw_bufspec
*b
)
110 if (q
->flag
& (FWXFERQ_RUNNING
| FWXFERQ_EXTBUF
))
113 q
->bulkxfer
= (struct fw_bulkxfer
*) kmalloc(
114 sizeof(struct fw_bulkxfer
) * b
->nchunk
,
117 b
->psize
= roundup2(b
->psize
, sizeof(u_int32_t
));
118 q
->buf
= fwdma_malloc_multiseg(fc
, sizeof(u_int32_t
),
119 b
->psize
, b
->nchunk
* b
->npacket
, BUS_DMA_WAITOK
);
121 if (q
->buf
== NULL
) {
122 kfree(q
->bulkxfer
, M_FW
);
126 q
->bnchunk
= b
->nchunk
;
127 q
->bnpacket
= b
->npacket
;
128 q
->psize
= (b
->psize
+ 3) & ~3;
131 STAILQ_INIT(&q
->stvalid
);
132 STAILQ_INIT(&q
->stfree
);
133 STAILQ_INIT(&q
->stdma
);
136 for(i
= 0 ; i
< q
->bnchunk
; i
++){
137 q
->bulkxfer
[i
].poffset
= i
* q
->bnpacket
;
138 q
->bulkxfer
[i
].mbuf
= NULL
;
139 STAILQ_INSERT_TAIL(&q
->stfree
, &q
->bulkxfer
[i
], link
);
142 q
->flag
&= ~FWXFERQ_MODEMASK
;
143 q
->flag
|= FWXFERQ_STREAM
;
144 q
->flag
|= FWXFERQ_EXTBUF
;
150 fwdev_freebuf(struct fw_xferq
*q
)
152 if (q
->flag
& FWXFERQ_EXTBUF
) {
154 fwdma_free_multiseg(q
->buf
);
156 kfree(q
->bulkxfer
, M_FW
);
158 q
->flag
&= ~FWXFERQ_EXTBUF
;
160 q
->maxq
= FWMAXQUEUE
;
167 fw_open (struct dev_open_args
*ap
)
169 cdev_t dev
= ap
->a_head
.a_dev
;
173 return fwmem_open(ap
);
175 if (dev
->si_drv1
!= NULL
)
178 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
179 if ((dev
->si_flags
& SI_NAMED
) == 0) {
180 int unit
= DEV2UNIT(dev
);
181 int sub
= DEV2SUB(dev
);
183 make_dev(&firewire_ops
, minor(dev
),
184 UID_ROOT
, GID_OPERATOR
, 0660,
185 "fw%d.%d", unit
, sub
);
189 dev
->si_drv1
= kmalloc(sizeof(struct fw_drv1
), M_FW
, M_WAITOK
| M_ZERO
);
195 fw_close (struct dev_close_args
*ap
)
197 cdev_t dev
= ap
->a_head
.a_dev
;
198 struct firewire_softc
*sc
;
199 struct firewire_comm
*fc
;
201 int unit
= DEV2UNIT(dev
);
202 struct fw_xfer
*xfer
;
207 return fwmem_close(ap
);
209 sc
= devclass_get_softc(firewire_devclass
, unit
);
211 d
= (struct fw_drv1
*)dev
->si_drv1
;
214 struct fw_xferq
*ir
= d
->ir
;
216 if ((ir
->flag
& FWXFERQ_OPEN
) == 0)
218 if (ir
->flag
& FWXFERQ_RUNNING
) {
219 ir
->flag
&= ~FWXFERQ_RUNNING
;
220 fc
->irx_disable(fc
, ir
->dmach
);
224 /* drain receiving buffer */
225 for (xfer
= STAILQ_FIRST(&ir
->q
);
226 xfer
!= NULL
; xfer
= STAILQ_FIRST(&ir
->q
)) {
228 STAILQ_REMOVE_HEAD(&ir
->q
, link
);
234 for (fwb
= STAILQ_FIRST(&ir
->binds
); fwb
!= NULL
;
235 fwb
= STAILQ_FIRST(&ir
->binds
)) {
236 STAILQ_REMOVE(&fc
->binds
, fwb
, fw_bind
, fclist
);
237 STAILQ_REMOVE_HEAD(&ir
->binds
, chlist
);
240 ir
->flag
&= ~(FWXFERQ_OPEN
|
241 FWXFERQ_MODEMASK
| FWXFERQ_CHTAGMASK
);
246 struct fw_xferq
*it
= d
->it
;
248 if ((it
->flag
& FWXFERQ_OPEN
) == 0)
250 if (it
->flag
& FWXFERQ_RUNNING
) {
251 it
->flag
&= ~FWXFERQ_RUNNING
;
252 fc
->itx_disable(fc
, it
->dmach
);
256 it
->flag
&= ~(FWXFERQ_OPEN
|
257 FWXFERQ_MODEMASK
| FWXFERQ_CHTAGMASK
);
260 kfree(dev
->si_drv1
, M_FW
);
270 fw_read (struct dev_read_args
*ap
)
272 cdev_t dev
= ap
->a_head
.a_dev
;
273 struct uio
*uio
= ap
->a_uio
;
274 struct firewire_softc
*sc
;
276 struct fw_xfer
*xfer
;
277 int err
= 0, slept
= 0;
278 int unit
= DEV2UNIT(dev
);
284 sc
= devclass_get_softc(firewire_devclass
, unit
);
286 ir
= ((struct fw_drv1
*)dev
->si_drv1
)->ir
;
287 if (ir
== NULL
|| ir
->buf
== NULL
)
291 xfer
= STAILQ_FIRST(&ir
->q
);
292 if (ir
->stproc
== NULL
) {
294 ir
->stproc
= STAILQ_FIRST(&ir
->stvalid
);
295 if (ir
->stproc
!= NULL
) {
297 STAILQ_REMOVE_HEAD(&ir
->stvalid
, link
);
302 if (xfer
== NULL
&& ir
->stproc
== NULL
) {
303 /* no data avaliable */
306 ir
->flag
|= FWXFERQ_WAKEUP
;
307 err
= tsleep(ir
, FWPRI
, "fw_read", hz
);
308 ir
->flag
&= ~FWXFERQ_WAKEUP
;
311 } else if (slept
== 1)
314 } else if(xfer
!= NULL
) {
315 #if 0 /* XXX broken */
316 /* per packet mode or FWACT_CH bind?*/
319 STAILQ_REMOVE_HEAD(&ir
->q
, link
);
321 fp
= &xfer
->recv
.hdr
;
322 if (sc
->fc
->irx_post
!= NULL
)
323 sc
->fc
->irx_post(sc
->fc
, fp
->mode
.ld
);
324 err
= uiomove((void *)fp
, 1 /* XXX header size */, uio
);
325 /* XXX copy payload too */
326 /* XXX we should recycle this xfer */
329 } else if(ir
->stproc
!= NULL
) {
331 fp
= (struct fw_pkt
*)fwdma_v_addr(ir
->buf
,
332 ir
->stproc
->poffset
+ ir
->queued
);
333 if(sc
->fc
->irx_post
!= NULL
)
334 sc
->fc
->irx_post(sc
->fc
, fp
->mode
.ld
);
335 if(fp
->mode
.stream
.len
== 0){
339 err
= uiomove((caddr_t
)fp
,
340 fp
->mode
.stream
.len
+ sizeof(u_int32_t
), uio
);
342 if(ir
->queued
>= ir
->bnpacket
){
344 STAILQ_INSERT_TAIL(&ir
->stfree
, ir
->stproc
, link
);
346 sc
->fc
->irx_enable(sc
->fc
, ir
->dmach
);
349 if (uio
->uio_resid
>= ir
->psize
) {
358 fw_write (struct dev_write_args
*ap
)
360 cdev_t dev
= ap
->a_head
.a_dev
;
361 struct uio
*uio
= ap
->a_uio
;
363 struct firewire_softc
*sc
;
364 int unit
= DEV2UNIT(dev
);
367 struct firewire_comm
*fc
;
371 return physwrite(ap
);
373 sc
= devclass_get_softc(firewire_devclass
, unit
);
375 it
= ((struct fw_drv1
*)dev
->si_drv1
)->it
;
376 if (it
== NULL
|| it
->buf
== NULL
)
379 if (it
->stproc
== NULL
) {
380 it
->stproc
= STAILQ_FIRST(&it
->stfree
);
381 if (it
->stproc
!= NULL
) {
383 STAILQ_REMOVE_HEAD(&it
->stfree
, link
);
386 } else if (slept
== 0) {
388 err
= sc
->fc
->itx_enable(sc
->fc
, it
->dmach
);
391 err
= tsleep(it
, FWPRI
, "fw_write", hz
);
400 fp
= (struct fw_pkt
*)fwdma_v_addr(it
->buf
,
401 it
->stproc
->poffset
+ it
->queued
);
402 err
= uiomove((caddr_t
)fp
, sizeof(struct fw_isohdr
), uio
);
403 err
= uiomove((caddr_t
)fp
->mode
.stream
.payload
,
404 fp
->mode
.stream
.len
, uio
);
406 if (it
->queued
>= it
->bnpacket
) {
408 STAILQ_INSERT_TAIL(&it
->stvalid
, it
->stproc
, link
);
411 err
= sc
->fc
->itx_enable(sc
->fc
, it
->dmach
);
413 if (uio
->uio_resid
>= sizeof(struct fw_isohdr
)) {
423 fw_ioctl (struct dev_ioctl_args
*ap
)
425 cdev_t dev
= ap
->a_head
.a_dev
;
426 struct firewire_softc
*sc
;
427 struct firewire_comm
*fc
;
429 int unit
= DEV2UNIT(dev
);
431 struct fw_device
*fwdev
;
433 struct fw_xferq
*ir
, *it
;
434 struct fw_xfer
*xfer
;
436 struct fw_devinfo
*devinfo
;
439 struct fw_devlstreq
*fwdevlst
= (struct fw_devlstreq
*)ap
->a_data
;
440 struct fw_asyreq
*asyreq
= (struct fw_asyreq
*)ap
->a_data
;
441 struct fw_isochreq
*ichreq
= (struct fw_isochreq
*)ap
->a_data
;
442 struct fw_isobufreq
*ibufreq
= (struct fw_isobufreq
*)ap
->a_data
;
443 struct fw_asybindreq
*bindreq
= (struct fw_asybindreq
*)ap
->a_data
;
444 struct fw_crom_buf
*crom_buf
= (struct fw_crom_buf
*)ap
->a_data
;
447 return fwmem_ioctl(ap
);
452 sc
= devclass_get_softc(firewire_devclass
, unit
);
454 d
= (struct fw_drv1
*)dev
->si_drv1
;
461 for (i
= 0; i
< fc
->nisodma
; i
++) {
463 if ((it
->flag
& FWXFERQ_OPEN
) == 0)
466 if (i
>= fc
->nisodma
) {
470 err
= fwdev_allocbuf(fc
, it
, &d
->bufreq
.tx
);
473 it
->flag
|= FWXFERQ_OPEN
;
476 it
->flag
|= (0x3f & ichreq
->ch
);
477 it
->flag
|= ((0x3 & ichreq
->tag
) << 6);
482 ichreq
->ch
= it
->flag
& 0x3f;
483 ichreq
->tag
= it
->flag
>> 2 & 0x3;
489 for (i
= 0; i
< fc
->nisodma
; i
++) {
491 if ((ir
->flag
& FWXFERQ_OPEN
) == 0)
494 if (i
>= fc
->nisodma
) {
498 err
= fwdev_allocbuf(fc
, ir
, &d
->bufreq
.rx
);
501 ir
->flag
|= FWXFERQ_OPEN
;
504 ir
->flag
|= (0x3f & ichreq
->ch
);
505 ir
->flag
|= ((0x3 & ichreq
->tag
) << 6);
507 err
= fc
->irx_enable(fc
, ir
->dmach
);
511 ichreq
->ch
= ir
->flag
& 0x3f;
512 ichreq
->tag
= ir
->flag
>> 2 & 0x3;
517 bcopy(ibufreq
, &d
->bufreq
, sizeof(d
->bufreq
));
520 bzero(&ibufreq
->rx
, sizeof(ibufreq
->rx
));
522 ibufreq
->rx
.nchunk
= ir
->bnchunk
;
523 ibufreq
->rx
.npacket
= ir
->bnpacket
;
524 ibufreq
->rx
.psize
= ir
->psize
;
526 bzero(&ibufreq
->tx
, sizeof(ibufreq
->tx
));
528 ibufreq
->tx
.nchunk
= it
->bnchunk
;
529 ibufreq
->tx
.npacket
= it
->bnpacket
;
530 ibufreq
->tx
.psize
= it
->psize
;
535 struct tcode_info
*tinfo
;
539 tinfo
= &sc
->fc
->tcode
[fp
->mode
.hdr
.tcode
];
541 if ((tinfo
->flag
& FWTI_BLOCK_ASY
) != 0)
542 pay_len
= MAX(0, asyreq
->req
.len
- tinfo
->hdr_len
);
544 xfer
= fw_xfer_alloc_buf(M_FWXFER
, pay_len
, PAGE_SIZE
/*XXX*/);
548 switch (asyreq
->req
.type
) {
552 fwdev
= fw_noderesolve_eui64(sc
->fc
,
553 &asyreq
->req
.dst
.eui
);
555 device_printf(sc
->fc
->bdev
,
556 "cannot find node\n");
560 fp
->mode
.hdr
.dst
= FWLOCALBUS
| fwdev
->dst
;
563 /* XXX what's this? */
570 bcopy(fp
, (void *)&xfer
->send
.hdr
, tinfo
->hdr_len
);
572 bcopy((char *)fp
+ tinfo
->hdr_len
,
573 (void *)&xfer
->send
.payload
, pay_len
);
574 xfer
->send
.spd
= asyreq
->req
.sped
;
575 xfer
->act
.hand
= fw_asy_callback
;
577 if ((err
= fw_asyreq(sc
->fc
, -1, xfer
)) != 0)
579 if ((err
= tsleep(xfer
, FWPRI
, "asyreq", hz
)) != 0)
581 if (xfer
->resp
!= 0) {
585 if ((tinfo
->flag
& FWTI_TLABEL
) == 0)
589 tinfo
= &sc
->fc
->tcode
[xfer
->recv
.hdr
.mode
.hdr
.tcode
];
590 if (asyreq
->req
.len
>= xfer
->recv
.pay_len
+ tinfo
->hdr_len
)
591 asyreq
->req
.len
= xfer
->recv
.pay_len
;
594 bcopy(&xfer
->recv
.hdr
, fp
, tinfo
->hdr_len
);
595 bcopy(xfer
->recv
.payload
, (char *)fp
+ tinfo
->hdr_len
,
596 MAX(0, asyreq
->req
.len
- tinfo
->hdr_len
));
598 fw_xfer_free_buf(xfer
);
605 fwb
= fw_bindlookup(sc
->fc
,
606 bindreq
->start
.hi
, bindreq
->start
.lo
);
611 STAILQ_REMOVE(&sc
->fc
->binds
, fwb
, fw_bind
, fclist
);
612 STAILQ_REMOVE(&ir
->binds
, fwb
, fw_bind
, chlist
);
616 if(bindreq
->len
<= 0 ){
620 if(bindreq
->start
.hi
> 0xffff ){
624 fwb
= kmalloc(sizeof (struct fw_bind
), M_FW
, M_WAITOK
);
625 fwb
->start
= ((u_int64_t
)bindreq
->start
.hi
<< 32) |
627 fwb
->end
= fwb
->start
+ bindreq
->len
;
629 fwb
->sub
= ir
->dmach
;
630 fwb
->act_type
= FWACT_CH
;
633 xfer
= fw_xfer_alloc(M_FWXFER
);
641 /* XXX broken. need multiple xfer */
642 STAILQ_INIT(&fwb
->xferlist
);
643 STAILQ_INSERT_TAIL(&fwb
->xferlist
, xfer
, link
);
645 err
= fw_bindadd(sc
->fc
, fwb
);
650 devinfo
= &fwdevlst
->dev
[0];
651 devinfo
->dst
= sc
->fc
->nodeid
;
652 devinfo
->status
= 0; /* XXX */
653 devinfo
->eui
.hi
= sc
->fc
->eui
.hi
;
654 devinfo
->eui
.lo
= sc
->fc
->eui
.lo
;
655 STAILQ_FOREACH(fwdev
, &sc
->fc
->devices
, link
) {
656 if(len
< FW_MAX_DEVLST
){
657 devinfo
= &fwdevlst
->dev
[len
++];
658 devinfo
->dst
= fwdev
->dst
;
660 (fwdev
->status
== FWDEVINVAL
)?0:1;
661 devinfo
->eui
.hi
= fwdev
->eui
.hi
;
662 devinfo
->eui
.lo
= fwdev
->eui
.lo
;
667 fwdevlst
->info_len
= len
;
670 bcopy(sc
->fc
->topology_map
, ap
->a_data
,
671 (sc
->fc
->topology_map
->crc_len
+ 1) * 4);
674 STAILQ_FOREACH(fwdev
, &sc
->fc
->devices
, link
)
675 if (FW_EUI64_EQUAL(fwdev
->eui
, crom_buf
->eui
))
678 if (!FW_EUI64_EQUAL(sc
->fc
->eui
, crom_buf
->eui
)) {
683 ptr
= kmalloc(CROMSIZE
, M_FW
, M_WAITOK
);
685 for (i
= 0; i
< CROMSIZE
/4; i
++)
686 ((u_int32_t
*)ptr
)[i
]
687 = ntohl(sc
->fc
->config_rom
[i
]);
690 ptr
= (void *)&fwdev
->csrrom
[0];
691 if (fwdev
->rommax
< CSRROMOFF
)
694 len
= fwdev
->rommax
- CSRROMOFF
+ 4;
696 if (crom_buf
->len
< len
&& crom_buf
->len
>= 0)
700 err
= copyout(ptr
, crom_buf
->ptr
, len
);
712 fw_poll(struct dev_poll_args
*ap
)
714 cdev_t dev
= ap
->a_head
.a_dev
;
715 struct firewire_softc
*sc
;
719 int unit
= DEV2UNIT(dev
);
722 return fwmem_poll(ap
);
724 sc
= devclass_get_softc(firewire_devclass
, unit
);
725 ir
= ((struct fw_drv1
*)dev
->si_drv1
)->ir
;
727 tmp
= POLLIN
| POLLRDNORM
;
728 if (ap
->a_events
& tmp
) {
729 if (STAILQ_FIRST(&ir
->q
) != NULL
)
732 selrecord(curthread
, &ir
->rsel
);
734 tmp
= POLLOUT
| POLLWRNORM
;
735 if (ap
->a_events
& tmp
) {
736 /* XXX should be fixed */
739 ap
->a_events
= revents
;
744 fw_mmap (struct dev_mmap_args
*ap
)
746 cdev_t dev
= ap
->a_head
.a_dev
;
747 struct firewire_softc
*sc
;
748 int unit
= DEV2UNIT(dev
);
751 return fwmem_mmap(ap
);
752 sc
= devclass_get_softc(firewire_devclass
, unit
);
758 fw_strategy(struct dev_strategy_args
*ap
)
760 cdev_t dev
= ap
->a_head
.a_dev
;
761 struct bio
*bio
= ap
->a_bio
;
762 struct buf
*bp
= bio
->bio_buf
;
764 if (DEV_FWMEM(dev
)) {
768 bp
->b_error
= EOPNOTSUPP
;
769 bp
->b_flags
|= B_ERROR
;
770 bp
->b_resid
= bp
->b_bcount
;
776 fwdev_makedev(struct firewire_softc
*sc
)
780 unit
= device_get_unit(sc
->fc
->bdev
);
781 /*HELPME dev_ops_add(&firewire_ops, FW_UNITMASK, FW_UNIT(unit));*/
786 fwdev_destroydev(struct firewire_softc
*sc
)
790 unit
= device_get_unit(sc
->fc
->bdev
);
791 kprintf("devfs: Please check that only the right firewire devices were removed!!!!\n");
792 dev_ops_remove_minor(&firewire_ops
, /*FW_UNITMASK, */FW_UNIT(unit
));
796 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
799 fwdev_clone(void *arg
, char *name
, int namelen
, cdev_t
*dev
)
801 struct firewire_softc
*sc
;
802 char *devnames
[NDEVTYPE
] = {"fw", "fwmem"};
804 int devflag
[NDEVTYPE
] = {0, FWMEM_FLAG
};
805 int i
, unit
= 0, sub
= 0;
810 for (i
= 0; i
< NDEVTYPE
; i
++)
811 if (dev_stdclone(name
, &subp
, devnames
[i
], &unit
) == 2)
817 if (subp
== NULL
|| *subp
++ != '.')
821 while (isdigit(*subp
)) {
823 sub
+= *subp
++ - '0';
828 sc
= devclass_get_softc(firewire_devclass
, unit
);
831 *dev
= make_dev(&firewire_ops
, MAKEMINOR(devflag
[i
], unit
, sub
),
832 UID_ROOT
, GID_OPERATOR
, 0660,
833 "%s%d.%d", devnames
[i
], unit
, sub
);
834 (*dev
)->si_flags
|= SI_CHEAPCLONE
;
835 dev_depends(sc
->dev
, *dev
);