.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * smscufx.c -- Framebuffer driver for SMSC UFX USB controller |
---|
3 | 4 | * |
---|
.. | .. |
---|
5 | 6 | * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it> |
---|
6 | 7 | * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com> |
---|
7 | 8 | * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com> |
---|
8 | | - * |
---|
9 | | - * This file is subject to the terms and conditions of the GNU General Public |
---|
10 | | - * License v2. See the file COPYING in the main directory of this archive for |
---|
11 | | - * more details. |
---|
12 | 9 | * |
---|
13 | 10 | * Based on udlfb, with work from Florian Echtler, Henrik Bjerregaard Pedersen, |
---|
14 | 11 | * and others. |
---|
.. | .. |
---|
100 | 97 | struct kref kref; |
---|
101 | 98 | int fb_count; |
---|
102 | 99 | bool virtualized; /* true when physical usb device not present */ |
---|
103 | | - struct delayed_work free_framebuffer_work; |
---|
104 | 100 | atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */ |
---|
105 | 101 | atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */ |
---|
106 | 102 | u8 *edid; /* null until we read edid from hw or get from sysfs */ |
---|
.. | .. |
---|
139 | 135 | static int ufx_submit_urb(struct ufx_data *dev, struct urb * urb, size_t len); |
---|
140 | 136 | static int ufx_alloc_urb_list(struct ufx_data *dev, int count, size_t size); |
---|
141 | 137 | static void ufx_free_urb_list(struct ufx_data *dev); |
---|
| 138 | + |
---|
| 139 | +static DEFINE_MUTEX(disconnect_mutex); |
---|
142 | 140 | |
---|
143 | 141 | /* reads a control register */ |
---|
144 | 142 | static int ufx_reg_read(struct ufx_data *dev, u32 index, u32 *data) |
---|
.. | .. |
---|
1073 | 1071 | if (user == 0 && !console) |
---|
1074 | 1072 | return -EBUSY; |
---|
1075 | 1073 | |
---|
| 1074 | + mutex_lock(&disconnect_mutex); |
---|
| 1075 | + |
---|
1076 | 1076 | /* If the USB device is gone, we don't accept new opens */ |
---|
1077 | | - if (dev->virtualized) |
---|
| 1077 | + if (dev->virtualized) { |
---|
| 1078 | + mutex_unlock(&disconnect_mutex); |
---|
1078 | 1079 | return -ENODEV; |
---|
| 1080 | + } |
---|
1079 | 1081 | |
---|
1080 | 1082 | dev->fb_count++; |
---|
1081 | 1083 | |
---|
.. | .. |
---|
1099 | 1101 | pr_debug("open /dev/fb%d user=%d fb_info=%p count=%d", |
---|
1100 | 1102 | info->node, user, info, dev->fb_count); |
---|
1101 | 1103 | |
---|
| 1104 | + mutex_unlock(&disconnect_mutex); |
---|
| 1105 | + |
---|
1102 | 1106 | return 0; |
---|
1103 | 1107 | } |
---|
1104 | 1108 | |
---|
.. | .. |
---|
1111 | 1115 | { |
---|
1112 | 1116 | struct ufx_data *dev = container_of(kref, struct ufx_data, kref); |
---|
1113 | 1117 | |
---|
1114 | | - /* this function will wait for all in-flight urbs to complete */ |
---|
1115 | | - if (dev->urbs.count > 0) |
---|
1116 | | - ufx_free_urb_list(dev); |
---|
1117 | | - |
---|
1118 | | - pr_debug("freeing ufx_data %p", dev); |
---|
1119 | | - |
---|
1120 | 1118 | kfree(dev); |
---|
1121 | 1119 | } |
---|
| 1120 | + |
---|
| 1121 | +static void ufx_ops_destory(struct fb_info *info) |
---|
| 1122 | +{ |
---|
| 1123 | + struct ufx_data *dev = info->par; |
---|
| 1124 | + int node = info->node; |
---|
| 1125 | + |
---|
| 1126 | + /* Assume info structure is freed after this point */ |
---|
| 1127 | + framebuffer_release(info); |
---|
| 1128 | + |
---|
| 1129 | + pr_debug("fb_info for /dev/fb%d has been freed", node); |
---|
| 1130 | + |
---|
| 1131 | + /* release reference taken by kref_init in probe() */ |
---|
| 1132 | + kref_put(&dev->kref, ufx_free); |
---|
| 1133 | +} |
---|
| 1134 | + |
---|
1122 | 1135 | |
---|
1123 | 1136 | static void ufx_release_urb_work(struct work_struct *work) |
---|
1124 | 1137 | { |
---|
.. | .. |
---|
1128 | 1141 | up(&unode->dev->urbs.limit_sem); |
---|
1129 | 1142 | } |
---|
1130 | 1143 | |
---|
1131 | | -static void ufx_free_framebuffer_work(struct work_struct *work) |
---|
| 1144 | +static void ufx_free_framebuffer(struct ufx_data *dev) |
---|
1132 | 1145 | { |
---|
1133 | | - struct ufx_data *dev = container_of(work, struct ufx_data, |
---|
1134 | | - free_framebuffer_work.work); |
---|
1135 | 1146 | struct fb_info *info = dev->info; |
---|
1136 | | - int node = info->node; |
---|
1137 | | - |
---|
1138 | | - unregister_framebuffer(info); |
---|
1139 | 1147 | |
---|
1140 | 1148 | if (info->cmap.len != 0) |
---|
1141 | 1149 | fb_dealloc_cmap(&info->cmap); |
---|
.. | .. |
---|
1146 | 1154 | fb_destroy_modelist(&info->modelist); |
---|
1147 | 1155 | |
---|
1148 | 1156 | dev->info = NULL; |
---|
1149 | | - |
---|
1150 | | - /* Assume info structure is freed after this point */ |
---|
1151 | | - framebuffer_release(info); |
---|
1152 | | - |
---|
1153 | | - pr_debug("fb_info for /dev/fb%d has been freed", node); |
---|
1154 | 1157 | |
---|
1155 | 1158 | /* ref taken in probe() as part of registering framebfufer */ |
---|
1156 | 1159 | kref_put(&dev->kref, ufx_free); |
---|
.. | .. |
---|
1163 | 1166 | { |
---|
1164 | 1167 | struct ufx_data *dev = info->par; |
---|
1165 | 1168 | |
---|
| 1169 | + mutex_lock(&disconnect_mutex); |
---|
| 1170 | + |
---|
1166 | 1171 | dev->fb_count--; |
---|
1167 | 1172 | |
---|
1168 | 1173 | /* We can't free fb_info here - fbmem will touch it when we return */ |
---|
1169 | 1174 | if (dev->virtualized && (dev->fb_count == 0)) |
---|
1170 | | - schedule_delayed_work(&dev->free_framebuffer_work, HZ); |
---|
| 1175 | + ufx_free_framebuffer(dev); |
---|
1171 | 1176 | |
---|
1172 | 1177 | if ((dev->fb_count == 0) && (info->fbdefio)) { |
---|
1173 | 1178 | fb_deferred_io_cleanup(info); |
---|
1174 | 1179 | kfree(info->fbdefio); |
---|
1175 | 1180 | info->fbdefio = NULL; |
---|
1176 | | - info->fbops->fb_mmap = ufx_ops_mmap; |
---|
1177 | 1181 | } |
---|
1178 | 1182 | |
---|
1179 | 1183 | pr_debug("released /dev/fb%d user=%d count=%d", |
---|
1180 | 1184 | info->node, user, dev->fb_count); |
---|
1181 | 1185 | |
---|
1182 | 1186 | kref_put(&dev->kref, ufx_free); |
---|
| 1187 | + |
---|
| 1188 | + mutex_unlock(&disconnect_mutex); |
---|
1183 | 1189 | |
---|
1184 | 1190 | return 0; |
---|
1185 | 1191 | } |
---|
.. | .. |
---|
1272 | 1278 | return 0; |
---|
1273 | 1279 | } |
---|
1274 | 1280 | |
---|
1275 | | -static struct fb_ops ufx_ops = { |
---|
| 1281 | +static const struct fb_ops ufx_ops = { |
---|
1276 | 1282 | .owner = THIS_MODULE, |
---|
1277 | 1283 | .fb_read = fb_sys_read, |
---|
1278 | 1284 | .fb_write = ufx_ops_write, |
---|
.. | .. |
---|
1287 | 1293 | .fb_blank = ufx_ops_blank, |
---|
1288 | 1294 | .fb_check_var = ufx_ops_check_var, |
---|
1289 | 1295 | .fb_set_par = ufx_ops_set_par, |
---|
| 1296 | + .fb_destroy = ufx_ops_destory, |
---|
1290 | 1297 | }; |
---|
1291 | 1298 | |
---|
1292 | 1299 | /* Assumes &info->lock held by caller |
---|
.. | .. |
---|
1653 | 1660 | |
---|
1654 | 1661 | /* allocates framebuffer driver structure, not framebuffer memory */ |
---|
1655 | 1662 | info = framebuffer_alloc(0, &usbdev->dev); |
---|
1656 | | - if (!info) { |
---|
1657 | | - dev_err(dev->gdev, "framebuffer_alloc failed\n"); |
---|
| 1663 | + if (!info) |
---|
1658 | 1664 | goto e_nomem; |
---|
1659 | | - } |
---|
1660 | 1665 | |
---|
1661 | 1666 | dev->info = info; |
---|
1662 | 1667 | info->par = dev; |
---|
1663 | 1668 | info->pseudo_palette = dev->pseudo_palette; |
---|
1664 | 1669 | info->fbops = &ufx_ops; |
---|
| 1670 | + INIT_LIST_HEAD(&info->modelist); |
---|
1665 | 1671 | |
---|
1666 | 1672 | retval = fb_alloc_cmap(&info->cmap, 256, 0); |
---|
1667 | 1673 | if (retval < 0) { |
---|
1668 | 1674 | dev_err(dev->gdev, "fb_alloc_cmap failed %x\n", retval); |
---|
1669 | 1675 | goto destroy_modedb; |
---|
1670 | 1676 | } |
---|
1671 | | - |
---|
1672 | | - INIT_DELAYED_WORK(&dev->free_framebuffer_work, |
---|
1673 | | - ufx_free_framebuffer_work); |
---|
1674 | | - |
---|
1675 | | - INIT_LIST_HEAD(&info->modelist); |
---|
1676 | 1677 | |
---|
1677 | 1678 | retval = ufx_reg_read(dev, 0x3000, &id_rev); |
---|
1678 | 1679 | check_warn_goto_error(retval, "error %d reading 0x3000 register from device", retval); |
---|
.. | .. |
---|
1746 | 1747 | static void ufx_usb_disconnect(struct usb_interface *interface) |
---|
1747 | 1748 | { |
---|
1748 | 1749 | struct ufx_data *dev; |
---|
| 1750 | + struct fb_info *info; |
---|
| 1751 | + |
---|
| 1752 | + mutex_lock(&disconnect_mutex); |
---|
1749 | 1753 | |
---|
1750 | 1754 | dev = usb_get_intfdata(interface); |
---|
| 1755 | + info = dev->info; |
---|
1751 | 1756 | |
---|
1752 | 1757 | pr_debug("USB disconnect starting\n"); |
---|
1753 | 1758 | |
---|
.. | .. |
---|
1761 | 1766 | |
---|
1762 | 1767 | /* if clients still have us open, will be freed on last close */ |
---|
1763 | 1768 | if (dev->fb_count == 0) |
---|
1764 | | - schedule_delayed_work(&dev->free_framebuffer_work, 0); |
---|
| 1769 | + ufx_free_framebuffer(dev); |
---|
1765 | 1770 | |
---|
1766 | | - /* release reference taken by kref_init in probe() */ |
---|
1767 | | - kref_put(&dev->kref, ufx_free); |
---|
| 1771 | + /* this function will wait for all in-flight urbs to complete */ |
---|
| 1772 | + if (dev->urbs.count > 0) |
---|
| 1773 | + ufx_free_urb_list(dev); |
---|
1768 | 1774 | |
---|
1769 | | - /* consider ufx_data freed */ |
---|
| 1775 | + pr_debug("freeing ufx_data %p", dev); |
---|
| 1776 | + |
---|
| 1777 | + unregister_framebuffer(info); |
---|
| 1778 | + |
---|
| 1779 | + mutex_unlock(&disconnect_mutex); |
---|
1770 | 1780 | } |
---|
1771 | 1781 | |
---|
1772 | 1782 | static struct usb_driver ufx_driver = { |
---|