Page MenuHomeFreeBSD

D58201.diff
No OneTemporary

D58201.diff

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

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)

Event Timeline