Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F162569004
D58201.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
D58201.diff
View Options
diff --git a/share/man/man4/firewire.4 b/share/man/man4/firewire.4
--- a/share/man/man4/firewire.4
+++ b/share/man/man4/firewire.4
@@ -29,7 +29,7 @@
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd January 23, 2025
+.Dd July 12, 2026
.Dt FIREWIRE 4
.Os
.Sh NAME
@@ -49,11 +49,6 @@
.Bd -literal -offset indent
firewire_load="YES"
.Ed
-.Sh DEPRECATION NOTICE
-The
-.Nm
-driver is slated to be removed prior to
-.Fx 16.0 .
.Sh DESCRIPTION
.Fx
provides machine-independent bus support and raw drivers for
@@ -72,6 +67,27 @@
bus attaches to the controller.
Additional drivers can be attached to the bus.
.Pp
+The
+.Nm
+bus parses each device's CSR configuration ROM to discover unit
+directories.
+A newbus child is created for each unit directory, carrying the
+.Va unit_spec_id
+and
+.Va unit_sw_version
+fields as ivars.
+Device-specific drivers such as
+.Xr fwcam 4 ,
+.Xr fwisound 4 ,
+and
+.Xr fwdv 4
+match against these fields in their probe routines.
+Protocol drivers such as
+.Xr sbp 4
+and
+.Xr fwe 4
+continue to use the legacy identify-based attachment model.
+.Pp
Up to 63 devices, including the host itself, can be attached to
a
.Nm
@@ -99,8 +115,11 @@
.El
.Sh SEE ALSO
.Xr dcons 4 ,
+.Xr fwcam 4 ,
+.Xr fwdv 4 ,
.Xr fwe 4 ,
.Xr fwip 4 ,
+.Xr fwisound 4 ,
.Xr fwohci 4 ,
.Xr pci 4 ,
.Xr sbp 4 ,
diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c
--- a/sys/dev/firewire/firewire.c
+++ b/sys/dev/firewire/firewire.c
@@ -86,12 +86,16 @@
static int firewire_resume(device_t);
static void firewire_xfer_timeout(void *, int);
static device_t firewire_add_child(device_t, u_int, const char *, int);
+static void firewire_child_deleted(device_t, device_t);
static void fw_try_bmr(void *);
static void fw_try_bmr_callback(struct fw_xfer *);
static void fw_asystart(struct fw_xfer *);
static int fw_get_tlabel(struct firewire_comm *, struct fw_xfer *);
static void fw_bus_probe(void *);
static void fw_attach_dev(struct firewire_comm *);
+static void fw_parse_units(struct fw_device *);
+static void fw_create_unit_children(struct firewire_comm *, struct fw_device *);
+static int fw_remove_unit_children(struct firewire_comm *, struct fw_device *);
static void fw_bus_probe_thread(void *);
#ifdef FW_VMACCESS
static void fw_vmaccess (struct fw_xfer *);
@@ -111,6 +115,7 @@
/* Bus interface */
DEVMETHOD(bus_add_child, firewire_add_child),
+ DEVMETHOD(bus_child_deleted, firewire_child_deleted),
DEVMETHOD_END
};
@@ -473,17 +478,39 @@
{
device_t child;
struct firewire_softc *sc;
+ struct fw_child_ivars *iv;
sc = device_get_softc(dev);
child = device_add_child(dev, name, unit);
if (child) {
- device_set_ivars(child, sc->fc);
+ iv = malloc(sizeof(*iv), M_FW, M_NOWAIT | M_ZERO);
+ if (iv == NULL) {
+ device_delete_child(dev, child);
+ return (NULL);
+ }
+ iv->type = FW_CHILD_BUS;
+ iv->u.fc = sc->fc;
+ device_set_ivars(child, iv);
device_probe_and_attach(child);
}
return child;
}
+static void
+firewire_child_deleted(device_t dev, device_t child)
+{
+ struct fw_child_ivars *iv;
+
+ iv = device_get_ivars(child);
+ if (iv != NULL) {
+ if (iv->type == FW_CHILD_UNIT && iv->u.unit != NULL)
+ iv->u.unit->dev = NULL;
+ free(iv, M_FW);
+ device_set_ivars(child, NULL);
+ }
+}
+
static int
firewire_resume(device_t dev)
{
@@ -523,6 +550,13 @@
if ((err = fwdev_destroydev(sc)) != 0)
return err;
+ /* Remove unit children before bus_generic_detach */
+ for (fwdev = STAILQ_FIRST(&fc->devices); fwdev != NULL;
+ fwdev = fwdev_next) {
+ fwdev_next = STAILQ_NEXT(fwdev, link);
+ fw_remove_unit_children(fc, fwdev);
+ }
+
if ((err = bus_generic_detach(dev)) != 0)
return err;
@@ -721,13 +755,22 @@
fw_reset_crom(fc);
+ /*
+ * Skip unit children; only bus-level children have post_busreset.
+ */
if (device_get_children(fc->bdev, &devlistp, &devcnt) == 0) {
- for (i = 0; i < devcnt; i++)
- if (device_get_state(devlistp[i]) >= DS_ATTACHED) {
- fdc = device_get_softc(devlistp[i]);
- if (fdc->post_busreset != NULL)
- fdc->post_busreset(fdc);
- }
+ for (i = 0; i < devcnt; i++) {
+ struct fw_child_ivars *iv;
+
+ if (device_get_state(devlistp[i]) < DS_ATTACHED)
+ continue;
+ iv = fw_get_ivars(devlistp[i]);
+ if (iv == NULL || iv->type != FW_CHILD_BUS)
+ continue;
+ fdc = device_get_softc(devlistp[i]);
+ if (fdc->post_busreset != NULL)
+ fdc->post_busreset(fdc);
+ }
free(devlistp, M_TEMP);
}
@@ -1585,6 +1628,7 @@
fwdev->dst = dfwdev->dst;
fwdev->maxrec = dfwdev->maxrec;
fwdev->status = dfwdev->status;
+ STAILQ_INIT(&fwdev->units);
/*
* Pre-1394a-2000 didn't have link_spd in
@@ -1638,10 +1682,17 @@
fwdev->status = FWDEVINIT;
/* unchanged ? */
if (bcmp(&csr[0], &fwdev->csrrom[0], sizeof(uint32_t) * 5) == 0) {
- if (firewire_debug)
- device_printf(fc->dev,
- "node%d: crom unchanged\n", node);
- return (0);
+ if (!STAILQ_EMPTY(&fwdev->units)) {
+ if (firewire_debug)
+ device_printf(fc->dev,
+ "node%d: crom unchanged\n", node);
+ fwdev->rom_changed = 0;
+ return (0);
+ }
+ /* Units lost after detach/reattach; re-parse. */
+ fwdev->rom_changed = 0;
+ } else {
+ fwdev->rom_changed = 1;
}
}
@@ -1764,6 +1815,136 @@
kproc_exit(0);
}
+static void
+fw_parse_units(struct fw_device *fwdev)
+{
+ struct csrhdr *hdr;
+ struct csrdirectory *rootdir, *udir;
+ struct csrreg *ureg;
+ struct fw_unit *unit;
+ uint32_t spec_id, sw_version;
+ uint32_t rom_quads, root_off, root_len;
+ uint32_t reg_off, udir_qoff, udir_len;
+ int ri, ui, uindex;
+
+ rom_quads = CSRROMSIZE / 4;
+ hdr = (struct csrhdr *)fwdev->csrrom;
+ if (hdr->info_len <= 1)
+ return;
+
+ root_off = 1 + hdr->info_len;
+ if (root_off >= rom_quads)
+ return;
+ rootdir = (struct csrdirectory *)&fwdev->csrrom[root_off];
+ root_len = rootdir->crc_len;
+ if (root_off + 1 + root_len > rom_quads)
+ return;
+
+ uindex = 0;
+ for (ri = 0; ri < (int)root_len; ri++) {
+ reg_off = root_off + 1 + ri;
+ if (reg_off >= rom_quads)
+ break;
+ if (rootdir->entry[ri].key != CROM_UDIR)
+ continue;
+
+ udir_qoff = reg_off + rootdir->entry[ri].val;
+ if (udir_qoff >= rom_quads)
+ continue;
+ udir = (struct csrdirectory *)&fwdev->csrrom[udir_qoff];
+ udir_len = udir->crc_len;
+ if (udir_qoff + 1 + udir_len > rom_quads)
+ continue;
+
+ spec_id = 0;
+ sw_version = 0;
+ for (ui = 0; ui < (int)udir_len; ui++) {
+ if (udir_qoff + 1 + ui >= rom_quads)
+ break;
+ ureg = &udir->entry[ui];
+ if (ureg->key == CSRKEY_SPEC)
+ spec_id = ureg->val;
+ else if (ureg->key == CSRKEY_VER)
+ sw_version = ureg->val;
+ }
+ if (spec_id == 0 && sw_version == 0)
+ continue;
+
+ unit = malloc(sizeof(*unit), M_FW, M_NOWAIT | M_ZERO);
+ if (unit == NULL)
+ continue;
+ unit->fwdev = fwdev;
+ unit->spec_id = spec_id;
+ unit->sw_version = sw_version;
+ unit->dir_offset = udir_qoff * 4;
+ STAILQ_INSERT_TAIL(&fwdev->units, unit, link);
+ uindex++;
+ }
+ if (firewire_debug && uindex > 0)
+ device_printf(fwdev->fc->bdev,
+ "node %d: %d unit director%s found\n",
+ fwdev->dst, uindex, uindex == 1 ? "y" : "ies");
+}
+
+static void
+fw_create_unit_children(struct firewire_comm *fc, struct fw_device *fwdev)
+{
+ struct fw_unit *unit;
+ struct fw_child_ivars *iv;
+
+ bus_topo_lock();
+ STAILQ_FOREACH(unit, &fwdev->units, link) {
+ if (unit->dev != NULL)
+ continue;
+ unit->dev = device_add_child(fc->bdev, NULL, DEVICE_UNIT_ANY);
+ if (unit->dev == NULL) {
+ device_printf(fc->bdev,
+ "failed to add unit child for node %d\n",
+ fwdev->dst);
+ continue;
+ }
+ iv = malloc(sizeof(*iv), M_FW, M_NOWAIT | M_ZERO);
+ if (iv == NULL) {
+ device_delete_child(fc->bdev, unit->dev);
+ unit->dev = NULL;
+ continue;
+ }
+ iv->type = FW_CHILD_UNIT;
+ iv->u.unit = unit;
+ device_set_ivars(unit->dev, iv);
+ if (firewire_debug)
+ device_printf(fc->bdev,
+ "node %d: unit spec=0x%06x ver=0x%06x\n",
+ fwdev->dst, unit->spec_id, unit->sw_version);
+ device_probe_and_attach(unit->dev);
+ }
+ bus_topo_unlock();
+}
+
+static int
+fw_remove_unit_children(struct firewire_comm *fc, struct fw_device *fwdev)
+{
+ struct fw_unit *unit, *next;
+ int err, ret;
+
+ ret = 0;
+ bus_topo_lock();
+ STAILQ_FOREACH_SAFE(unit, &fwdev->units, link, next) {
+ if (unit->dev != NULL) {
+ err = device_delete_child(fc->bdev, unit->dev);
+ if (err != 0) {
+ ret = err;
+ continue;
+ }
+ unit->dev = NULL;
+ }
+ STAILQ_REMOVE(&fwdev->units, unit, fw_unit, link);
+ free(unit, M_FW);
+ }
+ bus_topo_unlock();
+ return (ret);
+}
+
/*
* To attach sub-devices layer onto IEEE1394 bus.
*/
@@ -1780,6 +1961,15 @@
next = STAILQ_NEXT(fwdev, link);
if (fwdev->status == FWDEVINIT) {
fwdev->status = FWDEVATTACHED;
+ if (fwdev->rom_changed &&
+ !STAILQ_EMPTY(&fwdev->units)) {
+ if (fw_remove_unit_children(fc, fwdev) == 0)
+ fwdev->rom_changed = 0;
+ }
+ if (STAILQ_EMPTY(&fwdev->units)) {
+ fw_parse_units(fwdev);
+ }
+ fw_create_unit_children(fc, fwdev);
} else if (fwdev->status == FWDEVINVAL) {
fwdev->rcnt++;
if (firewire_debug)
@@ -1791,6 +1981,8 @@
* Remove devices which have not been seen
* for a while.
*/
+ if (fw_remove_unit_children(fc, fwdev) != 0)
+ continue;
STAILQ_REMOVE(&fc->devices, fwdev, fw_device,
link);
free(fwdev, M_FW);
@@ -1801,11 +1993,16 @@
err = device_get_children(fc->bdev, &devlistp, &devcnt);
if (err == 0) {
for (i = 0; i < devcnt; i++) {
- if (device_get_state(devlistp[i]) >= DS_ATTACHED) {
- fdc = device_get_softc(devlistp[i]);
- if (fdc->post_explore != NULL)
- fdc->post_explore(fdc);
- }
+ struct fw_child_ivars *iv;
+
+ if (device_get_state(devlistp[i]) < DS_ATTACHED)
+ continue;
+ iv = fw_get_ivars(devlistp[i]);
+ if (iv == NULL || iv->type != FW_CHILD_BUS)
+ continue;
+ fdc = device_get_softc(devlistp[i]);
+ if (fdc->post_explore != NULL)
+ fdc->post_explore(fdc);
}
free(devlistp, M_TEMP);
}
diff --git a/sys/dev/firewire/firewirereg.h b/sys/dev/firewire/firewirereg.h
--- a/sys/dev/firewire/firewirereg.h
+++ b/sys/dev/firewire/firewirereg.h
@@ -58,14 +58,38 @@
int rommax; /* offset from 0xffff f000 0000 */
uint32_t csrrom[CSRROMSIZE / 4];
int rcnt;
+ int rom_changed;
struct firewire_comm *fc;
uint32_t status;
#define FWDEVINIT 1
#define FWDEVATTACHED 2
#define FWDEVINVAL 3
+ STAILQ_HEAD(, fw_unit) units;
STAILQ_ENTRY(fw_device) link;
};
+struct fw_unit {
+ device_t dev;
+ struct fw_device *fwdev;
+ uint32_t spec_id;
+ uint32_t sw_version;
+ uint32_t dir_offset;
+ STAILQ_ENTRY(fw_unit) link;
+};
+
+enum fw_child_type {
+ FW_CHILD_BUS,
+ FW_CHILD_UNIT,
+};
+
+struct fw_child_ivars {
+ enum fw_child_type type;
+ union {
+ struct firewire_comm *fc;
+ struct fw_unit *unit;
+ } u;
+};
+
struct firewire_softc {
struct cdev *dev;
struct firewire_comm *fc;
@@ -294,6 +318,35 @@
extern devclass_t firewire_devclass;
extern int firewire_phydma_enable;
+static __inline struct fw_child_ivars *
+fw_get_ivars(device_t dev)
+{
+
+ return ((struct fw_child_ivars *)device_get_ivars(dev));
+}
+
+static __inline struct firewire_comm *
+fw_get_comm(device_t dev)
+{
+ struct fw_child_ivars *iv;
+
+ iv = fw_get_ivars(dev);
+ if (iv->type == FW_CHILD_BUS)
+ return (iv->u.fc);
+ return (iv->u.unit->fwdev->fc);
+}
+
+static __inline struct fw_unit *
+fw_get_unit(device_t dev)
+{
+ struct fw_child_ivars *iv;
+
+ iv = fw_get_ivars(dev);
+ if (iv->type == FW_CHILD_UNIT)
+ return (iv->u.unit);
+ return (NULL);
+}
+
#define FWPRI (PWAIT | PCATCH)
#define CALLOUT_INIT(x) callout_init(x, 1 /* mpsafe */)
diff --git a/sys/dev/firewire/if_fwe.c b/sys/dev/firewire/if_fwe.c
--- a/sys/dev/firewire/if_fwe.c
+++ b/sys/dev/firewire/if_fwe.c
@@ -123,10 +123,12 @@
{
device_t pa;
+ if (fw_get_unit(dev) != NULL)
+ return (ENXIO);
+
pa = device_get_parent(dev);
- if (device_get_unit(dev) != device_get_unit(pa)) {
+ if (device_get_unit(dev) != device_get_unit(pa))
return (ENXIO);
- }
device_set_desc(dev, "Ethernet over FireWire");
return (0);
@@ -150,7 +152,7 @@
fwe->stream_ch = stream_ch;
fwe->dma_ch = -1;
- fwe->fd.fc = device_get_ivars(dev);
+ fwe->fd.fc = fw_get_comm(dev);
if (tx_speed < 0)
tx_speed = fwe->fd.fc->speed;
diff --git a/sys/dev/firewire/if_fwip.c b/sys/dev/firewire/if_fwip.c
--- a/sys/dev/firewire/if_fwip.c
+++ b/sys/dev/firewire/if_fwip.c
@@ -134,10 +134,12 @@
{
device_t pa;
+ if (fw_get_unit(dev) != NULL)
+ return (ENXIO);
+
pa = device_get_parent(dev);
- if (device_get_unit(dev) != device_get_unit(pa)) {
+ if (device_get_unit(dev) != device_get_unit(pa))
return (ENXIO);
- }
device_set_desc(dev, "IP over FireWire");
return (0);
@@ -159,7 +161,7 @@
/* XXX */
fwip->dma_ch = -1;
- fwip->fd.fc = device_get_ivars(dev);
+ fwip->fd.fc = fw_get_comm(dev);
if (tx_speed < 0)
tx_speed = fwip->fd.fc->speed;
diff --git a/sys/dev/firewire/sbp.c b/sys/dev/firewire/sbp.c
--- a/sys/dev/firewire/sbp.c
+++ b/sys/dev/firewire/sbp.c
@@ -318,6 +318,9 @@
printf("sbp_probe\n");
END_DEBUG
+ if (fw_get_unit(dev) != NULL)
+ return (ENXIO);
+
device_set_desc(dev, "SBP-2/SCSI over FireWire");
#if 0
@@ -1917,7 +1920,7 @@
sbp_cold++;
sbp = device_get_softc(dev);
sbp->fd.dev = dev;
- sbp->fd.fc = fc = device_get_ivars(dev);
+ sbp->fd.fc = fc = fw_get_comm(dev);
mtx_init(&sbp->mtx, "sbp", NULL, MTX_DEF);
if (max_speed < 0)
diff --git a/sys/dev/firewire/sbp_targ.c b/sys/dev/firewire/sbp_targ.c
--- a/sys/dev/firewire/sbp_targ.c
+++ b/sys/dev/firewire/sbp_targ.c
@@ -249,10 +249,12 @@
{
device_t pa;
+ if (fw_get_unit(dev) != NULL)
+ return (ENXIO);
+
pa = device_get_parent(dev);
- if (device_get_unit(dev) != device_get_unit(pa)) {
+ if (device_get_unit(dev) != device_get_unit(pa))
return (ENXIO);
- }
device_set_desc(dev, "SBP-2/SCSI over FireWire target mode");
return (0);
@@ -1949,7 +1951,7 @@
bzero((void *)sc, sizeof(struct sbp_targ_softc));
mtx_init(&sc->mtx, "sbp_targ", NULL, MTX_DEF);
- sc->fd.fc = fc = device_get_ivars(dev);
+ sc->fd.fc = fc = fw_get_comm(dev);
sc->fd.dev = dev;
sc->fd.post_explore = (void *) sbp_targ_post_explore;
sc->fd.post_busreset = (void *) sbp_targ_post_busreset;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Jul 15, 3:39 PM (5 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35100816
Default Alt Text
D58201.diff (14 KB)
Attached To
Mode
D58201: firewire: per-unit-directory child device support
Attached
Detach File
Event Timeline
Log In to Comment