1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * WWAN device simulator for WWAN framework testing.
4 *
5 * Copyright (c) 2021, 2025, Sergey Ryazanov <ryazanov.s.a@gmail.com>
6 */
7
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/slab.h>
13 #include <linux/device.h>
14 #include <linux/spinlock.h>
15 #include <linux/time.h>
16 #include <linux/list.h>
17 #include <linux/skbuff.h>
18 #include <linux/timer.h>
19 #include <linux/netdevice.h>
20 #include <linux/wwan.h>
21 #include <linux/debugfs.h>
22 #include <linux/workqueue.h>
23
24 #include <net/arp.h>
25
26 static int wwan_hwsim_devsnum = 2;
27 module_param_named(devices, wwan_hwsim_devsnum, int, 0444);
28 MODULE_PARM_DESC(devices, "Number of simulated devices");
29
30 static const struct class wwan_hwsim_class = {
31 .name = "wwan_hwsim",
32 };
33
34 static struct dentry *wwan_hwsim_debugfs_topdir;
35 static struct dentry *wwan_hwsim_debugfs_devcreate;
36
37 static DEFINE_SPINLOCK(wwan_hwsim_devs_lock);
38 static LIST_HEAD(wwan_hwsim_devs);
39 static unsigned int wwan_hwsim_dev_idx;
40 static struct workqueue_struct *wwan_wq;
41
42 struct wwan_hwsim_dev {
43 struct list_head list;
44 unsigned int id;
45 struct device dev;
46 struct work_struct del_work;
47 struct dentry *debugfs_topdir;
48 struct dentry *debugfs_portcreate;
49 spinlock_t ports_lock; /* Serialize ports creation/deletion */
50 unsigned int port_idx;
51 struct list_head ports;
52 };
53
54 struct wwan_hwsim_port {
55 struct list_head list;
56 unsigned int id;
57 struct wwan_hwsim_dev *dev;
58 struct wwan_port *wwan;
59 struct work_struct del_work;
60 struct dentry *debugfs_topdir;
61 union {
62 struct {
63 enum { /* AT command parser state */
64 AT_PARSER_WAIT_A,
65 AT_PARSER_WAIT_T,
66 AT_PARSER_WAIT_TERM,
67 AT_PARSER_SKIP_LINE,
68 } pstate;
69 } at_emul;
70 struct {
71 struct timer_list timer;
72 } nmea_emul;
73 };
74 };
75
76 static const struct file_operations wwan_hwsim_debugfs_portdestroy_fops;
77 static const struct file_operations wwan_hwsim_debugfs_portcreate_fops;
78 static const struct file_operations wwan_hwsim_debugfs_devdestroy_fops;
79 static void wwan_hwsim_port_del_work(struct work_struct *work);
80 static void wwan_hwsim_dev_del_work(struct work_struct *work);
81
wwan_hwsim_netdev_xmit(struct sk_buff * skb,struct net_device * ndev)82 static netdev_tx_t wwan_hwsim_netdev_xmit(struct sk_buff *skb,
83 struct net_device *ndev)
84 {
85 ndev->stats.tx_packets++;
86 ndev->stats.tx_bytes += skb->len;
87 consume_skb(skb);
88 return NETDEV_TX_OK;
89 }
90
91 static const struct net_device_ops wwan_hwsim_netdev_ops = {
92 .ndo_start_xmit = wwan_hwsim_netdev_xmit,
93 };
94
wwan_hwsim_netdev_setup(struct net_device * ndev)95 static void wwan_hwsim_netdev_setup(struct net_device *ndev)
96 {
97 ndev->netdev_ops = &wwan_hwsim_netdev_ops;
98 ndev->needs_free_netdev = true;
99
100 ndev->mtu = ETH_DATA_LEN;
101 ndev->min_mtu = ETH_MIN_MTU;
102 ndev->max_mtu = ETH_MAX_MTU;
103
104 ndev->type = ARPHRD_NONE;
105 ndev->flags = IFF_POINTOPOINT | IFF_NOARP;
106 }
107
108 static const struct wwan_ops wwan_hwsim_wwan_rtnl_ops = {
109 .priv_size = 0, /* No private data */
110 .setup = wwan_hwsim_netdev_setup,
111 };
112
wwan_hwsim_at_emul_start(struct wwan_port * wport)113 static int wwan_hwsim_at_emul_start(struct wwan_port *wport)
114 {
115 struct wwan_hwsim_port *port = wwan_port_get_drvdata(wport);
116
117 port->at_emul.pstate = AT_PARSER_WAIT_A;
118
119 return 0;
120 }
121
wwan_hwsim_at_emul_stop(struct wwan_port * wport)122 static void wwan_hwsim_at_emul_stop(struct wwan_port *wport)
123 {
124 }
125
126 /* Implements a minimalistic AT commands parser that echo input back and
127 * reply with 'OK' to each input command. See AT command protocol details in the
128 * ITU-T V.250 recomendations document.
129 *
130 * Be aware that this processor is not fully V.250 compliant.
131 */
wwan_hwsim_at_emul_tx(struct wwan_port * wport,struct sk_buff * in)132 static int wwan_hwsim_at_emul_tx(struct wwan_port *wport, struct sk_buff *in)
133 {
134 struct wwan_hwsim_port *port = wwan_port_get_drvdata(wport);
135 struct sk_buff *out;
136 int i, n, s;
137
138 /* Estimate a max possible number of commands by counting the number of
139 * termination chars (S3 param, CR by default). And then allocate the
140 * output buffer that will be enough to fit the echo and result codes of
141 * all commands.
142 */
143 for (i = 0, n = 0; i < in->len; ++i)
144 if (in->data[i] == '\r')
145 n++;
146 n = in->len + n * (2 + 2 + 2); /* Output buffer size */
147 out = alloc_skb(n, GFP_KERNEL);
148 if (!out)
149 return -ENOMEM;
150
151 for (i = 0, s = 0; i < in->len; ++i) {
152 char c = in->data[i];
153
154 if (port->at_emul.pstate == AT_PARSER_WAIT_A) {
155 if (c == 'A' || c == 'a')
156 port->at_emul.pstate = AT_PARSER_WAIT_T;
157 else if (c != '\n') /* Ignore formating char */
158 port->at_emul.pstate = AT_PARSER_SKIP_LINE;
159 } else if (port->at_emul.pstate == AT_PARSER_WAIT_T) {
160 if (c == 'T' || c == 't')
161 port->at_emul.pstate = AT_PARSER_WAIT_TERM;
162 else
163 port->at_emul.pstate = AT_PARSER_SKIP_LINE;
164 } else if (port->at_emul.pstate == AT_PARSER_WAIT_TERM) {
165 if (c != '\r')
166 continue;
167 /* Consume the trailing formatting char as well */
168 if ((i + 1) < in->len && in->data[i + 1] == '\n')
169 i++;
170 n = i - s + 1;
171 skb_put_data(out, &in->data[s], n);/* Echo */
172 skb_put_data(out, "\r\nOK\r\n", 6);
173 s = i + 1;
174 port->at_emul.pstate = AT_PARSER_WAIT_A;
175 } else if (port->at_emul.pstate == AT_PARSER_SKIP_LINE) {
176 if (c != '\r')
177 continue;
178 port->at_emul.pstate = AT_PARSER_WAIT_A;
179 }
180 }
181
182 if (i > s) {
183 /* Echo the processed portion of a not yet completed command */
184 n = i - s;
185 skb_put_data(out, &in->data[s], n);
186 }
187
188 consume_skb(in);
189
190 wwan_port_rx(wport, out);
191
192 return 0;
193 }
194
195 static const struct wwan_port_ops wwan_hwsim_at_emul_port_ops = {
196 .start = wwan_hwsim_at_emul_start,
197 .stop = wwan_hwsim_at_emul_stop,
198 .tx = wwan_hwsim_at_emul_tx,
199 };
200
201 #if IS_ENABLED(CONFIG_GNSS)
202 #define NMEA_MAX_LEN 82 /* Max sentence length */
203 #define NMEA_TRAIL_LEN 5 /* '*' + Checksum + <CR><LF> */
204 #define NMEA_MAX_DATA_LEN (NMEA_MAX_LEN - NMEA_TRAIL_LEN)
205
206 static __printf(2, 3)
wwan_hwsim_nmea_skb_push_sentence(struct sk_buff * skb,const char * fmt,...)207 void wwan_hwsim_nmea_skb_push_sentence(struct sk_buff *skb,
208 const char *fmt, ...)
209 {
210 unsigned char *s, *p;
211 va_list ap;
212 u8 cs = 0;
213 int len;
214
215 s = skb_put(skb, NMEA_MAX_LEN + 1); /* +'\0' */
216 if (!s)
217 return;
218
219 va_start(ap, fmt);
220 len = vsnprintf(s, NMEA_MAX_DATA_LEN + 1, fmt, ap);
221 va_end(ap);
222 if (WARN_ON_ONCE(len > NMEA_MAX_DATA_LEN))/* No space for trailer */
223 return;
224
225 for (p = s + 1; *p != '\0'; ++p)/* Skip leading '$' or '!' */
226 cs ^= *p;
227 p += snprintf(p, 5 + 1, "*%02X\r\n", cs);
228
229 len = (p - s) - (NMEA_MAX_LEN + 1); /* exp. vs real length diff */
230 skb->tail += len; /* Adjust tail to real length */
231 skb->len += len;
232 }
233
wwan_hwsim_nmea_emul_timer(struct timer_list * t)234 static void wwan_hwsim_nmea_emul_timer(struct timer_list *t)
235 {
236 /* 43.74754722298909 N 11.25759835922875 E in DMM format */
237 static const unsigned int coord[4 * 2] = { 43, 44, 8528, 0,
238 11, 15, 4559, 0 };
239 struct wwan_hwsim_port *port = timer_container_of(port, t, nmea_emul.timer);
240 struct sk_buff *skb;
241 struct tm tm;
242
243 time64_to_tm(ktime_get_real_seconds(), 0, &tm);
244
245 mod_timer(&port->nmea_emul.timer, jiffies + HZ); /* 1 second */
246
247 skb = alloc_skb(NMEA_MAX_LEN * 2 + 2, GFP_ATOMIC); /* GGA + RMC */
248 if (!skb)
249 return;
250
251 wwan_hwsim_nmea_skb_push_sentence(skb,
252 "$GPGGA,%02u%02u%02u.000,%02u%02u.%04u,%c,%03u%02u.%04u,%c,1,7,1.03,176.2,M,55.2,M,,",
253 tm.tm_hour, tm.tm_min, tm.tm_sec,
254 coord[0], coord[1], coord[2],
255 coord[3] ? 'S' : 'N',
256 coord[4], coord[5], coord[6],
257 coord[7] ? 'W' : 'E');
258
259 wwan_hwsim_nmea_skb_push_sentence(skb,
260 "$GPRMC,%02u%02u%02u.000,A,%02u%02u.%04u,%c,%03u%02u.%04u,%c,0.02,31.66,%02u%02u%02u,,,A",
261 tm.tm_hour, tm.tm_min, tm.tm_sec,
262 coord[0], coord[1], coord[2],
263 coord[3] ? 'S' : 'N',
264 coord[4], coord[5], coord[6],
265 coord[7] ? 'W' : 'E',
266 tm.tm_mday, tm.tm_mon + 1,
267 (unsigned int)tm.tm_year - 100);
268
269 wwan_port_rx(port->wwan, skb);
270 }
271
wwan_hwsim_nmea_emul_start(struct wwan_port * wport)272 static int wwan_hwsim_nmea_emul_start(struct wwan_port *wport)
273 {
274 struct wwan_hwsim_port *port = wwan_port_get_drvdata(wport);
275
276 timer_setup(&port->nmea_emul.timer, wwan_hwsim_nmea_emul_timer, 0);
277 wwan_hwsim_nmea_emul_timer(&port->nmea_emul.timer);
278
279 return 0;
280 }
281
wwan_hwsim_nmea_emul_stop(struct wwan_port * wport)282 static void wwan_hwsim_nmea_emul_stop(struct wwan_port *wport)
283 {
284 struct wwan_hwsim_port *port = wwan_port_get_drvdata(wport);
285
286 timer_delete_sync(&port->nmea_emul.timer);
287 }
288
wwan_hwsim_nmea_emul_tx(struct wwan_port * wport,struct sk_buff * in)289 static int wwan_hwsim_nmea_emul_tx(struct wwan_port *wport, struct sk_buff *in)
290 {
291 consume_skb(in);
292
293 return 0;
294 }
295
296 static const struct wwan_port_ops wwan_hwsim_nmea_emul_port_ops = {
297 .start = wwan_hwsim_nmea_emul_start,
298 .stop = wwan_hwsim_nmea_emul_stop,
299 .tx = wwan_hwsim_nmea_emul_tx,
300 };
301 #endif
302
wwan_hwsim_port_new(struct wwan_hwsim_dev * dev,enum wwan_port_type type)303 static struct wwan_hwsim_port *wwan_hwsim_port_new(struct wwan_hwsim_dev *dev,
304 enum wwan_port_type type)
305 {
306 const struct wwan_port_ops *ops;
307 struct wwan_hwsim_port *port;
308 char name[0x10];
309 int err;
310
311 if (type == WWAN_PORT_AT)
312 ops = &wwan_hwsim_at_emul_port_ops;
313 #if IS_ENABLED(CONFIG_GNSS)
314 else if (type == WWAN_PORT_NMEA)
315 ops = &wwan_hwsim_nmea_emul_port_ops;
316 #endif
317 else
318 return ERR_PTR(-EINVAL);
319
320 port = kzalloc_obj(*port);
321 if (!port)
322 return ERR_PTR(-ENOMEM);
323
324 port->dev = dev;
325
326 spin_lock(&dev->ports_lock);
327 port->id = dev->port_idx++;
328 spin_unlock(&dev->ports_lock);
329
330 port->wwan = wwan_create_port(&dev->dev, type, ops, NULL, port);
331 if (IS_ERR(port->wwan)) {
332 err = PTR_ERR(port->wwan);
333 goto err_free_port;
334 }
335
336 INIT_WORK(&port->del_work, wwan_hwsim_port_del_work);
337
338 snprintf(name, sizeof(name), "port%u", port->id);
339 port->debugfs_topdir = debugfs_create_dir(name, dev->debugfs_topdir);
340 debugfs_create_file("destroy", 0200, port->debugfs_topdir, port,
341 &wwan_hwsim_debugfs_portdestroy_fops);
342
343 return port;
344
345 err_free_port:
346 kfree(port);
347
348 return ERR_PTR(err);
349 }
350
wwan_hwsim_port_del(struct wwan_hwsim_port * port)351 static void wwan_hwsim_port_del(struct wwan_hwsim_port *port)
352 {
353 debugfs_remove(port->debugfs_topdir);
354
355 /* Make sure that there is no pending deletion work */
356 if (current_work() != &port->del_work)
357 cancel_work_sync(&port->del_work);
358
359 wwan_remove_port(port->wwan);
360 kfree(port);
361 }
362
wwan_hwsim_port_del_work(struct work_struct * work)363 static void wwan_hwsim_port_del_work(struct work_struct *work)
364 {
365 struct wwan_hwsim_port *port =
366 container_of(work, typeof(*port), del_work);
367 struct wwan_hwsim_dev *dev = port->dev;
368
369 spin_lock(&dev->ports_lock);
370 if (list_empty(&port->list)) {
371 /* Someone else deleting port at the moment */
372 spin_unlock(&dev->ports_lock);
373 return;
374 }
375 list_del_init(&port->list);
376 spin_unlock(&dev->ports_lock);
377
378 wwan_hwsim_port_del(port);
379 }
380
wwan_hwsim_dev_release(struct device * sysdev)381 static void wwan_hwsim_dev_release(struct device *sysdev)
382 {
383 struct wwan_hwsim_dev *dev = container_of(sysdev, typeof(*dev), dev);
384
385 kfree(dev);
386 }
387
wwan_hwsim_dev_new(void)388 static struct wwan_hwsim_dev *wwan_hwsim_dev_new(void)
389 {
390 struct wwan_hwsim_dev *dev;
391 int err;
392
393 dev = kzalloc_obj(*dev);
394 if (!dev)
395 return ERR_PTR(-ENOMEM);
396
397 spin_lock(&wwan_hwsim_devs_lock);
398 dev->id = wwan_hwsim_dev_idx++;
399 spin_unlock(&wwan_hwsim_devs_lock);
400
401 dev->dev.release = wwan_hwsim_dev_release;
402 dev->dev.class = &wwan_hwsim_class;
403 dev_set_name(&dev->dev, "hwsim%u", dev->id);
404
405 spin_lock_init(&dev->ports_lock);
406 INIT_LIST_HEAD(&dev->ports);
407
408 err = device_register(&dev->dev);
409 if (err)
410 goto err_free_dev;
411
412 INIT_WORK(&dev->del_work, wwan_hwsim_dev_del_work);
413
414 err = wwan_register_ops(&dev->dev, &wwan_hwsim_wwan_rtnl_ops, dev, 1);
415 if (err)
416 goto err_unreg_dev;
417
418 dev->debugfs_topdir = debugfs_create_dir(dev_name(&dev->dev),
419 wwan_hwsim_debugfs_topdir);
420 debugfs_create_file("destroy", 0200, dev->debugfs_topdir, dev,
421 &wwan_hwsim_debugfs_devdestroy_fops);
422 dev->debugfs_portcreate =
423 debugfs_create_file("portcreate", 0200,
424 dev->debugfs_topdir, dev,
425 &wwan_hwsim_debugfs_portcreate_fops);
426
427 return dev;
428
429 err_unreg_dev:
430 device_unregister(&dev->dev);
431 /* Memory will be freed in the device release callback */
432
433 return ERR_PTR(err);
434
435 err_free_dev:
436 put_device(&dev->dev);
437
438 return ERR_PTR(err);
439 }
440
wwan_hwsim_dev_del(struct wwan_hwsim_dev * dev)441 static void wwan_hwsim_dev_del(struct wwan_hwsim_dev *dev)
442 {
443 debugfs_remove(dev->debugfs_portcreate); /* Avoid new ports */
444
445 spin_lock(&dev->ports_lock);
446 while (!list_empty(&dev->ports)) {
447 struct wwan_hwsim_port *port;
448
449 port = list_first_entry(&dev->ports, struct wwan_hwsim_port,
450 list);
451 list_del_init(&port->list);
452 spin_unlock(&dev->ports_lock);
453 wwan_hwsim_port_del(port);
454 spin_lock(&dev->ports_lock);
455 }
456 spin_unlock(&dev->ports_lock);
457
458 debugfs_remove(dev->debugfs_topdir);
459
460 /* This will remove all child netdev(s) */
461 wwan_unregister_ops(&dev->dev);
462
463 /* Make sure that there is no pending deletion work */
464 if (current_work() != &dev->del_work)
465 cancel_work_sync(&dev->del_work);
466
467 device_unregister(&dev->dev);
468 /* Memory will be freed in the device release callback */
469 }
470
wwan_hwsim_dev_del_work(struct work_struct * work)471 static void wwan_hwsim_dev_del_work(struct work_struct *work)
472 {
473 struct wwan_hwsim_dev *dev = container_of(work, typeof(*dev), del_work);
474
475 spin_lock(&wwan_hwsim_devs_lock);
476 if (list_empty(&dev->list)) {
477 /* Someone else deleting device at the moment */
478 spin_unlock(&wwan_hwsim_devs_lock);
479 return;
480 }
481 list_del_init(&dev->list);
482 spin_unlock(&wwan_hwsim_devs_lock);
483
484 wwan_hwsim_dev_del(dev);
485 }
486
wwan_hwsim_debugfs_portdestroy_write(struct file * file,const char __user * usrbuf,size_t count,loff_t * ppos)487 static ssize_t wwan_hwsim_debugfs_portdestroy_write(struct file *file,
488 const char __user *usrbuf,
489 size_t count, loff_t *ppos)
490 {
491 struct wwan_hwsim_port *port = file->private_data;
492
493 /* We can not delete port here since it will cause a deadlock due to
494 * waiting this callback to finish in the debugfs_remove() call. So,
495 * use workqueue.
496 */
497 queue_work(wwan_wq, &port->del_work);
498
499 return count;
500 }
501
502 static const struct file_operations wwan_hwsim_debugfs_portdestroy_fops = {
503 .write = wwan_hwsim_debugfs_portdestroy_write,
504 .open = simple_open,
505 .llseek = noop_llseek,
506 };
507
wwan_hwsim_debugfs_portcreate_write(struct file * file,const char __user * usrbuf,size_t count,loff_t * ppos)508 static ssize_t wwan_hwsim_debugfs_portcreate_write(struct file *file,
509 const char __user *usrbuf,
510 size_t count, loff_t *ppos)
511 {
512 struct wwan_hwsim_dev *dev = file->private_data;
513 struct wwan_hwsim_port *port;
514
515 port = wwan_hwsim_port_new(dev, WWAN_PORT_AT);
516 if (IS_ERR(port))
517 return PTR_ERR(port);
518
519 spin_lock(&dev->ports_lock);
520 list_add_tail(&port->list, &dev->ports);
521 spin_unlock(&dev->ports_lock);
522
523 return count;
524 }
525
526 static const struct file_operations wwan_hwsim_debugfs_portcreate_fops = {
527 .write = wwan_hwsim_debugfs_portcreate_write,
528 .open = simple_open,
529 .llseek = noop_llseek,
530 };
531
wwan_hwsim_debugfs_devdestroy_write(struct file * file,const char __user * usrbuf,size_t count,loff_t * ppos)532 static ssize_t wwan_hwsim_debugfs_devdestroy_write(struct file *file,
533 const char __user *usrbuf,
534 size_t count, loff_t *ppos)
535 {
536 struct wwan_hwsim_dev *dev = file->private_data;
537
538 /* We can not delete device here since it will cause a deadlock due to
539 * waiting this callback to finish in the debugfs_remove() call. So,
540 * use workqueue.
541 */
542 queue_work(wwan_wq, &dev->del_work);
543
544 return count;
545 }
546
547 static const struct file_operations wwan_hwsim_debugfs_devdestroy_fops = {
548 .write = wwan_hwsim_debugfs_devdestroy_write,
549 .open = simple_open,
550 .llseek = noop_llseek,
551 };
552
wwan_hwsim_debugfs_devcreate_write(struct file * file,const char __user * usrbuf,size_t count,loff_t * ppos)553 static ssize_t wwan_hwsim_debugfs_devcreate_write(struct file *file,
554 const char __user *usrbuf,
555 size_t count, loff_t *ppos)
556 {
557 struct wwan_hwsim_dev *dev;
558
559 dev = wwan_hwsim_dev_new();
560 if (IS_ERR(dev))
561 return PTR_ERR(dev);
562
563 spin_lock(&wwan_hwsim_devs_lock);
564 list_add_tail(&dev->list, &wwan_hwsim_devs);
565 spin_unlock(&wwan_hwsim_devs_lock);
566
567 return count;
568 }
569
570 static const struct file_operations wwan_hwsim_debugfs_devcreate_fops = {
571 .write = wwan_hwsim_debugfs_devcreate_write,
572 .open = simple_open,
573 .llseek = noop_llseek,
574 };
575
wwan_hwsim_init_devs(void)576 static int __init wwan_hwsim_init_devs(void)
577 {
578 struct wwan_hwsim_dev *dev;
579 int i, j;
580
581 for (i = 0; i < wwan_hwsim_devsnum; ++i) {
582 struct wwan_hwsim_port *port;
583
584 dev = wwan_hwsim_dev_new();
585 if (IS_ERR(dev))
586 return PTR_ERR(dev);
587
588 spin_lock(&wwan_hwsim_devs_lock);
589 list_add_tail(&dev->list, &wwan_hwsim_devs);
590 spin_unlock(&wwan_hwsim_devs_lock);
591
592 /* Create a few various ports per each device to accelerate
593 * the simulator readiness time.
594 */
595
596 for (j = 0; j < 2; ++j) {
597 port = wwan_hwsim_port_new(dev, WWAN_PORT_AT);
598 if (IS_ERR(port))
599 return PTR_ERR(port);
600
601 spin_lock(&dev->ports_lock);
602 list_add_tail(&port->list, &dev->ports);
603 spin_unlock(&dev->ports_lock);
604 }
605
606 #if IS_ENABLED(CONFIG_GNSS)
607 port = wwan_hwsim_port_new(dev, WWAN_PORT_NMEA);
608 if (IS_ERR(port)) {
609 dev_warn(&dev->dev, "failed to create initial NMEA port: %d\n",
610 (int)PTR_ERR(port));
611 } else {
612 spin_lock(&dev->ports_lock);
613 list_add_tail(&port->list, &dev->ports);
614 spin_unlock(&dev->ports_lock);
615 }
616 #endif
617 }
618
619 return 0;
620 }
621
wwan_hwsim_free_devs(void)622 static void wwan_hwsim_free_devs(void)
623 {
624 struct wwan_hwsim_dev *dev;
625
626 spin_lock(&wwan_hwsim_devs_lock);
627 while (!list_empty(&wwan_hwsim_devs)) {
628 dev = list_first_entry(&wwan_hwsim_devs, struct wwan_hwsim_dev,
629 list);
630 list_del_init(&dev->list);
631 spin_unlock(&wwan_hwsim_devs_lock);
632 wwan_hwsim_dev_del(dev);
633 spin_lock(&wwan_hwsim_devs_lock);
634 }
635 spin_unlock(&wwan_hwsim_devs_lock);
636 }
637
wwan_hwsim_init(void)638 static int __init wwan_hwsim_init(void)
639 {
640 int err;
641
642 if (wwan_hwsim_devsnum < 0 || wwan_hwsim_devsnum > 128)
643 return -EINVAL;
644
645 wwan_wq = alloc_workqueue("wwan_wq", WQ_PERCPU, 0);
646 if (!wwan_wq)
647 return -ENOMEM;
648
649 err = class_register(&wwan_hwsim_class);
650 if (err)
651 goto err_wq_destroy;
652
653 wwan_hwsim_debugfs_topdir = debugfs_create_dir("wwan_hwsim", NULL);
654 wwan_hwsim_debugfs_devcreate =
655 debugfs_create_file("devcreate", 0200,
656 wwan_hwsim_debugfs_topdir, NULL,
657 &wwan_hwsim_debugfs_devcreate_fops);
658
659 err = wwan_hwsim_init_devs();
660 if (err)
661 goto err_clean_devs;
662
663 return 0;
664
665 err_clean_devs:
666 debugfs_remove(wwan_hwsim_debugfs_devcreate); /* Avoid new devs */
667 wwan_hwsim_free_devs();
668 flush_workqueue(wwan_wq); /* Wait deletion works completion */
669 debugfs_remove(wwan_hwsim_debugfs_topdir);
670 class_unregister(&wwan_hwsim_class);
671 err_wq_destroy:
672 destroy_workqueue(wwan_wq);
673
674 return err;
675 }
676
wwan_hwsim_exit(void)677 static void __exit wwan_hwsim_exit(void)
678 {
679 debugfs_remove(wwan_hwsim_debugfs_devcreate); /* Avoid new devs */
680 wwan_hwsim_free_devs();
681 flush_workqueue(wwan_wq); /* Wait deletion works completion */
682 debugfs_remove(wwan_hwsim_debugfs_topdir);
683 class_unregister(&wwan_hwsim_class);
684 destroy_workqueue(wwan_wq);
685 }
686
687 module_init(wwan_hwsim_init);
688 module_exit(wwan_hwsim_exit);
689
690 MODULE_AUTHOR("Sergey Ryazanov");
691 MODULE_DESCRIPTION("Device simulator for WWAN framework");
692 MODULE_LICENSE("GPL");
693