if (thdev->type == INTEL_TH_SWITCH) { struct intel_th *th = to_intel_th(hub); int i, lowest;
/* * disconnect outputs * * intel_th_child_remove returns 0 unconditionally, so there is * no need to check the return value of device_for_each_child.
*/
device_for_each_child(dev, thdev, intel_th_child_remove);
/* * Remove outputs, that is, hub's children: they are created * at hub's probe time by having the hub call * intel_th_output_enable() for each of them.
*/ for (i = 0, lowest = -1; i < th->num_thdevs; i++) { /* * Move the non-output devices from higher up the * th->thdev[] array to lower positions to maintain * a contiguous array.
*/ if (th->thdev[i]->type != INTEL_TH_OUTPUT) { if (lowest >= 0) {
th->thdev[lowest] = th->thdev[i];
th->thdev[i] = NULL;
++lowest;
}
for (r = 0; r < subdev->nres; r++) { struct resource *devres = th->resource; int bar = TH_MMIO_CONFIG;
/* * Take .end == 0 to mean 'take the whole bar', * .start then tells us which bar it is. Default to * TH_MMIO_CONFIG.
*/ if (!res[r].end && res[r].flags == IORESOURCE_MEM) {
bar = res[r].start;
err = -ENODEV; if (bar >= th->num_resources) goto fail_put_device;
res[r].start = 0;
res[r].end = resource_size(&devres[bar]) - 1;
}
dev_dbg(th->dev, "%s:%d @ %pR\n",
subdev->name, r, &res[r]);
} elseif (res[r].flags & IORESOURCE_IRQ) { /* * Only pass on the IRQ if we have useful interrupts: * the ones that can be configured via MINTCTL.
*/ if (INTEL_TH_CAP(th, has_mintctl) && th->irq != -1)
res[r].start = th->irq;
}
}
err = intel_th_device_add_resources(thdev, res, subdev->nres); if (err) goto fail_put_device;
err = device_add(&thdev->dev); if (err) goto fail_free_res;
/* need switch driver to be loaded to enumerate the rest */ if (subdev->type == INTEL_TH_SWITCH && !req) {
err = intel_th_request_hub_module(th); if (!err)
req++;
}
return thdev;
fail_free_res:
kfree(thdev->resource);
fail_put_device:
put_device(&thdev->dev);
return ERR_PTR(err);
}
/** * intel_th_output_enable() - find and enable a device for a given output type * @th: Intel TH instance * @otype: output type * * Go through the unallocated output devices, find the first one whos type * matches @otype and instantiate it. These devices are removed when the hub * device is removed, see intel_th_remove().
*/ int intel_th_output_enable(struct intel_th *th, unsignedint otype)
{ struct intel_th_device *thdev; int src = 0, dst = 0;
for (src = 0, dst = 0; dst <= th->num_thdevs; src++, dst++) { for (; src < ARRAY_SIZE(intel_th_subdevices); src++) { if (intel_th_subdevices[src].type != INTEL_TH_OUTPUT) continue;
if (intel_th_subdevices[src].otype != otype) continue;
break;
}
/* no unallocated matching subdevices */ if (src == ARRAY_SIZE(intel_th_subdevices)) return -ENODEV;
for (; dst < th->num_thdevs; dst++) { if (th->thdev[dst]->type != INTEL_TH_OUTPUT) continue;
if (th->thdev[dst]->output.type != otype) continue;
break;
}
/* * intel_th_subdevices[src] matches our requirements and is * not matched in th::thdev[]
*/ if (dst == th->num_thdevs) goto found;
}
return -ENODEV;
found:
thdev = intel_th_subdevice_alloc(th, &intel_th_subdevices[src]); if (IS_ERR(thdev)) return PTR_ERR(thdev);
staticint intel_th_populate(struct intel_th *th)
{ int src;
/* create devices for each intel_th_subdevice */ for (src = 0; src < ARRAY_SIZE(intel_th_subdevices); src++) { conststruct intel_th_subdevice *subdev =
&intel_th_subdevices[src]; struct intel_th_device *thdev;
/* only allow SOURCE and SWITCH devices in host mode */ if ((INTEL_TH_CAP(th, host_mode_only) || host_mode) &&
subdev->type == INTEL_TH_OUTPUT) continue;
/* * don't enable port OUTPUTs in this path; SWITCH enables them * via intel_th_output_enable()
*/ if (subdev->type == INTEL_TH_OUTPUT &&
subdev->otype != GTH_NONE) continue;
thdev = intel_th_subdevice_alloc(th, subdev); /* note: caller should free subdevices from th::thdev[] */ if (IS_ERR(thdev)) { /* ENODEV for individual subdevices is allowed */ if (PTR_ERR(thdev) == -ENODEV) continue;
for (i = 0; i < th->num_thdevs; i++) { if (th->thdev[i]->type != INTEL_TH_OUTPUT) continue;
d = to_intel_th_driver(th->thdev[i]->dev.driver); if (d && d->irq)
ret |= d->irq(th->thdev[i]);
}
return ret;
}
/** * intel_th_alloc() - allocate a new Intel TH device and its subdevices * @dev: parent device * @drvdata: data private to the driver * @devres: resources indexed by th_mmio_idx * @ndevres: number of entries in the @devres resources
*/ struct intel_th *
intel_th_alloc(struct device *dev, conststruct intel_th_drvdata *drvdata, struct resource *devres, unsignedint ndevres)
{ int err, r, nr_mmios = 0; struct intel_th *th;
th = kzalloc(sizeof(*th), GFP_KERNEL); if (!th) return ERR_PTR(-ENOMEM);
intel_th_device_remove(th->hub); for (i = 0; i < th->num_thdevs; i++) { if (th->thdev[i] != th->hub)
intel_th_device_remove(th->thdev[i]);
th->thdev[i] = NULL;
}
th->num_thdevs = 0;
for (i = 0; i < th->num_irqs; i++)
devm_free_irq(th->dev, th->irq + i, th);
int intel_th_set_output(struct intel_th_device *thdev, unsignedint master)
{ struct intel_th_device *hub = to_intel_th_hub(thdev); struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver); int ret;
/* In host mode, this is up to the external debugger, do nothing. */ if (hub->host_mode) return 0;
/* * hub is instantiated together with the source device that * calls here, so guaranteed to be present.
*/
hubdrv = to_intel_th_driver(hub->dev.driver); if (!hubdrv || !try_module_get(hubdrv->driver.owner)) return -EINVAL;
if (!hubdrv->set_output) {
ret = -ENOTSUPP; goto out;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.