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};
3842static 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+
148221static 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
256329int init_dell_smbios_wmi (void )
0 commit comments