blob: f64fdadadaeb13f537867353bdd901ae10886c08 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13/*
14 * SMD Packet Driver -- Provides a binary SMD non-muxed packet port
15 * interface.
16 */
17
18#include <linux/slab.h>
19#include <linux/cdev.h>
20#include <linux/module.h>
21#include <linux/fs.h>
22#include <linux/device.h>
23#include <linux/sched.h>
24#include <linux/spinlock.h>
25#include <linux/mutex.h>
26#include <linux/delay.h>
27#include <linux/uaccess.h>
28#include <linux/workqueue.h>
29#include <linux/platform_device.h>
30#include <linux/completion.h>
31#include <linux/msm_smd_pkt.h>
32#include <linux/poll.h>
33#include <asm/ioctls.h>
34
35#include <mach/msm_smd.h>
36#include <mach/peripheral-loader.h>
37
38#include "smd_private.h"
39#ifdef CONFIG_ARCH_FSM9XXX
40#define NUM_SMD_PKT_PORTS 4
41#else
42#define NUM_SMD_PKT_PORTS 12
43#endif
44
45#define LOOPBACK_INX (NUM_SMD_PKT_PORTS - 1)
46
47#define DEVICE_NAME "smdpkt"
48
49struct smd_pkt_dev {
50 struct cdev cdev;
51 struct device *devicep;
52 void *pil;
53 struct platform_driver driver;
54
55 struct smd_channel *ch;
56 struct mutex ch_lock;
57 struct mutex rx_lock;
58 struct mutex tx_lock;
59 wait_queue_head_t ch_read_wait_queue;
60 wait_queue_head_t ch_write_wait_queue;
61 wait_queue_head_t ch_opened_wait_queue;
62
63 int i;
64
65 int blocking_write;
66 int needed_space;
67 int is_open;
68 unsigned ch_size;
69 uint open_modem_wait;
70
71 int has_reset;
72 int do_reset_notification;
73 struct completion ch_allocated;
74
75} *smd_pkt_devp[NUM_SMD_PKT_PORTS];
76
77struct class *smd_pkt_classp;
78static dev_t smd_pkt_number;
79static struct delayed_work loopback_work;
80static void check_and_wakeup_reader(struct smd_pkt_dev *smd_pkt_devp);
81static void check_and_wakeup_writer(struct smd_pkt_dev *smd_pkt_devp);
82static uint32_t is_modem_smsm_inited(void);
83
84static int msm_smd_pkt_debug_mask;
85module_param_named(debug_mask, msm_smd_pkt_debug_mask,
86 int, S_IRUGO | S_IWUSR | S_IWGRP);
87#define DEBUG
88
89#ifdef DEBUG
90#define D_DUMP_BUFFER(prestr, cnt, buf) \
91do { \
92 if (msm_smd_pkt_debug_mask) \
93 print_hex_dump(KERN_DEBUG, prestr, \
94 DUMP_PREFIX_NONE, 16, 1, \
95 buf, cnt, 1); \
96} while (0)
97#else
98#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
99#endif
100
101#ifdef DEBUG
102#define D(x...) if (msm_smd_pkt_debug_mask) printk(x)
103#else
104#define D(x...) do {} while (0)
105#endif
106
107static ssize_t open_timeout_store(struct device *d,
108 struct device_attribute *attr,
109 const char *buf,
110 size_t n)
111{
112 int i;
113 unsigned long tmp;
114 for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
115 if (smd_pkt_devp[i]->devicep == d)
116 break;
117 }
118 if (!strict_strtoul(buf, 10, &tmp)) {
119 smd_pkt_devp[i]->open_modem_wait = tmp;
120 return n;
121 } else {
122 pr_err("%s: unable to convert: %s to an int\n", __func__,
123 buf);
124 return -EINVAL;
125 }
126}
127
128static ssize_t open_timeout_show(struct device *d,
129 struct device_attribute *attr,
130 char *buf)
131{
132 int i;
133 for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
134 if (smd_pkt_devp[i]->devicep == d)
135 break;
136 }
Karthikeyan Ramasubramanian63fa3d32011-09-29 17:06:26 -0600137 return snprintf(buf, PAGE_SIZE, "%d\n",
138 smd_pkt_devp[i]->open_modem_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139}
140
141static DEVICE_ATTR(open_timeout, 0664, open_timeout_show, open_timeout_store);
142
143static int notify_reset(struct smd_pkt_dev *smd_pkt_devp)
144{
145 smd_pkt_devp->do_reset_notification = 0;
146
147 return -ENETRESET;
148}
149
150static void clean_and_signal(struct smd_pkt_dev *smd_pkt_devp)
151{
152 smd_pkt_devp->do_reset_notification = 1;
153 smd_pkt_devp->has_reset = 1;
154
155 smd_pkt_devp->is_open = 0;
156
157 wake_up_interruptible(&smd_pkt_devp->ch_read_wait_queue);
158 wake_up_interruptible(&smd_pkt_devp->ch_write_wait_queue);
159 wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
160}
161
162static void loopback_probe_worker(struct work_struct *work)
163{
164
165 /* Wait for the modem SMSM to be inited for the SMD
166 ** Loopback channel to be allocated at the modem. Since
167 ** the wait need to be done atmost once, using msleep
168 ** doesn't degrade the performance. */
169 if (!is_modem_smsm_inited())
170 schedule_delayed_work(&loopback_work, msecs_to_jiffies(1000));
171 else
172 smsm_change_state(SMSM_APPS_STATE,
173 0, SMSM_SMD_LOOPBACK);
174
175}
176
177static long smd_pkt_ioctl(struct file *file, unsigned int cmd,
178 unsigned long arg)
179{
180 int ret;
181 struct smd_pkt_dev *smd_pkt_devp;
182
183 smd_pkt_devp = file->private_data;
184 if (!smd_pkt_devp)
185 return -EINVAL;
186
187 switch (cmd) {
188 case TIOCMGET:
189 ret = smd_tiocmget(smd_pkt_devp->ch);
190 break;
191 case TIOCMSET:
192 ret = smd_tiocmset(smd_pkt_devp->ch, arg, ~arg);
193 break;
194 case SMD_PKT_IOCTL_BLOCKING_WRITE:
195 ret = get_user(smd_pkt_devp->blocking_write, (int *)arg);
196 break;
197 default:
198 ret = -1;
199 }
200
201 return ret;
202}
203
204ssize_t smd_pkt_read(struct file *file,
205 char __user *buf,
206 size_t count,
207 loff_t *ppos)
208{
209 int r;
210 int bytes_read;
211 struct smd_pkt_dev *smd_pkt_devp;
212 struct smd_channel *chl;
213
214 D(KERN_ERR "%s: read %i bytes\n",
215 __func__, count);
216
217 smd_pkt_devp = file->private_data;
218
219 if (!smd_pkt_devp || !smd_pkt_devp->ch)
220 return -EINVAL;
221
222 if (smd_pkt_devp->do_reset_notification) {
223 /* notify client that a reset occurred */
224 return notify_reset(smd_pkt_devp);
225 }
226
227 chl = smd_pkt_devp->ch;
228wait_for_packet:
229 r = wait_event_interruptible(smd_pkt_devp->ch_read_wait_queue,
230 (smd_cur_packet_size(chl) > 0 &&
231 smd_read_avail(chl) >=
232 smd_cur_packet_size(chl)) ||
233 smd_pkt_devp->has_reset);
234
235 if (smd_pkt_devp->has_reset)
236 return notify_reset(smd_pkt_devp);
237
238 if (r < 0) {
239 /* qualify error message */
240 if (r != -ERESTARTSYS) {
241 /* we get this anytime a signal comes in */
242 printk(KERN_ERR "ERROR:%s:%i:%s: "
243 "wait_event_interruptible ret %i\n",
244 __FILE__,
245 __LINE__,
246 __func__,
247 r
248 );
249 }
250 return r;
251 }
252
253 /* Here we have a whole packet waiting for us */
254
255 mutex_lock(&smd_pkt_devp->rx_lock);
256 bytes_read = smd_cur_packet_size(smd_pkt_devp->ch);
257
258 D(KERN_ERR "%s: after wait_event_interruptible bytes_read = %i\n",
259 __func__, bytes_read);
260
261 if (bytes_read == 0 ||
262 bytes_read < smd_read_avail(smd_pkt_devp->ch)) {
263 D(KERN_ERR "%s: Nothing to read\n", __func__);
264 mutex_unlock(&smd_pkt_devp->rx_lock);
265 goto wait_for_packet;
266 }
267
268 if (bytes_read > count) {
269 printk(KERN_ERR "packet size %i > buffer size %i, "
270 "dropping packet!", bytes_read, count);
271 smd_read(smd_pkt_devp->ch, 0, bytes_read);
272 mutex_unlock(&smd_pkt_devp->rx_lock);
273 return -EINVAL;
274 }
275
276 if (smd_read_user_buffer(smd_pkt_devp->ch, buf, bytes_read)
277 != bytes_read) {
278 mutex_unlock(&smd_pkt_devp->rx_lock);
279 if (smd_pkt_devp->has_reset)
280 return notify_reset(smd_pkt_devp);
281
282 printk(KERN_ERR "user read: not enough data?!\n");
283 return -EINVAL;
284 }
285 D_DUMP_BUFFER("read: ", bytes_read, buf);
286 mutex_unlock(&smd_pkt_devp->rx_lock);
287
288 D(KERN_ERR "%s: just read %i bytes\n",
289 __func__, bytes_read);
290
291 /* check and wakeup read threads waiting on this device */
292 check_and_wakeup_reader(smd_pkt_devp);
293
294 return bytes_read;
295}
296
297ssize_t smd_pkt_write(struct file *file,
298 const char __user *buf,
299 size_t count,
300 loff_t *ppos)
301{
302 int r = 0;
303 struct smd_pkt_dev *smd_pkt_devp;
304 DEFINE_WAIT(write_wait);
305
306 D(KERN_ERR "%s: writting %i bytes\n",
307 __func__, count);
308
309 smd_pkt_devp = file->private_data;
310
311 if (!smd_pkt_devp || !smd_pkt_devp->ch)
312 return -EINVAL;
313
314 if (count > smd_pkt_devp->ch_size)
315 return -EINVAL;
316
317 if (smd_pkt_devp->do_reset_notification) {
318 /* notify client that a reset occurred */
319 return notify_reset(smd_pkt_devp);
320 }
321
322 if (smd_pkt_devp->blocking_write) {
323 for (;;) {
324 mutex_lock(&smd_pkt_devp->tx_lock);
325 if (smd_pkt_devp->has_reset) {
326 smd_disable_read_intr(smd_pkt_devp->ch);
327 mutex_unlock(&smd_pkt_devp->tx_lock);
328 return notify_reset(smd_pkt_devp);
329 }
330 if (signal_pending(current)) {
331 smd_disable_read_intr(smd_pkt_devp->ch);
332 mutex_unlock(&smd_pkt_devp->tx_lock);
333 return -ERESTARTSYS;
334 }
335
336 prepare_to_wait(&smd_pkt_devp->ch_write_wait_queue,
337 &write_wait, TASK_INTERRUPTIBLE);
338 smd_enable_read_intr(smd_pkt_devp->ch);
339 if (smd_write_avail(smd_pkt_devp->ch) < count) {
340 if (!smd_pkt_devp->needed_space ||
341 count < smd_pkt_devp->needed_space)
342 smd_pkt_devp->needed_space = count;
343 mutex_unlock(&smd_pkt_devp->tx_lock);
344 schedule();
345 } else
346 break;
347 }
348 finish_wait(&smd_pkt_devp->ch_write_wait_queue, &write_wait);
349 smd_disable_read_intr(smd_pkt_devp->ch);
350 if (smd_pkt_devp->has_reset) {
351 mutex_unlock(&smd_pkt_devp->tx_lock);
352 return notify_reset(smd_pkt_devp);
353 }
354 if (signal_pending(current)) {
355 mutex_unlock(&smd_pkt_devp->tx_lock);
356 return -ERESTARTSYS;
357 }
358 } else {
359 if (smd_pkt_devp->has_reset)
360 return notify_reset(smd_pkt_devp);
361 if (signal_pending(current))
362 return -ERESTARTSYS;
363
364 mutex_lock(&smd_pkt_devp->tx_lock);
365 if (smd_write_avail(smd_pkt_devp->ch) < count) {
366 D(KERN_ERR "%s: Not enough space to write\n",
367 __func__);
368 mutex_unlock(&smd_pkt_devp->tx_lock);
369 return -ENOMEM;
370 }
371 }
372
373 D_DUMP_BUFFER("write: ", count, buf);
374
375 smd_pkt_devp->needed_space = 0;
376
377 r = smd_write_user_buffer(smd_pkt_devp->ch, buf, count);
378 if (r != count) {
379 mutex_unlock(&smd_pkt_devp->tx_lock);
380 if (smd_pkt_devp->has_reset)
381 return notify_reset(smd_pkt_devp);
382
383 printk(KERN_ERR "ERROR:%s:%i:%s: "
384 "smd_write(ch,buf,count = %i) ret %i.\n",
385 __FILE__,
386 __LINE__,
387 __func__,
388 count,
389 r);
390 return r;
391 }
392 mutex_unlock(&smd_pkt_devp->tx_lock);
393
394 D(KERN_ERR "%s: just wrote %i bytes\n",
395 __func__, count);
396
397 return count;
398}
399
400static unsigned int smd_pkt_poll(struct file *file, poll_table *wait)
401{
402 struct smd_pkt_dev *smd_pkt_devp;
403 unsigned int mask = 0;
404
405 smd_pkt_devp = file->private_data;
406 if (!smd_pkt_devp)
407 return POLLERR;
408
409 poll_wait(file, &smd_pkt_devp->ch_read_wait_queue, wait);
410 if (smd_read_avail(smd_pkt_devp->ch))
411 mask |= POLLIN | POLLRDNORM;
412
413 return mask;
414}
415
416static void check_and_wakeup_reader(struct smd_pkt_dev *smd_pkt_devp)
417{
418 int sz;
419
420 if (!smd_pkt_devp || !smd_pkt_devp->ch)
421 return;
422
423 sz = smd_cur_packet_size(smd_pkt_devp->ch);
424 if (sz == 0) {
425 D(KERN_ERR "%s: packet size is 0\n", __func__);
426 return;
427 }
428 if (sz > smd_read_avail(smd_pkt_devp->ch)) {
429 D(KERN_ERR "%s: packet size is %i - "
430 "the whole packet isn't here\n",
431 __func__, sz);
432 return;
433 }
434
435 /* here we have a packet of size sz ready */
436 wake_up_interruptible(&smd_pkt_devp->ch_read_wait_queue);
437 D(KERN_ERR "%s: after wake_up\n", __func__);
438}
439
440static void check_and_wakeup_writer(struct smd_pkt_dev *smd_pkt_devp)
441{
442 int sz;
443
444 if (!smd_pkt_devp || !smd_pkt_devp->ch)
445 return;
446
447 sz = smd_write_avail(smd_pkt_devp->ch);
448 if (sz >= smd_pkt_devp->needed_space) {
449 D(KERN_ERR "%s: %d bytes Write Space available\n",
450 __func__, sz);
451 smd_disable_read_intr(smd_pkt_devp->ch);
452 wake_up_interruptible(&smd_pkt_devp->ch_write_wait_queue);
453 }
454}
455
456static void ch_notify(void *priv, unsigned event)
457{
458 struct smd_pkt_dev *smd_pkt_devp = priv;
459
460 if (smd_pkt_devp->ch == 0)
461 return;
462
463 switch (event) {
464 case SMD_EVENT_DATA: {
465 D(KERN_ERR "%s: data\n", __func__);
466 check_and_wakeup_reader(smd_pkt_devp);
467 if (smd_pkt_devp->blocking_write)
468 check_and_wakeup_writer(smd_pkt_devp);
469 D(KERN_ERR "%s: data after check_and_wakeup\n", __func__);
470 break;
471 }
472 case SMD_EVENT_OPEN:
473 D(KERN_ERR "%s: smd opened\n",
474 __func__);
475
476 smd_pkt_devp->has_reset = 0;
477 smd_pkt_devp->is_open = 1;
478 wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
479 break;
480 case SMD_EVENT_CLOSE:
481 smd_pkt_devp->is_open = 0;
482 printk(KERN_ERR "%s: smd closed\n",
483 __func__);
484
485 /* put port into reset state */
486 clean_and_signal(smd_pkt_devp);
487 if (smd_pkt_devp->i == LOOPBACK_INX)
488 schedule_delayed_work(&loopback_work,
489 msecs_to_jiffies(1000));
490 break;
491 }
492}
493
494#ifdef CONFIG_ARCH_FSM9XXX
495static char *smd_pkt_dev_name[] = {
496 "smdcntl1",
497 "smdcntl2",
498 "smd22",
499 "smd_pkt_loopback",
500};
501
502static char *smd_ch_name[] = {
503 "DATA6_CNTL",
504 "DATA7_CNTL",
505 "DATA22",
506 "LOOPBACK",
507};
508
509static uint32_t smd_ch_edge[] = {
510 SMD_APPS_QDSP,
511 SMD_APPS_QDSP,
512 SMD_APPS_QDSP,
513 SMD_APPS_QDSP
514};
515#else
516static char *smd_pkt_dev_name[] = {
517 "smdcntl0",
518 "smdcntl1",
519 "smdcntl2",
520 "smdcntl3",
521 "smdcntl4",
522 "smdcntl5",
523 "smdcntl6",
524 "smdcntl7",
525 "smd22",
526 "smd_sns_dsps",
Angshuman Sarkara18a2722011-07-29 13:41:13 +0530527 "apr_apps2",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700528 "smd_pkt_loopback",
529};
530
531static char *smd_ch_name[] = {
532 "DATA5_CNTL",
533 "DATA6_CNTL",
534 "DATA7_CNTL",
535 "DATA8_CNTL",
536 "DATA9_CNTL",
537 "DATA12_CNTL",
538 "DATA13_CNTL",
539 "DATA14_CNTL",
540 "DATA22",
541 "SENSOR",
Angshuman Sarkara18a2722011-07-29 13:41:13 +0530542 "apr_apps2",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543 "LOOPBACK",
544};
545
546static uint32_t smd_ch_edge[] = {
547 SMD_APPS_MODEM,
548 SMD_APPS_MODEM,
549 SMD_APPS_MODEM,
550 SMD_APPS_MODEM,
551 SMD_APPS_MODEM,
552 SMD_APPS_MODEM,
553 SMD_APPS_MODEM,
554 SMD_APPS_MODEM,
555 SMD_APPS_MODEM,
556 SMD_APPS_DSPS,
557 SMD_APPS_QDSP,
558 SMD_APPS_MODEM,
559};
560#endif
561
562static int smd_pkt_dummy_probe(struct platform_device *pdev)
563{
564 int i;
565
566 for (i = 0; i < NUM_SMD_PKT_PORTS; i++) {
Jeff Hugoa5ee4362011-07-15 13:48:48 -0600567 if (!strncmp(pdev->name, smd_ch_name[i], SMD_MAX_CH_NAME_LEN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700568 complete_all(&smd_pkt_devp[i]->ch_allocated);
569 break;
570 }
571 }
572 return 0;
573}
574
575static uint32_t is_modem_smsm_inited(void)
576{
577 uint32_t modem_state;
578 uint32_t ready_state = (SMSM_INIT | SMSM_SMDINIT);
579
580 modem_state = smsm_get_state(SMSM_MODEM_STATE);
581 return (modem_state & ready_state) == ready_state;
582}
583
584int smd_pkt_open(struct inode *inode, struct file *file)
585{
586 int r = 0;
587 struct smd_pkt_dev *smd_pkt_devp;
588 char *peripheral = NULL;
589
590 smd_pkt_devp = container_of(inode->i_cdev, struct smd_pkt_dev, cdev);
591
592 if (!smd_pkt_devp)
593 return -EINVAL;
594
595 file->private_data = smd_pkt_devp;
596
597 mutex_lock(&smd_pkt_devp->ch_lock);
598 if (smd_pkt_devp->ch == 0) {
599
600 if (smd_ch_edge[smd_pkt_devp->i] == SMD_APPS_MODEM)
601 peripheral = "modem";
602 else if (smd_ch_edge[smd_pkt_devp->i] == SMD_APPS_QDSP)
603 peripheral = "q6";
604
605 if (peripheral) {
606 smd_pkt_devp->pil = pil_get(peripheral);
607 if (IS_ERR(smd_pkt_devp->pil)) {
608 r = PTR_ERR(smd_pkt_devp->pil);
609 goto out;
610 }
611
612 /* Wait for the modem SMSM to be inited for the SMD
613 ** Loopback channel to be allocated at the modem. Since
614 ** the wait need to be done atmost once, using msleep
615 ** doesn't degrade the performance. */
Jeff Hugoa5ee4362011-07-15 13:48:48 -0600616 if (!strncmp(smd_ch_name[smd_pkt_devp->i], "LOOPBACK",
617 SMD_MAX_CH_NAME_LEN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700618 if (!is_modem_smsm_inited())
619 msleep(5000);
620 smsm_change_state(SMSM_APPS_STATE,
621 0, SMSM_SMD_LOOPBACK);
622 msleep(100);
623 }
624
625 /*
626 * Wait for a packet channel to be allocated so we know
627 * the modem is ready enough.
628 */
629 if (smd_pkt_devp->open_modem_wait) {
630 r = wait_for_completion_interruptible_timeout(
631 &smd_pkt_devp->ch_allocated,
632 msecs_to_jiffies(
633 smd_pkt_devp->open_modem_wait
634 * 1000));
635 if (r == 0)
636 r = -ETIMEDOUT;
637 if (r < 0) {
638 pr_err("%s: wait failed for smd port:"
639 " %d\n", __func__, r);
640 goto release_pil;
641 }
642 }
643 }
644
645 r = smd_named_open_on_edge(smd_ch_name[smd_pkt_devp->i],
646 smd_ch_edge[smd_pkt_devp->i],
647 &smd_pkt_devp->ch,
648 smd_pkt_devp,
649 ch_notify);
650 if (r < 0) {
651 pr_err("%s: %s open failed %d\n", __func__,
652 smd_ch_name[smd_pkt_devp->i], r);
653 goto release_pil;
654 }
655
656 r = wait_event_interruptible_timeout(
657 smd_pkt_devp->ch_opened_wait_queue,
658 smd_pkt_devp->is_open, (2 * HZ));
659 if (r == 0)
660 r = -ETIMEDOUT;
661
662 if (r < 0) {
663 pr_err("%s: wait failed for smd open: %d\n",
664 __func__, r);
665 } else if (!smd_pkt_devp->is_open) {
666 pr_err("%s: Invalid open notification\n", __func__);
667 r = -ENODEV;
668 } else {
669 smd_disable_read_intr(smd_pkt_devp->ch);
670 smd_pkt_devp->ch_size =
671 smd_write_avail(smd_pkt_devp->ch);
672 r = 0;
673 }
674 }
675release_pil:
676 if (peripheral && (r < 0))
677 pil_put(smd_pkt_devp->pil);
678out:
679 mutex_unlock(&smd_pkt_devp->ch_lock);
680
681 return r;
682}
683
684int smd_pkt_release(struct inode *inode, struct file *file)
685{
686 int r = 0;
687 struct smd_pkt_dev *smd_pkt_devp = file->private_data;
688
689 if (!smd_pkt_devp)
690 return -EINVAL;
691
692 clean_and_signal(smd_pkt_devp);
693
694 mutex_lock(&smd_pkt_devp->ch_lock);
695 if (smd_pkt_devp->ch != 0) {
696 r = smd_close(smd_pkt_devp->ch);
697 smd_pkt_devp->ch = 0;
698 smd_pkt_devp->blocking_write = 0;
699 if (smd_pkt_devp->pil)
700 pil_put(smd_pkt_devp->pil);
701 }
702 mutex_unlock(&smd_pkt_devp->ch_lock);
703
704 smd_pkt_devp->has_reset = 0;
705 smd_pkt_devp->do_reset_notification = 0;
706
707 return r;
708}
709
710static const struct file_operations smd_pkt_fops = {
711 .owner = THIS_MODULE,
712 .open = smd_pkt_open,
713 .release = smd_pkt_release,
714 .read = smd_pkt_read,
715 .write = smd_pkt_write,
716 .poll = smd_pkt_poll,
717 .unlocked_ioctl = smd_pkt_ioctl,
718};
719
720static int __init smd_pkt_init(void)
721{
722 int i;
723 int r;
724
725 r = alloc_chrdev_region(&smd_pkt_number,
726 0,
727 NUM_SMD_PKT_PORTS,
728 DEVICE_NAME);
729 if (IS_ERR_VALUE(r)) {
730 printk(KERN_ERR "ERROR:%s:%i:%s: "
731 "alloc_chrdev_region() ret %i.\n",
732 __FILE__,
733 __LINE__,
734 __func__,
735 r);
736 goto error0;
737 }
738
739 smd_pkt_classp = class_create(THIS_MODULE, DEVICE_NAME);
740 if (IS_ERR(smd_pkt_classp)) {
741 printk(KERN_ERR "ERROR:%s:%i:%s: "
742 "class_create() ENOMEM\n",
743 __FILE__,
744 __LINE__,
745 __func__);
746 r = -ENOMEM;
747 goto error1;
748 }
749
750 for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
751 smd_pkt_devp[i] = kzalloc(sizeof(struct smd_pkt_dev),
752 GFP_KERNEL);
753 if (IS_ERR(smd_pkt_devp[i])) {
754 printk(KERN_ERR "ERROR:%s:%i:%s kmalloc() ENOMEM\n",
755 __FILE__,
756 __LINE__,
757 __func__);
758 r = -ENOMEM;
759 goto error2;
760 }
761
762 smd_pkt_devp[i]->i = i;
763
764 init_waitqueue_head(&smd_pkt_devp[i]->ch_read_wait_queue);
765 init_waitqueue_head(&smd_pkt_devp[i]->ch_write_wait_queue);
766 smd_pkt_devp[i]->is_open = 0;
767 init_waitqueue_head(&smd_pkt_devp[i]->ch_opened_wait_queue);
768
769 mutex_init(&smd_pkt_devp[i]->ch_lock);
770 mutex_init(&smd_pkt_devp[i]->rx_lock);
771 mutex_init(&smd_pkt_devp[i]->tx_lock);
772 init_completion(&smd_pkt_devp[i]->ch_allocated);
773
774 cdev_init(&smd_pkt_devp[i]->cdev, &smd_pkt_fops);
775 smd_pkt_devp[i]->cdev.owner = THIS_MODULE;
776
777 r = cdev_add(&smd_pkt_devp[i]->cdev,
778 (smd_pkt_number + i),
779 1);
780
781 if (IS_ERR_VALUE(r)) {
782 printk(KERN_ERR "%s:%i:%s: cdev_add() ret %i\n",
783 __FILE__,
784 __LINE__,
785 __func__,
786 r);
787 kfree(smd_pkt_devp[i]);
788 goto error2;
789 }
790
791 smd_pkt_devp[i]->devicep =
792 device_create(smd_pkt_classp,
793 NULL,
794 (smd_pkt_number + i),
795 NULL,
796 smd_pkt_dev_name[i]);
797
798 if (IS_ERR(smd_pkt_devp[i]->devicep)) {
799 printk(KERN_ERR "%s:%i:%s: "
800 "device_create() ENOMEM\n",
801 __FILE__,
802 __LINE__,
803 __func__);
804 r = -ENOMEM;
805 cdev_del(&smd_pkt_devp[i]->cdev);
806 kfree(smd_pkt_devp[i]);
807 goto error2;
808 }
809 if (device_create_file(smd_pkt_devp[i]->devicep,
810 &dev_attr_open_timeout))
811 pr_err("%s: unable to create device attr on #%d\n",
812 __func__, i);
813
814 smd_pkt_devp[i]->driver.probe = smd_pkt_dummy_probe;
815 smd_pkt_devp[i]->driver.driver.name = smd_ch_name[i];
816 smd_pkt_devp[i]->driver.driver.owner = THIS_MODULE;
817 r = platform_driver_register(&smd_pkt_devp[i]->driver);
818 if (r)
819 goto error2;
820 }
821
822 INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
823
824 D(KERN_INFO "SMD Packet Port Driver Initialized.\n");
825 return 0;
826
827 error2:
828 if (i > 0) {
829 while (--i >= 0) {
830 platform_driver_unregister(&smd_pkt_devp[i]->driver);
831 cdev_del(&smd_pkt_devp[i]->cdev);
832 kfree(smd_pkt_devp[i]);
833 device_destroy(smd_pkt_classp,
834 MKDEV(MAJOR(smd_pkt_number), i));
835 }
836 }
837
838 class_destroy(smd_pkt_classp);
839 error1:
840 unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS);
841 error0:
842 return r;
843}
844
845static void __exit smd_pkt_cleanup(void)
846{
847 int i;
848
849 for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
850 platform_driver_unregister(&smd_pkt_devp[i]->driver);
851 cdev_del(&smd_pkt_devp[i]->cdev);
852 kfree(smd_pkt_devp[i]);
853 device_destroy(smd_pkt_classp,
854 MKDEV(MAJOR(smd_pkt_number), i));
855 }
856
857 class_destroy(smd_pkt_classp);
858
859 unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS);
860}
861
862module_init(smd_pkt_init);
863module_exit(smd_pkt_cleanup);
864
865MODULE_DESCRIPTION("MSM Shared Memory Packet Port");
866MODULE_LICENSE("GPL v2");