blob: 7c7a82238ce5a6eb6e89e3763af13c1acc07fdb0 [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
Karthikeyan Ramasubramanian703e8a12011-11-08 16:50:06 -0700157 wake_up(&smd_pkt_devp->ch_read_wait_queue);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700158 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;
Karthikeyan Ramasubramanian703e8a12011-11-08 16:50:06 -0700211 int pkt_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700212 struct smd_pkt_dev *smd_pkt_devp;
213 struct smd_channel *chl;
214
215 D(KERN_ERR "%s: read %i bytes\n",
216 __func__, count);
217
218 smd_pkt_devp = file->private_data;
219
220 if (!smd_pkt_devp || !smd_pkt_devp->ch)
221 return -EINVAL;
222
223 if (smd_pkt_devp->do_reset_notification) {
224 /* notify client that a reset occurred */
225 return notify_reset(smd_pkt_devp);
226 }
227
228 chl = smd_pkt_devp->ch;
229wait_for_packet:
230 r = wait_event_interruptible(smd_pkt_devp->ch_read_wait_queue,
231 (smd_cur_packet_size(chl) > 0 &&
Karthikeyan Ramasubramanian703e8a12011-11-08 16:50:06 -0700232 smd_read_avail(chl)) ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700233 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);
Karthikeyan Ramasubramanian703e8a12011-11-08 16:50:06 -0700256 pkt_size = smd_cur_packet_size(smd_pkt_devp->ch);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700257
Karthikeyan Ramasubramanian703e8a12011-11-08 16:50:06 -0700258 if (!pkt_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 D(KERN_ERR "%s: Nothing to read\n", __func__);
260 mutex_unlock(&smd_pkt_devp->rx_lock);
261 goto wait_for_packet;
262 }
263
Karthikeyan Ramasubramanian703e8a12011-11-08 16:50:06 -0700264 if (pkt_size > count) {
265 pr_err("packet size %i > buffer size %i,", pkt_size, count);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266 mutex_unlock(&smd_pkt_devp->rx_lock);
Karthikeyan Ramasubramanian703e8a12011-11-08 16:50:06 -0700267 return -ETOOSMALL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 }
269
Karthikeyan Ramasubramanian703e8a12011-11-08 16:50:06 -0700270 bytes_read = 0;
271 do {
272 r = smd_read_user_buffer(smd_pkt_devp->ch,
273 (buf + bytes_read),
274 (pkt_size - bytes_read));
275 if (r < 0) {
276 mutex_unlock(&smd_pkt_devp->rx_lock);
277 if (smd_pkt_devp->has_reset)
278 return notify_reset(smd_pkt_devp);
279 return r;
280 }
281 bytes_read += r;
282 if (pkt_size != bytes_read)
283 wait_event(smd_pkt_devp->ch_read_wait_queue,
284 smd_read_avail(smd_pkt_devp->ch) ||
285 smd_pkt_devp->has_reset);
286 if (smd_pkt_devp->has_reset) {
287 mutex_unlock(&smd_pkt_devp->rx_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288 return notify_reset(smd_pkt_devp);
Karthikeyan Ramasubramanian703e8a12011-11-08 16:50:06 -0700289 }
290 } while (pkt_size != bytes_read);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291 D_DUMP_BUFFER("read: ", bytes_read, buf);
292 mutex_unlock(&smd_pkt_devp->rx_lock);
293
294 D(KERN_ERR "%s: just read %i bytes\n",
295 __func__, bytes_read);
296
297 /* check and wakeup read threads waiting on this device */
298 check_and_wakeup_reader(smd_pkt_devp);
299
300 return bytes_read;
301}
302
303ssize_t smd_pkt_write(struct file *file,
304 const char __user *buf,
305 size_t count,
306 loff_t *ppos)
307{
308 int r = 0;
309 struct smd_pkt_dev *smd_pkt_devp;
310 DEFINE_WAIT(write_wait);
311
312 D(KERN_ERR "%s: writting %i bytes\n",
313 __func__, count);
314
315 smd_pkt_devp = file->private_data;
316
317 if (!smd_pkt_devp || !smd_pkt_devp->ch)
318 return -EINVAL;
319
320 if (count > smd_pkt_devp->ch_size)
321 return -EINVAL;
322
323 if (smd_pkt_devp->do_reset_notification) {
324 /* notify client that a reset occurred */
325 return notify_reset(smd_pkt_devp);
326 }
327
328 if (smd_pkt_devp->blocking_write) {
329 for (;;) {
330 mutex_lock(&smd_pkt_devp->tx_lock);
331 if (smd_pkt_devp->has_reset) {
332 smd_disable_read_intr(smd_pkt_devp->ch);
333 mutex_unlock(&smd_pkt_devp->tx_lock);
334 return notify_reset(smd_pkt_devp);
335 }
336 if (signal_pending(current)) {
337 smd_disable_read_intr(smd_pkt_devp->ch);
338 mutex_unlock(&smd_pkt_devp->tx_lock);
339 return -ERESTARTSYS;
340 }
341
342 prepare_to_wait(&smd_pkt_devp->ch_write_wait_queue,
343 &write_wait, TASK_INTERRUPTIBLE);
344 smd_enable_read_intr(smd_pkt_devp->ch);
345 if (smd_write_avail(smd_pkt_devp->ch) < count) {
346 if (!smd_pkt_devp->needed_space ||
347 count < smd_pkt_devp->needed_space)
348 smd_pkt_devp->needed_space = count;
349 mutex_unlock(&smd_pkt_devp->tx_lock);
350 schedule();
351 } else
352 break;
353 }
354 finish_wait(&smd_pkt_devp->ch_write_wait_queue, &write_wait);
355 smd_disable_read_intr(smd_pkt_devp->ch);
356 if (smd_pkt_devp->has_reset) {
357 mutex_unlock(&smd_pkt_devp->tx_lock);
358 return notify_reset(smd_pkt_devp);
359 }
360 if (signal_pending(current)) {
361 mutex_unlock(&smd_pkt_devp->tx_lock);
362 return -ERESTARTSYS;
363 }
364 } else {
365 if (smd_pkt_devp->has_reset)
366 return notify_reset(smd_pkt_devp);
367 if (signal_pending(current))
368 return -ERESTARTSYS;
369
370 mutex_lock(&smd_pkt_devp->tx_lock);
371 if (smd_write_avail(smd_pkt_devp->ch) < count) {
372 D(KERN_ERR "%s: Not enough space to write\n",
373 __func__);
374 mutex_unlock(&smd_pkt_devp->tx_lock);
375 return -ENOMEM;
376 }
377 }
378
379 D_DUMP_BUFFER("write: ", count, buf);
380
381 smd_pkt_devp->needed_space = 0;
382
383 r = smd_write_user_buffer(smd_pkt_devp->ch, buf, count);
384 if (r != count) {
385 mutex_unlock(&smd_pkt_devp->tx_lock);
386 if (smd_pkt_devp->has_reset)
387 return notify_reset(smd_pkt_devp);
388
389 printk(KERN_ERR "ERROR:%s:%i:%s: "
390 "smd_write(ch,buf,count = %i) ret %i.\n",
391 __FILE__,
392 __LINE__,
393 __func__,
394 count,
395 r);
396 return r;
397 }
398 mutex_unlock(&smd_pkt_devp->tx_lock);
399
400 D(KERN_ERR "%s: just wrote %i bytes\n",
401 __func__, count);
402
403 return count;
404}
405
406static unsigned int smd_pkt_poll(struct file *file, poll_table *wait)
407{
408 struct smd_pkt_dev *smd_pkt_devp;
409 unsigned int mask = 0;
410
411 smd_pkt_devp = file->private_data;
412 if (!smd_pkt_devp)
413 return POLLERR;
414
415 poll_wait(file, &smd_pkt_devp->ch_read_wait_queue, wait);
416 if (smd_read_avail(smd_pkt_devp->ch))
417 mask |= POLLIN | POLLRDNORM;
418
419 return mask;
420}
421
422static void check_and_wakeup_reader(struct smd_pkt_dev *smd_pkt_devp)
423{
424 int sz;
425
426 if (!smd_pkt_devp || !smd_pkt_devp->ch)
427 return;
428
429 sz = smd_cur_packet_size(smd_pkt_devp->ch);
430 if (sz == 0) {
431 D(KERN_ERR "%s: packet size is 0\n", __func__);
432 return;
433 }
Karthikeyan Ramasubramanian703e8a12011-11-08 16:50:06 -0700434 if (!smd_read_avail(smd_pkt_devp->ch)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435 D(KERN_ERR "%s: packet size is %i - "
Karthikeyan Ramasubramanian703e8a12011-11-08 16:50:06 -0700436 "but the data isn't here\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437 __func__, sz);
438 return;
439 }
440
441 /* here we have a packet of size sz ready */
Karthikeyan Ramasubramanian703e8a12011-11-08 16:50:06 -0700442 wake_up(&smd_pkt_devp->ch_read_wait_queue);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443 D(KERN_ERR "%s: after wake_up\n", __func__);
444}
445
446static void check_and_wakeup_writer(struct smd_pkt_dev *smd_pkt_devp)
447{
448 int sz;
449
450 if (!smd_pkt_devp || !smd_pkt_devp->ch)
451 return;
452
453 sz = smd_write_avail(smd_pkt_devp->ch);
454 if (sz >= smd_pkt_devp->needed_space) {
455 D(KERN_ERR "%s: %d bytes Write Space available\n",
456 __func__, sz);
457 smd_disable_read_intr(smd_pkt_devp->ch);
458 wake_up_interruptible(&smd_pkt_devp->ch_write_wait_queue);
459 }
460}
461
462static void ch_notify(void *priv, unsigned event)
463{
464 struct smd_pkt_dev *smd_pkt_devp = priv;
465
466 if (smd_pkt_devp->ch == 0)
467 return;
468
469 switch (event) {
470 case SMD_EVENT_DATA: {
471 D(KERN_ERR "%s: data\n", __func__);
472 check_and_wakeup_reader(smd_pkt_devp);
473 if (smd_pkt_devp->blocking_write)
474 check_and_wakeup_writer(smd_pkt_devp);
475 D(KERN_ERR "%s: data after check_and_wakeup\n", __func__);
476 break;
477 }
478 case SMD_EVENT_OPEN:
479 D(KERN_ERR "%s: smd opened\n",
480 __func__);
481
482 smd_pkt_devp->has_reset = 0;
483 smd_pkt_devp->is_open = 1;
484 wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
485 break;
486 case SMD_EVENT_CLOSE:
487 smd_pkt_devp->is_open = 0;
488 printk(KERN_ERR "%s: smd closed\n",
489 __func__);
490
491 /* put port into reset state */
492 clean_and_signal(smd_pkt_devp);
493 if (smd_pkt_devp->i == LOOPBACK_INX)
494 schedule_delayed_work(&loopback_work,
495 msecs_to_jiffies(1000));
496 break;
497 }
498}
499
500#ifdef CONFIG_ARCH_FSM9XXX
501static char *smd_pkt_dev_name[] = {
502 "smdcntl1",
503 "smdcntl2",
504 "smd22",
505 "smd_pkt_loopback",
506};
507
508static char *smd_ch_name[] = {
509 "DATA6_CNTL",
510 "DATA7_CNTL",
511 "DATA22",
512 "LOOPBACK",
513};
514
515static uint32_t smd_ch_edge[] = {
516 SMD_APPS_QDSP,
517 SMD_APPS_QDSP,
518 SMD_APPS_QDSP,
519 SMD_APPS_QDSP
520};
521#else
522static char *smd_pkt_dev_name[] = {
523 "smdcntl0",
524 "smdcntl1",
525 "smdcntl2",
526 "smdcntl3",
527 "smdcntl4",
528 "smdcntl5",
529 "smdcntl6",
530 "smdcntl7",
531 "smd22",
532 "smd_sns_dsps",
Angshuman Sarkara18a2722011-07-29 13:41:13 +0530533 "apr_apps2",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534 "smd_pkt_loopback",
535};
536
537static char *smd_ch_name[] = {
538 "DATA5_CNTL",
539 "DATA6_CNTL",
540 "DATA7_CNTL",
541 "DATA8_CNTL",
542 "DATA9_CNTL",
543 "DATA12_CNTL",
544 "DATA13_CNTL",
545 "DATA14_CNTL",
546 "DATA22",
547 "SENSOR",
Angshuman Sarkara18a2722011-07-29 13:41:13 +0530548 "apr_apps2",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700549 "LOOPBACK",
550};
551
552static uint32_t smd_ch_edge[] = {
553 SMD_APPS_MODEM,
554 SMD_APPS_MODEM,
555 SMD_APPS_MODEM,
556 SMD_APPS_MODEM,
557 SMD_APPS_MODEM,
558 SMD_APPS_MODEM,
559 SMD_APPS_MODEM,
560 SMD_APPS_MODEM,
561 SMD_APPS_MODEM,
562 SMD_APPS_DSPS,
563 SMD_APPS_QDSP,
564 SMD_APPS_MODEM,
565};
566#endif
567
568static int smd_pkt_dummy_probe(struct platform_device *pdev)
569{
570 int i;
571
572 for (i = 0; i < NUM_SMD_PKT_PORTS; i++) {
Jeff Hugoa5ee4362011-07-15 13:48:48 -0600573 if (!strncmp(pdev->name, smd_ch_name[i], SMD_MAX_CH_NAME_LEN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574 complete_all(&smd_pkt_devp[i]->ch_allocated);
575 break;
576 }
577 }
578 return 0;
579}
580
581static uint32_t is_modem_smsm_inited(void)
582{
583 uint32_t modem_state;
584 uint32_t ready_state = (SMSM_INIT | SMSM_SMDINIT);
585
586 modem_state = smsm_get_state(SMSM_MODEM_STATE);
587 return (modem_state & ready_state) == ready_state;
588}
589
590int smd_pkt_open(struct inode *inode, struct file *file)
591{
592 int r = 0;
593 struct smd_pkt_dev *smd_pkt_devp;
594 char *peripheral = NULL;
595
596 smd_pkt_devp = container_of(inode->i_cdev, struct smd_pkt_dev, cdev);
597
598 if (!smd_pkt_devp)
599 return -EINVAL;
600
601 file->private_data = smd_pkt_devp;
602
603 mutex_lock(&smd_pkt_devp->ch_lock);
604 if (smd_pkt_devp->ch == 0) {
605
606 if (smd_ch_edge[smd_pkt_devp->i] == SMD_APPS_MODEM)
607 peripheral = "modem";
608 else if (smd_ch_edge[smd_pkt_devp->i] == SMD_APPS_QDSP)
609 peripheral = "q6";
610
611 if (peripheral) {
612 smd_pkt_devp->pil = pil_get(peripheral);
613 if (IS_ERR(smd_pkt_devp->pil)) {
614 r = PTR_ERR(smd_pkt_devp->pil);
615 goto out;
616 }
617
618 /* Wait for the modem SMSM to be inited for the SMD
619 ** Loopback channel to be allocated at the modem. Since
620 ** the wait need to be done atmost once, using msleep
621 ** doesn't degrade the performance. */
Jeff Hugoa5ee4362011-07-15 13:48:48 -0600622 if (!strncmp(smd_ch_name[smd_pkt_devp->i], "LOOPBACK",
623 SMD_MAX_CH_NAME_LEN)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700624 if (!is_modem_smsm_inited())
625 msleep(5000);
626 smsm_change_state(SMSM_APPS_STATE,
627 0, SMSM_SMD_LOOPBACK);
628 msleep(100);
629 }
630
631 /*
632 * Wait for a packet channel to be allocated so we know
633 * the modem is ready enough.
634 */
635 if (smd_pkt_devp->open_modem_wait) {
636 r = wait_for_completion_interruptible_timeout(
637 &smd_pkt_devp->ch_allocated,
638 msecs_to_jiffies(
639 smd_pkt_devp->open_modem_wait
640 * 1000));
641 if (r == 0)
642 r = -ETIMEDOUT;
643 if (r < 0) {
644 pr_err("%s: wait failed for smd port:"
645 " %d\n", __func__, r);
646 goto release_pil;
647 }
648 }
649 }
650
651 r = smd_named_open_on_edge(smd_ch_name[smd_pkt_devp->i],
652 smd_ch_edge[smd_pkt_devp->i],
653 &smd_pkt_devp->ch,
654 smd_pkt_devp,
655 ch_notify);
656 if (r < 0) {
657 pr_err("%s: %s open failed %d\n", __func__,
658 smd_ch_name[smd_pkt_devp->i], r);
659 goto release_pil;
660 }
661
662 r = wait_event_interruptible_timeout(
663 smd_pkt_devp->ch_opened_wait_queue,
664 smd_pkt_devp->is_open, (2 * HZ));
665 if (r == 0)
666 r = -ETIMEDOUT;
667
668 if (r < 0) {
669 pr_err("%s: wait failed for smd open: %d\n",
670 __func__, r);
671 } else if (!smd_pkt_devp->is_open) {
672 pr_err("%s: Invalid open notification\n", __func__);
673 r = -ENODEV;
674 } else {
675 smd_disable_read_intr(smd_pkt_devp->ch);
676 smd_pkt_devp->ch_size =
677 smd_write_avail(smd_pkt_devp->ch);
678 r = 0;
679 }
680 }
681release_pil:
682 if (peripheral && (r < 0))
683 pil_put(smd_pkt_devp->pil);
684out:
685 mutex_unlock(&smd_pkt_devp->ch_lock);
686
687 return r;
688}
689
690int smd_pkt_release(struct inode *inode, struct file *file)
691{
692 int r = 0;
693 struct smd_pkt_dev *smd_pkt_devp = file->private_data;
694
695 if (!smd_pkt_devp)
696 return -EINVAL;
697
698 clean_and_signal(smd_pkt_devp);
699
700 mutex_lock(&smd_pkt_devp->ch_lock);
701 if (smd_pkt_devp->ch != 0) {
702 r = smd_close(smd_pkt_devp->ch);
703 smd_pkt_devp->ch = 0;
704 smd_pkt_devp->blocking_write = 0;
705 if (smd_pkt_devp->pil)
706 pil_put(smd_pkt_devp->pil);
707 }
708 mutex_unlock(&smd_pkt_devp->ch_lock);
709
710 smd_pkt_devp->has_reset = 0;
711 smd_pkt_devp->do_reset_notification = 0;
712
713 return r;
714}
715
716static const struct file_operations smd_pkt_fops = {
717 .owner = THIS_MODULE,
718 .open = smd_pkt_open,
719 .release = smd_pkt_release,
720 .read = smd_pkt_read,
721 .write = smd_pkt_write,
722 .poll = smd_pkt_poll,
723 .unlocked_ioctl = smd_pkt_ioctl,
724};
725
726static int __init smd_pkt_init(void)
727{
728 int i;
729 int r;
730
731 r = alloc_chrdev_region(&smd_pkt_number,
732 0,
733 NUM_SMD_PKT_PORTS,
734 DEVICE_NAME);
735 if (IS_ERR_VALUE(r)) {
736 printk(KERN_ERR "ERROR:%s:%i:%s: "
737 "alloc_chrdev_region() ret %i.\n",
738 __FILE__,
739 __LINE__,
740 __func__,
741 r);
742 goto error0;
743 }
744
745 smd_pkt_classp = class_create(THIS_MODULE, DEVICE_NAME);
746 if (IS_ERR(smd_pkt_classp)) {
747 printk(KERN_ERR "ERROR:%s:%i:%s: "
748 "class_create() ENOMEM\n",
749 __FILE__,
750 __LINE__,
751 __func__);
752 r = -ENOMEM;
753 goto error1;
754 }
755
756 for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
757 smd_pkt_devp[i] = kzalloc(sizeof(struct smd_pkt_dev),
758 GFP_KERNEL);
759 if (IS_ERR(smd_pkt_devp[i])) {
760 printk(KERN_ERR "ERROR:%s:%i:%s kmalloc() ENOMEM\n",
761 __FILE__,
762 __LINE__,
763 __func__);
764 r = -ENOMEM;
765 goto error2;
766 }
767
768 smd_pkt_devp[i]->i = i;
769
770 init_waitqueue_head(&smd_pkt_devp[i]->ch_read_wait_queue);
771 init_waitqueue_head(&smd_pkt_devp[i]->ch_write_wait_queue);
772 smd_pkt_devp[i]->is_open = 0;
773 init_waitqueue_head(&smd_pkt_devp[i]->ch_opened_wait_queue);
774
775 mutex_init(&smd_pkt_devp[i]->ch_lock);
776 mutex_init(&smd_pkt_devp[i]->rx_lock);
777 mutex_init(&smd_pkt_devp[i]->tx_lock);
778 init_completion(&smd_pkt_devp[i]->ch_allocated);
779
780 cdev_init(&smd_pkt_devp[i]->cdev, &smd_pkt_fops);
781 smd_pkt_devp[i]->cdev.owner = THIS_MODULE;
782
783 r = cdev_add(&smd_pkt_devp[i]->cdev,
784 (smd_pkt_number + i),
785 1);
786
787 if (IS_ERR_VALUE(r)) {
788 printk(KERN_ERR "%s:%i:%s: cdev_add() ret %i\n",
789 __FILE__,
790 __LINE__,
791 __func__,
792 r);
793 kfree(smd_pkt_devp[i]);
794 goto error2;
795 }
796
797 smd_pkt_devp[i]->devicep =
798 device_create(smd_pkt_classp,
799 NULL,
800 (smd_pkt_number + i),
801 NULL,
802 smd_pkt_dev_name[i]);
803
804 if (IS_ERR(smd_pkt_devp[i]->devicep)) {
805 printk(KERN_ERR "%s:%i:%s: "
806 "device_create() ENOMEM\n",
807 __FILE__,
808 __LINE__,
809 __func__);
810 r = -ENOMEM;
811 cdev_del(&smd_pkt_devp[i]->cdev);
812 kfree(smd_pkt_devp[i]);
813 goto error2;
814 }
815 if (device_create_file(smd_pkt_devp[i]->devicep,
816 &dev_attr_open_timeout))
817 pr_err("%s: unable to create device attr on #%d\n",
818 __func__, i);
819
820 smd_pkt_devp[i]->driver.probe = smd_pkt_dummy_probe;
821 smd_pkt_devp[i]->driver.driver.name = smd_ch_name[i];
822 smd_pkt_devp[i]->driver.driver.owner = THIS_MODULE;
823 r = platform_driver_register(&smd_pkt_devp[i]->driver);
824 if (r)
825 goto error2;
826 }
827
828 INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
829
830 D(KERN_INFO "SMD Packet Port Driver Initialized.\n");
831 return 0;
832
833 error2:
834 if (i > 0) {
835 while (--i >= 0) {
836 platform_driver_unregister(&smd_pkt_devp[i]->driver);
837 cdev_del(&smd_pkt_devp[i]->cdev);
838 kfree(smd_pkt_devp[i]);
839 device_destroy(smd_pkt_classp,
840 MKDEV(MAJOR(smd_pkt_number), i));
841 }
842 }
843
844 class_destroy(smd_pkt_classp);
845 error1:
846 unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS);
847 error0:
848 return r;
849}
850
851static void __exit smd_pkt_cleanup(void)
852{
853 int i;
854
855 for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
856 platform_driver_unregister(&smd_pkt_devp[i]->driver);
857 cdev_del(&smd_pkt_devp[i]->cdev);
858 kfree(smd_pkt_devp[i]);
859 device_destroy(smd_pkt_classp,
860 MKDEV(MAJOR(smd_pkt_number), i));
861 }
862
863 class_destroy(smd_pkt_classp);
864
865 unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS);
866}
867
868module_init(smd_pkt_init);
869module_exit(smd_pkt_cleanup);
870
871MODULE_DESCRIPTION("MSM Shared Memory Packet Port");
872MODULE_LICENSE("GPL v2");