Skip to content

Commit 93885e8

Browse files
Wer-Wolfjwrdegoede
authored andcommitted
platform/x86: dell-smbios-wmi: Stop using WMI chardev
The WMI chardev API will be removed in the near future. Reimplement the necessary bits used by this driver so that userspace software depending on it does no break. Signed-off-by: Armin Wolf <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Hans de Goede <[email protected]> Signed-off-by: Hans de Goede <[email protected]>
1 parent ba35896 commit 93885e8

File tree

1 file changed

+117
-44
lines changed

1 file changed

+117
-44
lines changed

drivers/platform/x86/dell/dell-smbios-wmi.c

Lines changed: 117 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88

99
#include <linux/device.h>
1010
#include <linux/dmi.h>
11+
#include <linux/fs.h>
1112
#include <linux/list.h>
13+
#include <linux/miscdevice.h>
1214
#include <linux/module.h>
1315
#include <linux/mutex.h>
1416
#include <linux/uaccess.h>
1517
#include <linux/wmi.h>
18+
#include <uapi/linux/wmi.h>
1619
#include "dell-smbios.h"
1720
#include "dell-wmi-descriptor.h"
1821

@@ -33,7 +36,8 @@ struct wmi_smbios_priv {
3336
struct list_head list;
3437
struct wmi_device *wdev;
3538
struct device *child;
36-
u32 req_buf_size;
39+
u64 req_buf_size;
40+
struct miscdevice char_dev;
3741
};
3842
static LIST_HEAD(wmi_list);
3943

@@ -109,48 +113,115 @@ static int dell_smbios_wmi_call(struct calling_interface_buffer *buffer)
109113
return ret;
110114
}
111115

112-
static long dell_smbios_wmi_filter(struct wmi_device *wdev, unsigned int cmd,
113-
struct wmi_ioctl_buffer *arg)
116+
static int dell_smbios_wmi_open(struct inode *inode, struct file *filp)
114117
{
115118
struct wmi_smbios_priv *priv;
116-
int ret = 0;
117-
118-
switch (cmd) {
119-
case DELL_WMI_SMBIOS_CMD:
120-
mutex_lock(&call_mutex);
121-
priv = dev_get_drvdata(&wdev->dev);
122-
if (!priv) {
123-
ret = -ENODEV;
124-
goto fail_smbios_cmd;
125-
}
126-
memcpy(priv->buf, arg, priv->req_buf_size);
127-
if (dell_smbios_call_filter(&wdev->dev, &priv->buf->std)) {
128-
dev_err(&wdev->dev, "Invalid call %d/%d:%8x\n",
129-
priv->buf->std.cmd_class,
130-
priv->buf->std.cmd_select,
131-
priv->buf->std.input[0]);
132-
ret = -EFAULT;
133-
goto fail_smbios_cmd;
134-
}
135-
ret = run_smbios_call(priv->wdev);
136-
if (ret)
137-
goto fail_smbios_cmd;
138-
memcpy(arg, priv->buf, priv->req_buf_size);
139-
fail_smbios_cmd:
140-
mutex_unlock(&call_mutex);
141-
break;
142-
default:
143-
ret = -ENOIOCTLCMD;
119+
120+
priv = container_of(filp->private_data, struct wmi_smbios_priv, char_dev);
121+
filp->private_data = priv;
122+
123+
return nonseekable_open(inode, filp);
124+
}
125+
126+
static ssize_t dell_smbios_wmi_read(struct file *filp, char __user *buffer, size_t length,
127+
loff_t *offset)
128+
{
129+
struct wmi_smbios_priv *priv = filp->private_data;
130+
131+
return simple_read_from_buffer(buffer, length, offset, &priv->req_buf_size,
132+
sizeof(priv->req_buf_size));
133+
}
134+
135+
static long dell_smbios_wmi_do_ioctl(struct wmi_smbios_priv *priv,
136+
struct dell_wmi_smbios_buffer __user *arg)
137+
{
138+
long ret;
139+
140+
if (get_user(priv->buf->length, &arg->length))
141+
return -EFAULT;
142+
143+
if (priv->buf->length < priv->req_buf_size)
144+
return -EINVAL;
145+
146+
/* if it's too big, warn, driver will only use what is needed */
147+
if (priv->buf->length > priv->req_buf_size)
148+
dev_err(&priv->wdev->dev, "Buffer %llu is bigger than required %llu\n",
149+
priv->buf->length, priv->req_buf_size);
150+
151+
if (copy_from_user(priv->buf, arg, priv->req_buf_size))
152+
return -EFAULT;
153+
154+
if (dell_smbios_call_filter(&priv->wdev->dev, &priv->buf->std)) {
155+
dev_err(&priv->wdev->dev, "Invalid call %d/%d:%8x\n",
156+
priv->buf->std.cmd_class,
157+
priv->buf->std.cmd_select,
158+
priv->buf->std.input[0]);
159+
160+
return -EINVAL;
144161
}
162+
163+
ret = run_smbios_call(priv->wdev);
164+
if (ret)
165+
return ret;
166+
167+
if (copy_to_user(arg, priv->buf, priv->req_buf_size))
168+
return -EFAULT;
169+
170+
return 0;
171+
}
172+
173+
static long dell_smbios_wmi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
174+
{
175+
struct dell_wmi_smbios_buffer __user *input = (struct dell_wmi_smbios_buffer __user *)arg;
176+
struct wmi_smbios_priv *priv = filp->private_data;
177+
long ret;
178+
179+
if (cmd != DELL_WMI_SMBIOS_CMD)
180+
return -ENOIOCTLCMD;
181+
182+
mutex_lock(&call_mutex);
183+
ret = dell_smbios_wmi_do_ioctl(priv, input);
184+
mutex_unlock(&call_mutex);
185+
145186
return ret;
146187
}
147188

189+
static const struct file_operations dell_smbios_wmi_fops = {
190+
.owner = THIS_MODULE,
191+
.open = dell_smbios_wmi_open,
192+
.read = dell_smbios_wmi_read,
193+
.unlocked_ioctl = dell_smbios_wmi_ioctl,
194+
.compat_ioctl = compat_ptr_ioctl,
195+
};
196+
197+
static void dell_smbios_wmi_unregister_chardev(void *data)
198+
{
199+
struct miscdevice *char_dev = data;
200+
201+
misc_deregister(char_dev);
202+
}
203+
204+
static int dell_smbios_wmi_register_chardev(struct wmi_smbios_priv *priv)
205+
{
206+
int ret;
207+
208+
priv->char_dev.minor = MISC_DYNAMIC_MINOR;
209+
priv->char_dev.name = "wmi/dell-smbios";
210+
priv->char_dev.fops = &dell_smbios_wmi_fops;
211+
priv->char_dev.mode = 0444;
212+
213+
ret = misc_register(&priv->char_dev);
214+
if (ret < 0)
215+
return ret;
216+
217+
return devm_add_action_or_reset(&priv->wdev->dev, dell_smbios_wmi_unregister_chardev,
218+
&priv->char_dev);
219+
}
220+
148221
static int dell_smbios_wmi_probe(struct wmi_device *wdev, const void *context)
149222
{
150-
struct wmi_driver *wdriver =
151-
container_of(wdev->dev.driver, struct wmi_driver, driver);
152223
struct wmi_smbios_priv *priv;
153-
u32 hotfix;
224+
u32 buffer_size, hotfix;
154225
int count;
155226
int ret;
156227

@@ -163,39 +234,42 @@ static int dell_smbios_wmi_probe(struct wmi_device *wdev, const void *context)
163234
if (!priv)
164235
return -ENOMEM;
165236

237+
priv->wdev = wdev;
238+
dev_set_drvdata(&wdev->dev, priv);
239+
166240
/* WMI buffer size will be either 4k or 32k depending on machine */
167-
if (!dell_wmi_get_size(&priv->req_buf_size))
241+
if (!dell_wmi_get_size(&buffer_size))
168242
return -EPROBE_DEFER;
169243

244+
priv->req_buf_size = buffer_size;
245+
170246
/* some SMBIOS calls fail unless BIOS contains hotfix */
171247
if (!dell_wmi_get_hotfix(&hotfix))
172248
return -EPROBE_DEFER;
173-
if (!hotfix) {
249+
250+
if (!hotfix)
174251
dev_warn(&wdev->dev,
175252
"WMI SMBIOS userspace interface not supported(%u), try upgrading to a newer BIOS\n",
176253
hotfix);
177-
wdriver->filter_callback = NULL;
178-
}
179254

180255
/* add in the length object we will use internally with ioctl */
181256
priv->req_buf_size += sizeof(u64);
182-
ret = set_required_buffer_size(wdev, priv->req_buf_size);
183-
if (ret)
184-
return ret;
185257

186258
count = get_order(priv->req_buf_size);
187259
priv->buf = (void *)devm_get_free_pages(&wdev->dev, GFP_KERNEL, count);
188260
if (!priv->buf)
189261
return -ENOMEM;
190262

263+
ret = dell_smbios_wmi_register_chardev(priv);
264+
if (ret)
265+
return ret;
266+
191267
/* ID is used by dell-smbios to set priority of drivers */
192268
wdev->dev.id = 1;
193269
ret = dell_smbios_register_device(&wdev->dev, &dell_smbios_wmi_call);
194270
if (ret)
195271
return ret;
196272

197-
priv->wdev = wdev;
198-
dev_set_drvdata(&wdev->dev, priv);
199273
mutex_lock(&list_mutex);
200274
list_add_tail(&priv->list, &wmi_list);
201275
mutex_unlock(&list_mutex);
@@ -250,7 +324,6 @@ static struct wmi_driver dell_smbios_wmi_driver = {
250324
.probe = dell_smbios_wmi_probe,
251325
.remove = dell_smbios_wmi_remove,
252326
.id_table = dell_smbios_wmi_id_table,
253-
.filter_callback = dell_smbios_wmi_filter,
254327
};
255328

256329
int init_dell_smbios_wmi(void)

0 commit comments

Comments
 (0)