Skip to content

Commit 92a9c19

Browse files
kaysieversschandinat
authored andcommitted
udlfb: remove sysfs framebuffer device with USB .disconnect()
The USB graphics card driver delays the unregistering of the framebuffer device to a workqueue, which breaks the userspace visible remove uevent sequence. Recent userspace tools started to support USB graphics card hotplug out-of-the-box and rely on proper events sent by the kernel. The framebuffer device is a direct child of the USB interface which is removed immediately after the USB .disconnect() callback. But the fb device in /sys stays around until its final cleanup, at a time where all the parent devices have been removed already. To work around that, we remove the sysfs fb device directly in the USB .disconnect() callback and leave only the cleanup of the internal fb data to the delayed work. Before: add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2 (usb) add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0 (usb) add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/graphics/fb0 (graphics) remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0 (usb) remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2 (usb) remove /2-1.2:1.0/graphics/fb0 (graphics) After: add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2 (usb) add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0 (usb) add /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/graphics/fb1 (graphics) remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/graphics/fb1 (graphics) remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0 (usb) remove /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2 (usb) Cc: [email protected] Tested-by: Bernie Thompson <[email protected]> Acked-by: Bernie Thompson <[email protected]> Signed-off-by: Kay Sievers <[email protected]> Signed-off-by: Florian Tobias Schandinat <[email protected]>
1 parent 857a8df commit 92a9c19

File tree

3 files changed

+19
-2
lines changed

3 files changed

+19
-2
lines changed

drivers/video/fbmem.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1665,14 +1665,14 @@ static int do_unregister_framebuffer(struct fb_info *fb_info)
16651665
if (ret)
16661666
return -EINVAL;
16671667

1668+
unlink_framebuffer(fb_info);
16681669
if (fb_info->pixmap.addr &&
16691670
(fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
16701671
kfree(fb_info->pixmap.addr);
16711672
fb_destroy_modelist(&fb_info->modelist);
16721673
registered_fb[i] = NULL;
16731674
num_registered_fb--;
16741675
fb_cleanup_device(fb_info);
1675-
device_destroy(fb_class, MKDEV(FB_MAJOR, i));
16761676
event.info = fb_info;
16771677
fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
16781678

@@ -1681,6 +1681,22 @@ static int do_unregister_framebuffer(struct fb_info *fb_info)
16811681
return 0;
16821682
}
16831683

1684+
int unlink_framebuffer(struct fb_info *fb_info)
1685+
{
1686+
int i;
1687+
1688+
i = fb_info->node;
1689+
if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
1690+
return -EINVAL;
1691+
1692+
if (fb_info->dev) {
1693+
device_destroy(fb_class, MKDEV(FB_MAJOR, i));
1694+
fb_info->dev = NULL;
1695+
}
1696+
return 0;
1697+
}
1698+
EXPORT_SYMBOL(unlink_framebuffer);
1699+
16841700
void remove_conflicting_framebuffers(struct apertures_struct *a,
16851701
const char *name, bool primary)
16861702
{

drivers/video/udlfb.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1739,7 +1739,7 @@ static void dlfb_usb_disconnect(struct usb_interface *interface)
17391739
for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
17401740
device_remove_file(info->dev, &fb_device_attrs[i]);
17411741
device_remove_bin_file(info->dev, &edid_attr);
1742-
1742+
unlink_framebuffer(info);
17431743
usb_set_intfdata(interface, NULL);
17441744

17451745
/* if clients still have us open, will be freed on last close */

include/linux/fb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,7 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
10031003
/* drivers/video/fbmem.c */
10041004
extern int register_framebuffer(struct fb_info *fb_info);
10051005
extern int unregister_framebuffer(struct fb_info *fb_info);
1006+
extern int unlink_framebuffer(struct fb_info *fb_info);
10061007
extern void remove_conflicting_framebuffers(struct apertures_struct *a,
10071008
const char *name, bool primary);
10081009
extern int fb_prepare_logo(struct fb_info *fb_info, int rotate);

0 commit comments

Comments
 (0)