aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging
diff options
context:
space:
mode:
authorDaniel Walker <dwalker@codeaurora.org>2010-05-11 18:56:44 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-05-14 16:21:30 -0400
commitbf597e99d2fd4c5d25485fd4e4877bbae2be816c (patch)
treeda7ae43a21dd8f0dc1d2904ccfc7e8370d148201 /drivers/staging
parente64354c0be3b7134c85571a525b2e37fc4a95eef (diff)
staging: dream: smd: remove all smd related code
Part of this code is already in my MSM tree. I'll move the rest forward through my tree also. Signed-off-by: Daniel Walker <dwalker@codeaurora.org> CC: Pavel Machek <pavel@ucw.cz> CC: linux-arm-msm@vger.kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/dream/Kconfig1
-rw-r--r--drivers/staging/dream/Makefile2
-rw-r--r--drivers/staging/dream/smd/Kconfig26
-rw-r--r--drivers/staging/dream/smd/Makefile7
-rw-r--r--drivers/staging/dream/smd/rpc_server_dog_keepalive.c68
-rw-r--r--drivers/staging/dream/smd/rpc_server_time_remote.c77
-rw-r--r--drivers/staging/dream/smd/smd.c1330
-rw-r--r--drivers/staging/dream/smd/smd_private.h164
-rw-r--r--drivers/staging/dream/smd/smd_qmi.c851
-rw-r--r--drivers/staging/dream/smd/smd_rpcrouter.c1261
-rw-r--r--drivers/staging/dream/smd/smd_rpcrouter.h193
-rw-r--r--drivers/staging/dream/smd/smd_rpcrouter_device.c377
-rw-r--r--drivers/staging/dream/smd/smd_rpcrouter_servers.c226
-rw-r--r--drivers/staging/dream/smd/smd_tty.c208
14 files changed, 1 insertions, 4790 deletions
diff --git a/drivers/staging/dream/Kconfig b/drivers/staging/dream/Kconfig
index 707cc71a8a6a..0c30b19a5a7c 100644
--- a/drivers/staging/dream/Kconfig
+++ b/drivers/staging/dream/Kconfig
@@ -3,7 +3,6 @@ config DREAM
3 depends on MACH_TROUT 3 depends on MACH_TROUT
4 4
5if DREAM 5if DREAM
6source "drivers/staging/dream/smd/Kconfig"
7 6
8source "drivers/staging/dream/camera/Kconfig" 7source "drivers/staging/dream/camera/Kconfig"
9 8
diff --git a/drivers/staging/dream/Makefile b/drivers/staging/dream/Makefile
index 43d1eec8e257..fbea0abcc864 100644
--- a/drivers/staging/dream/Makefile
+++ b/drivers/staging/dream/Makefile
@@ -1,5 +1,5 @@
1EXTRA_CFLAGS=-Idrivers/staging/dream/include 1EXTRA_CFLAGS=-Idrivers/staging/dream/include
2obj-$(CONFIG_MSM_ADSP) += qdsp5/ smd/ 2obj-$(CONFIG_MSM_ADSP) += qdsp5/
3obj-$(CONFIG_MSM_CAMERA) += camera/ 3obj-$(CONFIG_MSM_CAMERA) += camera/
4obj-$(CONFIG_INPUT_GPIO) += gpio_axis.o gpio_event.o gpio_input.o gpio_matrix.o gpio_output.o 4obj-$(CONFIG_INPUT_GPIO) += gpio_axis.o gpio_event.o gpio_input.o gpio_matrix.o gpio_output.o
5 5
diff --git a/drivers/staging/dream/smd/Kconfig b/drivers/staging/dream/smd/Kconfig
deleted file mode 100644
index 17b8bdc7b9b7..000000000000
--- a/drivers/staging/dream/smd/Kconfig
+++ /dev/null
@@ -1,26 +0,0 @@
1config MSM_SMD
2 depends on ARCH_MSM
3 default y
4 bool "MSM Shared Memory Driver (SMD)"
5 help
6 Support for the shared memory interface between the apps
7 processor and the baseband processor. Provides access to
8 the "shared heap", as well as virtual serial channels
9 used to communicate with various services on the baseband
10 processor.
11
12config MSM_ONCRPCROUTER
13 depends on MSM_SMD
14 default y
15 bool "MSM ONCRPC router support"
16 help
17 Support for the MSM ONCRPC router for communication between
18 the ARM9 and ARM11
19
20config MSM_RPCSERVERS
21 depends on MSM_ONCRPCROUTER
22 default y
23 bool "Kernel side RPC server bundle"
24 help
25 none
26
diff --git a/drivers/staging/dream/smd/Makefile b/drivers/staging/dream/smd/Makefile
deleted file mode 100644
index 1c87618366a7..000000000000
--- a/drivers/staging/dream/smd/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
1EXTRA_CFLAGS=-Idrivers/staging/dream/include
2obj-$(CONFIG_MSM_SMD) += smd.o smd_tty.o smd_qmi.o
3obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter.o
4obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_device.o
5obj-$(CONFIG_MSM_ONCRPCROUTER) += smd_rpcrouter_servers.o
6obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_dog_keepalive.o
7obj-$(CONFIG_MSM_RPCSERVERS) += rpc_server_time_remote.o
diff --git a/drivers/staging/dream/smd/rpc_server_dog_keepalive.c b/drivers/staging/dream/smd/rpc_server_dog_keepalive.c
deleted file mode 100644
index b23fccfa87e2..000000000000
--- a/drivers/staging/dream/smd/rpc_server_dog_keepalive.c
+++ /dev/null
@@ -1,68 +0,0 @@
1/* arch/arm/mach-msm/rpc_server_dog_keepalive.c
2 *
3 * Copyright (C) 2007 Google, Inc.
4 * Author: Iliyan Malchev <ibm@android.com>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/kernel.h>
19#include <mach/msm_rpcrouter.h>
20
21/* dog_keepalive server definitions */
22
23#define DOG_KEEPALIVE_PROG 0x30000015
24#if CONFIG_MSM_AMSS_VERSION==6210
25#define DOG_KEEPALIVE_VERS 0
26#define RPC_DOG_KEEPALIVE_BEACON 1
27#elif (CONFIG_MSM_AMSS_VERSION==6220) || (CONFIG_MSM_AMSS_VERSION==6225)
28#define DOG_KEEPALIVE_VERS 0x731fa727
29#define RPC_DOG_KEEPALIVE_BEACON 2
30#elif CONFIG_MSM_AMSS_VERSION==6350
31#define DOG_KEEPALIVE_VERS 0x00010000
32#define RPC_DOG_KEEPALIVE_BEACON 2
33#else
34#error "Unsupported AMSS version"
35#endif
36#define RPC_DOG_KEEPALIVE_NULL 0
37
38
39/* TODO: Remove server registration with _VERS when modem is upated with _COMP*/
40
41static int handle_rpc_call(struct msm_rpc_server *server,
42 struct rpc_request_hdr *req, unsigned len)
43{
44 switch (req->procedure) {
45 case RPC_DOG_KEEPALIVE_NULL:
46 return 0;
47 case RPC_DOG_KEEPALIVE_BEACON:
48 printk(KERN_INFO "DOG KEEPALIVE PING\n");
49 return 0;
50 default:
51 return -ENODEV;
52 }
53}
54
55static struct msm_rpc_server rpc_server = {
56 .prog = DOG_KEEPALIVE_PROG,
57 .vers = DOG_KEEPALIVE_VERS,
58 .rpc_call = handle_rpc_call,
59};
60
61static int __init rpc_server_init(void)
62{
63 /* Dual server registration to support backwards compatibility vers */
64 return msm_rpc_create_server(&rpc_server);
65}
66
67
68module_init(rpc_server_init);
diff --git a/drivers/staging/dream/smd/rpc_server_time_remote.c b/drivers/staging/dream/smd/rpc_server_time_remote.c
deleted file mode 100644
index 2f90fc88c385..000000000000
--- a/drivers/staging/dream/smd/rpc_server_time_remote.c
+++ /dev/null
@@ -1,77 +0,0 @@
1/* arch/arm/mach-msm/rpc_server_time_remote.c
2 *
3 * Copyright (C) 2007 Google, Inc.
4 * Author: Iliyan Malchev <ibm@android.com>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/kernel.h>
19#include <mach/msm_rpcrouter.h>
20
21/* time_remote_mtoa server definitions. */
22
23#define TIME_REMOTE_MTOA_PROG 0x3000005d
24#if CONFIG_MSM_AMSS_VERSION==6210
25#define TIME_REMOTE_MTOA_VERS 0
26#elif (CONFIG_MSM_AMSS_VERSION==6220) || (CONFIG_MSM_AMSS_VERSION==6225)
27#define TIME_REMOTE_MTOA_VERS 0x9202a8e4
28#elif CONFIG_MSM_AMSS_VERSION==6350
29#define TIME_REMOTE_MTOA_VERS 0x00010000
30#else
31#error "Unknown AMSS version"
32#endif
33#define RPC_TIME_REMOTE_MTOA_NULL 0
34#define RPC_TIME_TOD_SET_APPS_BASES 2
35
36struct rpc_time_tod_set_apps_bases_args {
37 uint32_t tick;
38 uint64_t stamp;
39};
40
41static int handle_rpc_call(struct msm_rpc_server *server,
42 struct rpc_request_hdr *req, unsigned len)
43{
44 switch (req->procedure) {
45 case RPC_TIME_REMOTE_MTOA_NULL:
46 return 0;
47
48 case RPC_TIME_TOD_SET_APPS_BASES: {
49 struct rpc_time_tod_set_apps_bases_args *args;
50 args = (struct rpc_time_tod_set_apps_bases_args *)(req + 1);
51 args->tick = be32_to_cpu(args->tick);
52 args->stamp = be64_to_cpu(args->stamp);
53 printk(KERN_INFO "RPC_TIME_TOD_SET_APPS_BASES:\n"
54 "\ttick = %d\n"
55 "\tstamp = %lld\n",
56 args->tick, args->stamp);
57 return 0;
58 }
59 default:
60 return -ENODEV;
61 }
62}
63
64static struct msm_rpc_server rpc_server = {
65 .prog = TIME_REMOTE_MTOA_PROG,
66 .vers = TIME_REMOTE_MTOA_VERS,
67 .rpc_call = handle_rpc_call,
68};
69
70static int __init rpc_server_init(void)
71{
72 /* Dual server registration to support backwards compatibility vers */
73 return msm_rpc_create_server(&rpc_server);
74}
75
76
77module_init(rpc_server_init);
diff --git a/drivers/staging/dream/smd/smd.c b/drivers/staging/dream/smd/smd.c
deleted file mode 100644
index 8f35be7193fb..000000000000
--- a/drivers/staging/dream/smd/smd.c
+++ /dev/null
@@ -1,1330 +0,0 @@
1/* arch/arm/mach-msm/smd.c
2 *
3 * Copyright (C) 2007 Google, Inc.
4 * Author: Brian Swetland <swetland@google.com>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/platform_device.h>
18#include <linux/module.h>
19#include <linux/fs.h>
20#include <linux/cdev.h>
21#include <linux/device.h>
22#include <linux/wait.h>
23#include <linux/interrupt.h>
24#include <linux/irq.h>
25#include <linux/list.h>
26#include <linux/slab.h>
27#include <linux/debugfs.h>
28#include <linux/delay.h>
29#include <linux/io.h>
30
31#include <mach/msm_smd.h>
32#include <mach/msm_iomap.h>
33#include <mach/system.h>
34
35#include "smd_private.h"
36#include "../../../../arch/arm/mach-msm/proc_comm.h"
37
38void (*msm_hw_reset_hook)(void);
39
40#define MODULE_NAME "msm_smd"
41
42enum {
43 MSM_SMD_DEBUG = 1U << 0,
44 MSM_SMSM_DEBUG = 1U << 0,
45};
46
47static int msm_smd_debug_mask;
48
49module_param_named(debug_mask, msm_smd_debug_mask,
50 int, S_IRUGO | S_IWUSR | S_IWGRP);
51
52void *smem_find(unsigned id, unsigned size);
53static void smd_diag(void);
54
55static unsigned last_heap_free = 0xffffffff;
56
57#define MSM_A2M_INT(n) (MSM_CSR_BASE + 0x400 + (n) * 4)
58
59static inline void notify_other_smsm(void)
60{
61 writel(1, MSM_A2M_INT(5));
62}
63
64static inline void notify_other_smd(void)
65{
66 writel(1, MSM_A2M_INT(0));
67}
68
69static void smd_diag(void)
70{
71 char *x;
72
73 x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG);
74 if (x != 0) {
75 x[SZ_DIAG_ERR_MSG - 1] = 0;
76 pr_info("smem: DIAG '%s'\n", x);
77 }
78}
79
80/* call when SMSM_RESET flag is set in the A9's smsm_state */
81static void handle_modem_crash(void)
82{
83 pr_err("ARM9 has CRASHED\n");
84 smd_diag();
85
86 /* hard reboot if possible */
87 if (msm_hw_reset_hook)
88 msm_hw_reset_hook();
89
90 /* in this case the modem or watchdog should reboot us */
91 for (;;)
92 ;
93}
94
95extern int (*msm_check_for_modem_crash)(void);
96
97static int check_for_modem_crash(void)
98{
99 struct smsm_shared *smsm;
100
101 smsm = smem_find(ID_SHARED_STATE, 2 * sizeof(struct smsm_shared));
102
103 /* if the modem's not ready yet, we have to hope for the best */
104 if (!smsm)
105 return 0;
106
107 if (smsm[1].state & SMSM_RESET) {
108 handle_modem_crash();
109 return -1;
110 } else {
111 return 0;
112 }
113}
114
115#define SMD_SS_CLOSED 0x00000000
116#define SMD_SS_OPENING 0x00000001
117#define SMD_SS_OPENED 0x00000002
118#define SMD_SS_FLUSHING 0x00000003
119#define SMD_SS_CLOSING 0x00000004
120#define SMD_SS_RESET 0x00000005
121#define SMD_SS_RESET_OPENING 0x00000006
122
123#define SMD_BUF_SIZE 8192
124#define SMD_CHANNELS 64
125
126#define SMD_HEADER_SIZE 20
127
128
129/* the spinlock is used to synchronize between the
130** irq handler and code that mutates the channel
131** list or fiddles with channel state
132*/
133static DEFINE_SPINLOCK(smd_lock);
134static DEFINE_SPINLOCK(smem_lock);
135
136/* the mutex is used during open() and close()
137** operations to avoid races while creating or
138** destroying smd_channel structures
139*/
140static DEFINE_MUTEX(smd_creation_mutex);
141
142static int smd_initialized;
143
144struct smd_alloc_elm {
145 char name[20];
146 uint32_t cid;
147 uint32_t ctype;
148 uint32_t ref_count;
149};
150
151struct smd_half_channel {
152 unsigned state;
153 unsigned char fDSR;
154 unsigned char fCTS;
155 unsigned char fCD;
156 unsigned char fRI;
157 unsigned char fHEAD;
158 unsigned char fTAIL;
159 unsigned char fSTATE;
160 unsigned char fUNUSED;
161 unsigned tail;
162 unsigned head;
163 unsigned char data[SMD_BUF_SIZE];
164};
165
166struct smd_shared {
167 struct smd_half_channel ch0;
168 struct smd_half_channel ch1;
169};
170
171struct smd_channel {
172 volatile struct smd_half_channel *send;
173 volatile struct smd_half_channel *recv;
174 struct list_head ch_list;
175
176 unsigned current_packet;
177 unsigned n;
178 void *priv;
179 void (*notify)(void *priv, unsigned flags);
180
181 int (*read)(smd_channel_t *ch, void *data, int len);
182 int (*write)(smd_channel_t *ch, const void *data, int len);
183 int (*read_avail)(smd_channel_t *ch);
184 int (*write_avail)(smd_channel_t *ch);
185
186 void (*update_state)(smd_channel_t *ch);
187 unsigned last_state;
188
189 char name[32];
190 struct platform_device pdev;
191};
192
193static LIST_HEAD(smd_ch_closed_list);
194static LIST_HEAD(smd_ch_list);
195
196static unsigned char smd_ch_allocated[64];
197static struct work_struct probe_work;
198
199static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type);
200
201static void smd_channel_probe_worker(struct work_struct *work)
202{
203 struct smd_alloc_elm *shared;
204 unsigned n;
205
206 shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
207
208 for (n = 0; n < 64; n++) {
209 if (smd_ch_allocated[n])
210 continue;
211 if (!shared[n].ref_count)
212 continue;
213 if (!shared[n].name[0])
214 continue;
215 smd_alloc_channel(shared[n].name,
216 shared[n].cid,
217 shared[n].ctype);
218 smd_ch_allocated[n] = 1;
219 }
220}
221
222static char *chstate(unsigned n)
223{
224 switch (n) {
225 case SMD_SS_CLOSED:
226 return "CLOSED";
227 case SMD_SS_OPENING:
228 return "OPENING";
229 case SMD_SS_OPENED:
230 return "OPENED";
231 case SMD_SS_FLUSHING:
232 return "FLUSHING";
233 case SMD_SS_CLOSING:
234 return "CLOSING";
235 case SMD_SS_RESET:
236 return "RESET";
237 case SMD_SS_RESET_OPENING:
238 return "ROPENING";
239 default:
240 return "UNKNOWN";
241 }
242}
243
244/* how many bytes are available for reading */
245static int smd_stream_read_avail(struct smd_channel *ch)
246{
247 return (ch->recv->head - ch->recv->tail) & (SMD_BUF_SIZE - 1);
248}
249
250/* how many bytes we are free to write */
251static int smd_stream_write_avail(struct smd_channel *ch)
252{
253 return (SMD_BUF_SIZE - 1) -
254 ((ch->send->head - ch->send->tail) & (SMD_BUF_SIZE - 1));
255}
256
257static int smd_packet_read_avail(struct smd_channel *ch)
258{
259 if (ch->current_packet) {
260 int n = smd_stream_read_avail(ch);
261 if (n > ch->current_packet)
262 n = ch->current_packet;
263 return n;
264 } else {
265 return 0;
266 }
267}
268
269static int smd_packet_write_avail(struct smd_channel *ch)
270{
271 int n = smd_stream_write_avail(ch);
272 return n > SMD_HEADER_SIZE ? n - SMD_HEADER_SIZE : 0;
273}
274
275static int ch_is_open(struct smd_channel *ch)
276{
277 return (ch->recv->state == SMD_SS_OPENED) &&
278 (ch->send->state == SMD_SS_OPENED);
279}
280
281/* provide a pointer and length to readable data in the fifo */
282static unsigned ch_read_buffer(struct smd_channel *ch, void **ptr)
283{
284 unsigned head = ch->recv->head;
285 unsigned tail = ch->recv->tail;
286 *ptr = (void *) (ch->recv->data + tail);
287
288 if (tail <= head)
289 return head - tail;
290 else
291 return SMD_BUF_SIZE - tail;
292}
293
294/* advance the fifo read pointer after data from ch_read_buffer is consumed */
295static void ch_read_done(struct smd_channel *ch, unsigned count)
296{
297 BUG_ON(count > smd_stream_read_avail(ch));
298 ch->recv->tail = (ch->recv->tail + count) & (SMD_BUF_SIZE - 1);
299 ch->recv->fTAIL = 1;
300}
301
302/* basic read interface to ch_read_{buffer,done} used
303** by smd_*_read() and update_packet_state()
304** will read-and-discard if the _data pointer is null
305*/
306static int ch_read(struct smd_channel *ch, void *_data, int len)
307{
308 void *ptr;
309 unsigned n;
310 unsigned char *data = _data;
311 int orig_len = len;
312
313 while (len > 0) {
314 n = ch_read_buffer(ch, &ptr);
315 if (n == 0)
316 break;
317
318 if (n > len)
319 n = len;
320 if (_data)
321 memcpy(data, ptr, n);
322
323 data += n;
324 len -= n;
325 ch_read_done(ch, n);
326 }
327
328 return orig_len - len;
329}
330
331static void update_stream_state(struct smd_channel *ch)
332{
333 /* streams have no special state requiring updating */
334}
335
336static void update_packet_state(struct smd_channel *ch)
337{
338 unsigned hdr[5];
339 int r;
340
341 /* can't do anything if we're in the middle of a packet */
342 if (ch->current_packet != 0)
343 return;
344
345 /* don't bother unless we can get the full header */
346 if (smd_stream_read_avail(ch) < SMD_HEADER_SIZE)
347 return;
348
349 r = ch_read(ch, hdr, SMD_HEADER_SIZE);
350 BUG_ON(r != SMD_HEADER_SIZE);
351
352 ch->current_packet = hdr[0];
353}
354
355/* provide a pointer and length to next free space in the fifo */
356static unsigned ch_write_buffer(struct smd_channel *ch, void **ptr)
357{
358 unsigned head = ch->send->head;
359 unsigned tail = ch->send->tail;
360 *ptr = (void *) (ch->send->data + head);
361
362 if (head < tail) {
363 return tail - head - 1;
364 } else {
365 if (tail == 0)
366 return SMD_BUF_SIZE - head - 1;
367 else
368 return SMD_BUF_SIZE - head;
369 }
370}
371
372/* advace the fifo write pointer after freespace
373 * from ch_write_buffer is filled
374 */
375static void ch_write_done(struct smd_channel *ch, unsigned count)
376{
377 BUG_ON(count > smd_stream_write_avail(ch));
378 ch->send->head = (ch->send->head + count) & (SMD_BUF_SIZE - 1);
379 ch->send->fHEAD = 1;
380}
381
382static void hc_set_state(volatile struct smd_half_channel *hc, unsigned n)
383{
384 if (n == SMD_SS_OPENED) {
385 hc->fDSR = 1;
386 hc->fCTS = 1;
387 hc->fCD = 1;
388 } else {
389 hc->fDSR = 0;
390 hc->fCTS = 0;
391 hc->fCD = 0;
392 }
393 hc->state = n;
394 hc->fSTATE = 1;
395 notify_other_smd();
396}
397
398static void do_smd_probe(void)
399{
400 struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
401 if (shared->heap_info.free_offset != last_heap_free) {
402 last_heap_free = shared->heap_info.free_offset;
403 schedule_work(&probe_work);
404 }
405}
406
407static void smd_state_change(struct smd_channel *ch,
408 unsigned last, unsigned next)
409{
410 ch->last_state = next;
411
412 pr_info("SMD: ch %d %s -> %s\n", ch->n,
413 chstate(last), chstate(next));
414
415 switch (next) {
416 case SMD_SS_OPENING:
417 ch->recv->tail = 0;
418 case SMD_SS_OPENED:
419 if (ch->send->state != SMD_SS_OPENED)
420 hc_set_state(ch->send, SMD_SS_OPENED);
421 ch->notify(ch->priv, SMD_EVENT_OPEN);
422 break;
423 case SMD_SS_FLUSHING:
424 case SMD_SS_RESET:
425 /* we should force them to close? */
426 default:
427 ch->notify(ch->priv, SMD_EVENT_CLOSE);
428 }
429}
430
431static irqreturn_t smd_irq_handler(int irq, void *data)
432{
433 unsigned long flags;
434 struct smd_channel *ch;
435 int do_notify = 0;
436 unsigned ch_flags;
437 unsigned tmp;
438
439 spin_lock_irqsave(&smd_lock, flags);
440 list_for_each_entry(ch, &smd_ch_list, ch_list) {
441 ch_flags = 0;
442 if (ch_is_open(ch)) {
443 if (ch->recv->fHEAD) {
444 ch->recv->fHEAD = 0;
445 ch_flags |= 1;
446 do_notify |= 1;
447 }
448 if (ch->recv->fTAIL) {
449 ch->recv->fTAIL = 0;
450 ch_flags |= 2;
451 do_notify |= 1;
452 }
453 if (ch->recv->fSTATE) {
454 ch->recv->fSTATE = 0;
455 ch_flags |= 4;
456 do_notify |= 1;
457 }
458 }
459 tmp = ch->recv->state;
460 if (tmp != ch->last_state)
461 smd_state_change(ch, ch->last_state, tmp);
462 if (ch_flags) {
463 ch->update_state(ch);
464 ch->notify(ch->priv, SMD_EVENT_DATA);
465 }
466 }
467 if (do_notify)
468 notify_other_smd();
469 spin_unlock_irqrestore(&smd_lock, flags);
470 do_smd_probe();
471 return IRQ_HANDLED;
472}
473
474static void smd_fake_irq_handler(unsigned long arg)
475{
476 smd_irq_handler(0, NULL);
477}
478
479static DECLARE_TASKLET(smd_fake_irq_tasklet, smd_fake_irq_handler, 0);
480
481void smd_sleep_exit(void)
482{
483 unsigned long flags;
484 struct smd_channel *ch;
485 unsigned tmp;
486 int need_int = 0;
487
488 spin_lock_irqsave(&smd_lock, flags);
489 list_for_each_entry(ch, &smd_ch_list, ch_list) {
490 if (ch_is_open(ch)) {
491 if (ch->recv->fHEAD) {
492 if (msm_smd_debug_mask & MSM_SMD_DEBUG)
493 pr_info("smd_sleep_exit ch %d fHEAD "
494 "%x %x %x\n",
495 ch->n, ch->recv->fHEAD,
496 ch->recv->head, ch->recv->tail);
497 need_int = 1;
498 break;
499 }
500 if (ch->recv->fTAIL) {
501 if (msm_smd_debug_mask & MSM_SMD_DEBUG)
502 pr_info("smd_sleep_exit ch %d fTAIL "
503 "%x %x %x\n",
504 ch->n, ch->recv->fTAIL,
505 ch->send->head, ch->send->tail);
506 need_int = 1;
507 break;
508 }
509 if (ch->recv->fSTATE) {
510 if (msm_smd_debug_mask & MSM_SMD_DEBUG)
511 pr_info("smd_sleep_exit ch %d fSTATE %x"
512 "\n", ch->n, ch->recv->fSTATE);
513 need_int = 1;
514 break;
515 }
516 tmp = ch->recv->state;
517 if (tmp != ch->last_state) {
518 if (msm_smd_debug_mask & MSM_SMD_DEBUG)
519 pr_info("smd_sleep_exit ch %d "
520 "state %x != %x\n",
521 ch->n, tmp, ch->last_state);
522 need_int = 1;
523 break;
524 }
525 }
526 }
527 spin_unlock_irqrestore(&smd_lock, flags);
528 do_smd_probe();
529 if (need_int) {
530 if (msm_smd_debug_mask & MSM_SMD_DEBUG)
531 pr_info("smd_sleep_exit need interrupt\n");
532 tasklet_schedule(&smd_fake_irq_tasklet);
533 }
534}
535
536
537void smd_kick(smd_channel_t *ch)
538{
539 unsigned long flags;
540 unsigned tmp;
541
542 spin_lock_irqsave(&smd_lock, flags);
543 ch->update_state(ch);
544 tmp = ch->recv->state;
545 if (tmp != ch->last_state) {
546 ch->last_state = tmp;
547 if (tmp == SMD_SS_OPENED)
548 ch->notify(ch->priv, SMD_EVENT_OPEN);
549 else
550 ch->notify(ch->priv, SMD_EVENT_CLOSE);
551 }
552 ch->notify(ch->priv, SMD_EVENT_DATA);
553 notify_other_smd();
554 spin_unlock_irqrestore(&smd_lock, flags);
555}
556
557static int smd_is_packet(int chn)
558{
559 if ((chn > 4) || (chn == 1))
560 return 1;
561 else
562 return 0;
563}
564
565static int smd_stream_write(smd_channel_t *ch, const void *_data, int len)
566{
567 void *ptr;
568 const unsigned char *buf = _data;
569 unsigned xfer;
570 int orig_len = len;
571
572 if (len < 0)
573 return -EINVAL;
574
575 while ((xfer = ch_write_buffer(ch, &ptr)) != 0) {
576 if (!ch_is_open(ch))
577 break;
578 if (xfer > len)
579 xfer = len;
580 memcpy(ptr, buf, xfer);
581 ch_write_done(ch, xfer);
582 len -= xfer;
583 buf += xfer;
584 if (len == 0)
585 break;
586 }
587
588 notify_other_smd();
589
590 return orig_len - len;
591}
592
593static int smd_packet_write(smd_channel_t *ch, const void *_data, int len)
594{
595 unsigned hdr[5];
596
597 if (len < 0)
598 return -EINVAL;
599
600 if (smd_stream_write_avail(ch) < (len + SMD_HEADER_SIZE))
601 return -ENOMEM;
602
603 hdr[0] = len;
604 hdr[1] = hdr[2] = hdr[3] = hdr[4] = 0;
605
606 smd_stream_write(ch, hdr, sizeof(hdr));
607 smd_stream_write(ch, _data, len);
608
609 return len;
610}
611
612static int smd_stream_read(smd_channel_t *ch, void *data, int len)
613{
614 int r;
615
616 if (len < 0)
617 return -EINVAL;
618
619 r = ch_read(ch, data, len);
620 if (r > 0)
621 notify_other_smd();
622
623 return r;
624}
625
626static int smd_packet_read(smd_channel_t *ch, void *data, int len)
627{
628 unsigned long flags;
629 int r;
630
631 if (len < 0)
632 return -EINVAL;
633
634 if (len > ch->current_packet)
635 len = ch->current_packet;
636
637 r = ch_read(ch, data, len);
638 if (r > 0)
639 notify_other_smd();
640
641 spin_lock_irqsave(&smd_lock, flags);
642 ch->current_packet -= r;
643 update_packet_state(ch);
644 spin_unlock_irqrestore(&smd_lock, flags);
645
646 return r;
647}
648
649static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type)
650{
651 struct smd_channel *ch;
652 struct smd_shared *shared;
653
654 shared = smem_alloc(ID_SMD_CHANNELS + cid, sizeof(*shared));
655 if (!shared) {
656 pr_err("smd_alloc_channel() cid %d does not exist\n", cid);
657 return;
658 }
659
660 ch = kzalloc(sizeof(struct smd_channel), GFP_KERNEL);
661 if (ch == 0) {
662 pr_err("smd_alloc_channel() out of memory\n");
663 return;
664 }
665
666 ch->send = &shared->ch0;
667 ch->recv = &shared->ch1;
668 ch->n = cid;
669
670 if (smd_is_packet(cid)) {
671 ch->read = smd_packet_read;
672 ch->write = smd_packet_write;
673 ch->read_avail = smd_packet_read_avail;
674 ch->write_avail = smd_packet_write_avail;
675 ch->update_state = update_packet_state;
676 } else {
677 ch->read = smd_stream_read;
678 ch->write = smd_stream_write;
679 ch->read_avail = smd_stream_read_avail;
680 ch->write_avail = smd_stream_write_avail;
681 ch->update_state = update_stream_state;
682 }
683
684 memcpy(ch->name, "SMD_", 4);
685 memcpy(ch->name + 4, name, 20);
686 ch->name[23] = 0;
687 ch->pdev.name = ch->name;
688 ch->pdev.id = -1;
689
690 pr_info("smd_alloc_channel() '%s' cid=%d, shared=%p\n",
691 ch->name, ch->n, shared);
692
693 mutex_lock(&smd_creation_mutex);
694 list_add(&ch->ch_list, &smd_ch_closed_list);
695 mutex_unlock(&smd_creation_mutex);
696
697 platform_device_register(&ch->pdev);
698}
699
700static void do_nothing_notify(void *priv, unsigned flags)
701{
702}
703
704struct smd_channel *smd_get_channel(const char *name)
705{
706 struct smd_channel *ch;
707
708 mutex_lock(&smd_creation_mutex);
709 list_for_each_entry(ch, &smd_ch_closed_list, ch_list) {
710 if (!strcmp(name, ch->name)) {
711 list_del(&ch->ch_list);
712 mutex_unlock(&smd_creation_mutex);
713 return ch;
714 }
715 }
716 mutex_unlock(&smd_creation_mutex);
717
718 return NULL;
719}
720
721int smd_open(const char *name, smd_channel_t **_ch,
722 void *priv, void (*notify)(void *, unsigned))
723{
724 struct smd_channel *ch;
725 unsigned long flags;
726
727 if (smd_initialized == 0) {
728 pr_info("smd_open() before smd_init()\n");
729 return -ENODEV;
730 }
731
732 ch = smd_get_channel(name);
733 if (!ch)
734 return -ENODEV;
735
736 if (notify == 0)
737 notify = do_nothing_notify;
738
739 ch->notify = notify;
740 ch->current_packet = 0;
741 ch->last_state = SMD_SS_CLOSED;
742 ch->priv = priv;
743
744 *_ch = ch;
745
746 spin_lock_irqsave(&smd_lock, flags);
747 list_add(&ch->ch_list, &smd_ch_list);
748
749 /* If the remote side is CLOSING, we need to get it to
750 * move to OPENING (which we'll do by moving from CLOSED to
751 * OPENING) and then get it to move from OPENING to
752 * OPENED (by doing the same state change ourselves).
753 *
754 * Otherwise, it should be OPENING and we can move directly
755 * to OPENED so that it will follow.
756 */
757 if (ch->recv->state == SMD_SS_CLOSING) {
758 ch->send->head = 0;
759 hc_set_state(ch->send, SMD_SS_OPENING);
760 } else {
761 hc_set_state(ch->send, SMD_SS_OPENED);
762 }
763 spin_unlock_irqrestore(&smd_lock, flags);
764 smd_kick(ch);
765
766 return 0;
767}
768
769int smd_close(smd_channel_t *ch)
770{
771 unsigned long flags;
772
773 pr_info("smd_close(%p)\n", ch);
774
775 if (ch == 0)
776 return -1;
777
778 spin_lock_irqsave(&smd_lock, flags);
779 ch->notify = do_nothing_notify;
780 list_del(&ch->ch_list);
781 hc_set_state(ch->send, SMD_SS_CLOSED);
782 spin_unlock_irqrestore(&smd_lock, flags);
783
784 mutex_lock(&smd_creation_mutex);
785 list_add(&ch->ch_list, &smd_ch_closed_list);
786 mutex_unlock(&smd_creation_mutex);
787
788 return 0;
789}
790
791int smd_read(smd_channel_t *ch, void *data, int len)
792{
793 return ch->read(ch, data, len);
794}
795
796int smd_write(smd_channel_t *ch, const void *data, int len)
797{
798 return ch->write(ch, data, len);
799}
800
801int smd_read_avail(smd_channel_t *ch)
802{
803 return ch->read_avail(ch);
804}
805
806int smd_write_avail(smd_channel_t *ch)
807{
808 return ch->write_avail(ch);
809}
810
811int smd_wait_until_readable(smd_channel_t *ch, int bytes)
812{
813 return -1;
814}
815
816int smd_wait_until_writable(smd_channel_t *ch, int bytes)
817{
818 return -1;
819}
820
821int smd_cur_packet_size(smd_channel_t *ch)
822{
823 return ch->current_packet;
824}
825
826
827/* ------------------------------------------------------------------------- */
828
829void *smem_alloc(unsigned id, unsigned size)
830{
831 return smem_find(id, size);
832}
833
834static void *_smem_find(unsigned id, unsigned *size)
835{
836 struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
837 struct smem_heap_entry *toc = shared->heap_toc;
838
839 if (id >= SMEM_NUM_ITEMS)
840 return 0;
841
842 if (toc[id].allocated) {
843 *size = toc[id].size;
844 return (void *) (MSM_SHARED_RAM_BASE + toc[id].offset);
845 }
846
847 return 0;
848}
849
850void *smem_find(unsigned id, unsigned size_in)
851{
852 unsigned size;
853 void *ptr;
854
855 ptr = _smem_find(id, &size);
856 if (!ptr)
857 return 0;
858
859 size_in = ALIGN(size_in, 8);
860 if (size_in != size) {
861 pr_err("smem_find(%d, %d): wrong size %d\n",
862 id, size_in, size);
863 return 0;
864 }
865
866 return ptr;
867}
868
869static irqreturn_t smsm_irq_handler(int irq, void *data)
870{
871 unsigned long flags;
872 struct smsm_shared *smsm;
873
874 spin_lock_irqsave(&smem_lock, flags);
875 smsm = smem_alloc(ID_SHARED_STATE,
876 2 * sizeof(struct smsm_shared));
877
878 if (smsm == 0) {
879 pr_info("<SM NO STATE>\n");
880 } else {
881 unsigned apps = smsm[0].state;
882 unsigned modm = smsm[1].state;
883
884 if (msm_smd_debug_mask & MSM_SMSM_DEBUG)
885 pr_info("<SM %08x %08x>\n", apps, modm);
886 if (modm & SMSM_RESET) {
887 handle_modem_crash();
888 } else {
889 apps |= SMSM_INIT;
890 if (modm & SMSM_SMDINIT)
891 apps |= SMSM_SMDINIT;
892 if (modm & SMSM_RPCINIT)
893 apps |= SMSM_RPCINIT;
894 }
895
896 if (smsm[0].state != apps) {
897 if (msm_smd_debug_mask & MSM_SMSM_DEBUG)
898 pr_info("<SM %08x NOTIFY>\n", apps);
899 smsm[0].state = apps;
900 do_smd_probe();
901 notify_other_smsm();
902 }
903 }
904 spin_unlock_irqrestore(&smem_lock, flags);
905 return IRQ_HANDLED;
906}
907
908int smsm_change_state(uint32_t clear_mask, uint32_t set_mask)
909{
910 unsigned long flags;
911 struct smsm_shared *smsm;
912
913 spin_lock_irqsave(&smem_lock, flags);
914
915 smsm = smem_alloc(ID_SHARED_STATE,
916 2 * sizeof(struct smsm_shared));
917
918 if (smsm) {
919 if (smsm[1].state & SMSM_RESET)
920 handle_modem_crash();
921 smsm[0].state = (smsm[0].state & ~clear_mask) | set_mask;
922 if (msm_smd_debug_mask & MSM_SMSM_DEBUG)
923 pr_info("smsm_change_state %x\n",
924 smsm[0].state);
925 notify_other_smsm();
926 }
927
928 spin_unlock_irqrestore(&smem_lock, flags);
929
930 if (smsm == NULL) {
931 pr_err("smsm_change_state <SM NO STATE>\n");
932 return -EIO;
933 }
934 return 0;
935}
936
937uint32_t smsm_get_state(void)
938{
939 unsigned long flags;
940 struct smsm_shared *smsm;
941 uint32_t rv;
942
943 spin_lock_irqsave(&smem_lock, flags);
944
945 smsm = smem_alloc(ID_SHARED_STATE,
946 2 * sizeof(struct smsm_shared));
947
948 if (smsm)
949 rv = smsm[1].state;
950 else
951 rv = 0;
952
953 if (rv & SMSM_RESET)
954 handle_modem_crash();
955
956 spin_unlock_irqrestore(&smem_lock, flags);
957
958 if (smsm == NULL)
959 pr_err("smsm_get_state <SM NO STATE>\n");
960 return rv;
961}
962
963int smsm_set_sleep_duration(uint32_t delay)
964{
965 uint32_t *ptr;
966
967 ptr = smem_alloc(SMEM_SMSM_SLEEP_DELAY, sizeof(*ptr));
968 if (ptr == NULL) {
969 pr_err("smsm_set_sleep_duration <SM NO SLEEP_DELAY>\n");
970 return -EIO;
971 }
972 if (msm_smd_debug_mask & MSM_SMSM_DEBUG)
973 pr_info("smsm_set_sleep_duration %d -> %d\n",
974 *ptr, delay);
975 *ptr = delay;
976 return 0;
977}
978
979int smsm_set_interrupt_info(struct smsm_interrupt_info *info)
980{
981 struct smsm_interrupt_info *ptr;
982
983 ptr = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*ptr));
984 if (ptr == NULL) {
985 pr_err("smsm_set_sleep_duration <SM NO INT_INFO>\n");
986 return -EIO;
987 }
988 if (msm_smd_debug_mask & MSM_SMSM_DEBUG)
989 pr_info("smsm_set_interrupt_info %x %x -> %x %x\n",
990 ptr->aArm_en_mask, ptr->aArm_interrupts_pending,
991 info->aArm_en_mask, info->aArm_interrupts_pending);
992 *ptr = *info;
993 return 0;
994}
995
996#define MAX_NUM_SLEEP_CLIENTS 64
997#define MAX_SLEEP_NAME_LEN 8
998
999#define NUM_GPIO_INT_REGISTERS 6
1000#define GPIO_SMEM_NUM_GROUPS 2
1001#define GPIO_SMEM_MAX_PC_INTERRUPTS 8
1002
1003struct tramp_gpio_save {
1004 unsigned int enable;
1005 unsigned int detect;
1006 unsigned int polarity;
1007};
1008
1009struct tramp_gpio_smem {
1010 uint16_t num_fired[GPIO_SMEM_NUM_GROUPS];
1011 uint16_t fired[GPIO_SMEM_NUM_GROUPS][GPIO_SMEM_MAX_PC_INTERRUPTS];
1012 uint32_t enabled[NUM_GPIO_INT_REGISTERS];
1013 uint32_t detection[NUM_GPIO_INT_REGISTERS];
1014 uint32_t polarity[NUM_GPIO_INT_REGISTERS];
1015};
1016
1017
1018void smsm_print_sleep_info(void)
1019{
1020 unsigned long flags;
1021 uint32_t *ptr;
1022 struct tramp_gpio_smem *gpio;
1023 struct smsm_interrupt_info *int_info;
1024
1025
1026 spin_lock_irqsave(&smem_lock, flags);
1027
1028 ptr = smem_alloc(SMEM_SMSM_SLEEP_DELAY, sizeof(*ptr));
1029 if (ptr)
1030 pr_info("SMEM_SMSM_SLEEP_DELAY: %x\n", *ptr);
1031
1032 ptr = smem_alloc(SMEM_SMSM_LIMIT_SLEEP, sizeof(*ptr));
1033 if (ptr)
1034 pr_info("SMEM_SMSM_LIMIT_SLEEP: %x\n", *ptr);
1035
1036 ptr = smem_alloc(SMEM_SLEEP_POWER_COLLAPSE_DISABLED, sizeof(*ptr));
1037 if (ptr)
1038 pr_info("SMEM_SLEEP_POWER_COLLAPSE_DISABLED: %x\n", *ptr);
1039
1040 int_info = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*int_info));
1041 if (int_info)
1042 pr_info("SMEM_SMSM_INT_INFO %x %x %x\n",
1043 int_info->aArm_en_mask,
1044 int_info->aArm_interrupts_pending,
1045 int_info->aArm_wakeup_reason);
1046
1047 gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*gpio));
1048 if (gpio) {
1049 int i;
1050 for (i = 0; i < NUM_GPIO_INT_REGISTERS; i++)
1051 pr_info("SMEM_GPIO_INT: %d: e %x d %x p %x\n",
1052 i, gpio->enabled[i], gpio->detection[i],
1053 gpio->polarity[i]);
1054
1055 for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++)
1056 pr_info("SMEM_GPIO_INT: %d: f %d: %d %d...\n",
1057 i, gpio->num_fired[i], gpio->fired[i][0],
1058 gpio->fired[i][1]);
1059 }
1060
1061 spin_unlock_irqrestore(&smem_lock, flags);
1062}
1063
1064int smd_core_init(void)
1065{
1066 int r;
1067 pr_info("smd_core_init()\n");
1068
1069 r = request_irq(INT_A9_M2A_0, smd_irq_handler,
1070 IRQF_TRIGGER_RISING, "smd_dev", 0);
1071 if (r < 0)
1072 return r;
1073 r = enable_irq_wake(INT_A9_M2A_0);
1074 if (r < 0)
1075 pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_0\n");
1076
1077 r = request_irq(INT_A9_M2A_5, smsm_irq_handler,
1078 IRQF_TRIGGER_RISING, "smsm_dev", 0);
1079 if (r < 0) {
1080 free_irq(INT_A9_M2A_0, 0);
1081 return r;
1082 }
1083 r = enable_irq_wake(INT_A9_M2A_5);
1084 if (r < 0)
1085 pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_5\n");
1086
1087 /* we may have missed a signal while booting -- fake
1088 * an interrupt to make sure we process any existing
1089 * state
1090 */
1091 smsm_irq_handler(0, 0);
1092
1093 pr_info("smd_core_init() done\n");
1094
1095 return 0;
1096}
1097
1098#if defined(CONFIG_DEBUG_FS)
1099
1100static int dump_ch(char *buf, int max, int n,
1101 struct smd_half_channel *s,
1102 struct smd_half_channel *r)
1103{
1104 return scnprintf(
1105 buf, max,
1106 "ch%02d:"
1107 " %8s(%04d/%04d) %c%c%c%c%c%c%c <->"
1108 " %8s(%04d/%04d) %c%c%c%c%c%c%c\n", n,
1109 chstate(s->state), s->tail, s->head,
1110 s->fDSR ? 'D' : 'd',
1111 s->fCTS ? 'C' : 'c',
1112 s->fCD ? 'C' : 'c',
1113 s->fRI ? 'I' : 'i',
1114 s->fHEAD ? 'W' : 'w',
1115 s->fTAIL ? 'R' : 'r',
1116 s->fSTATE ? 'S' : 's',
1117 chstate(r->state), r->tail, r->head,
1118 r->fDSR ? 'D' : 'd',
1119 r->fCTS ? 'R' : 'r',
1120 r->fCD ? 'C' : 'c',
1121 r->fRI ? 'I' : 'i',
1122 r->fHEAD ? 'W' : 'w',
1123 r->fTAIL ? 'R' : 'r',
1124 r->fSTATE ? 'S' : 's'
1125 );
1126}
1127
1128static int debug_read_stat(char *buf, int max)
1129{
1130 struct smsm_shared *smsm;
1131 char *msg;
1132 int i = 0;
1133
1134 smsm = smem_find(ID_SHARED_STATE,
1135 2 * sizeof(struct smsm_shared));
1136
1137 msg = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG);
1138
1139 if (smsm) {
1140 if (smsm[1].state & SMSM_RESET)
1141 i += scnprintf(buf + i, max - i,
1142 "smsm: ARM9 HAS CRASHED\n");
1143 i += scnprintf(buf + i, max - i, "smsm: a9: %08x a11: %08x\n",
1144 smsm[0].state, smsm[1].state);
1145 } else {
1146 i += scnprintf(buf + i, max - i, "smsm: cannot find\n");
1147 }
1148 if (msg) {
1149 msg[SZ_DIAG_ERR_MSG - 1] = 0;
1150 i += scnprintf(buf + i, max - i, "diag: '%s'\n", msg);
1151 }
1152 return i;
1153}
1154
1155static int debug_read_mem(char *buf, int max)
1156{
1157 unsigned n;
1158 struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
1159 struct smem_heap_entry *toc = shared->heap_toc;
1160 int i = 0;
1161
1162 i += scnprintf(buf + i, max - i,
1163 "heap: init=%d free=%d remain=%d\n",
1164 shared->heap_info.initialized,
1165 shared->heap_info.free_offset,
1166 shared->heap_info.heap_remaining);
1167
1168 for (n = 0; n < SMEM_NUM_ITEMS; n++) {
1169 if (toc[n].allocated == 0)
1170 continue;
1171 i += scnprintf(buf + i, max - i,
1172 "%04d: offsed %08x size %08x\n",
1173 n, toc[n].offset, toc[n].size);
1174 }
1175 return i;
1176}
1177
1178static int debug_read_ch(char *buf, int max)
1179{
1180 struct smd_shared *shared;
1181 int n, i = 0;
1182
1183 for (n = 0; n < SMD_CHANNELS; n++) {
1184 shared = smem_find(ID_SMD_CHANNELS + n,
1185 sizeof(struct smd_shared));
1186 if (shared == 0)
1187 continue;
1188 i += dump_ch(buf + i, max - i, n, &shared->ch0, &shared->ch1);
1189 }
1190
1191 return i;
1192}
1193
1194static int debug_read_version(char *buf, int max)
1195{
1196 struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
1197 unsigned version = shared->version[VERSION_MODEM];
1198 return sprintf(buf, "%d.%d\n", version >> 16, version & 0xffff);
1199}
1200
1201static int debug_read_build_id(char *buf, int max)
1202{
1203 unsigned size;
1204 void *data;
1205
1206 data = _smem_find(SMEM_HW_SW_BUILD_ID, &size);
1207 if (!data)
1208 return 0;
1209
1210 if (size >= max)
1211 size = max;
1212 memcpy(buf, data, size);
1213
1214 return size;
1215}
1216
1217static int debug_read_alloc_tbl(char *buf, int max)
1218{
1219 struct smd_alloc_elm *shared;
1220 int n, i = 0;
1221
1222 shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
1223
1224 for (n = 0; n < 64; n++) {
1225 if (shared[n].ref_count == 0)
1226 continue;
1227 i += scnprintf(buf + i, max - i,
1228 "%03d: %20s cid=%02d ctype=%d ref_count=%d\n",
1229 n, shared[n].name, shared[n].cid,
1230 shared[n].ctype, shared[n].ref_count);
1231 }
1232
1233 return i;
1234}
1235
1236static int debug_boom(char *buf, int max)
1237{
1238 unsigned ms = 5000;
1239 msm_proc_comm(PCOM_RESET_MODEM, &ms, 0);
1240 return 0;
1241}
1242
1243#define DEBUG_BUFMAX 4096
1244static char debug_buffer[DEBUG_BUFMAX];
1245
1246static ssize_t debug_read(struct file *file, char __user *buf,
1247 size_t count, loff_t *ppos)
1248{
1249 int (*fill)(char *buf, int max) = file->private_data;
1250 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
1251 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
1252}
1253
1254static int debug_open(struct inode *inode, struct file *file)
1255{
1256 file->private_data = inode->i_private;
1257 return 0;
1258}
1259
1260static const struct file_operations debug_ops = {
1261 .read = debug_read,
1262 .open = debug_open,
1263};
1264
1265static void debug_create(const char *name, mode_t mode,
1266 struct dentry *dent,
1267 int (*fill)(char *buf, int max))
1268{
1269 debugfs_create_file(name, mode, dent, fill, &debug_ops);
1270}
1271
1272static void smd_debugfs_init(void)
1273{
1274 struct dentry *dent;
1275
1276 dent = debugfs_create_dir("smd", 0);
1277 if (IS_ERR(dent))
1278 return;
1279
1280 debug_create("ch", 0444, dent, debug_read_ch);
1281 debug_create("stat", 0444, dent, debug_read_stat);
1282 debug_create("mem", 0444, dent, debug_read_mem);
1283 debug_create("version", 0444, dent, debug_read_version);
1284 debug_create("tbl", 0444, dent, debug_read_alloc_tbl);
1285 debug_create("build", 0444, dent, debug_read_build_id);
1286 debug_create("boom", 0444, dent, debug_boom);
1287}
1288#else
1289static void smd_debugfs_init(void) {}
1290#endif
1291
1292static int __init msm_smd_probe(struct platform_device *pdev)
1293{
1294 pr_info("smd_init()\n");
1295
1296 INIT_WORK(&probe_work, smd_channel_probe_worker);
1297
1298 if (smd_core_init()) {
1299 pr_err("smd_core_init() failed\n");
1300 return -1;
1301 }
1302
1303 do_smd_probe();
1304
1305 msm_check_for_modem_crash = check_for_modem_crash;
1306
1307 smd_debugfs_init();
1308 smd_initialized = 1;
1309
1310 return 0;
1311}
1312
1313static struct platform_driver msm_smd_driver = {
1314 .probe = msm_smd_probe,
1315 .driver = {
1316 .name = MODULE_NAME,
1317 .owner = THIS_MODULE,
1318 },
1319};
1320
1321static int __init msm_smd_init(void)
1322{
1323 return platform_driver_register(&msm_smd_driver);
1324}
1325
1326module_init(msm_smd_init);
1327
1328MODULE_DESCRIPTION("MSM Shared Memory Core");
1329MODULE_AUTHOR("Brian Swetland <swetland@google.com>");
1330MODULE_LICENSE("GPL");
diff --git a/drivers/staging/dream/smd/smd_private.h b/drivers/staging/dream/smd/smd_private.h
deleted file mode 100644
index 1b2e1c89ea2e..000000000000
--- a/drivers/staging/dream/smd/smd_private.h
+++ /dev/null
@@ -1,164 +0,0 @@
1/* arch/arm/mach-msm/smd_private.h
2 *
3 * Copyright (C) 2007 Google, Inc.
4 * Copyright (c) 2007 QUALCOMM Incorporated
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16#ifndef _ARCH_ARM_MACH_MSM_MSM_SMD_PRIVATE_H_
17#define _ARCH_ARM_MACH_MSM_MSM_SMD_PRIVATE_H_
18
19struct smem_heap_info {
20 unsigned initialized;
21 unsigned free_offset;
22 unsigned heap_remaining;
23 unsigned reserved;
24};
25
26struct smem_heap_entry {
27 unsigned allocated;
28 unsigned offset;
29 unsigned size;
30 unsigned reserved;
31};
32
33struct smem_proc_comm {
34 unsigned command;
35 unsigned status;
36 unsigned data1;
37 unsigned data2;
38};
39
40#define PC_APPS 0
41#define PC_MODEM 1
42
43#define VERSION_QDSP6 4
44#define VERSION_APPS_SBL 6
45#define VERSION_MODEM_SBL 7
46#define VERSION_APPS 8
47#define VERSION_MODEM 9
48
49struct smem_shared {
50 struct smem_proc_comm proc_comm[4];
51 unsigned version[32];
52 struct smem_heap_info heap_info;
53 struct smem_heap_entry heap_toc[128];
54};
55
56struct smsm_shared {
57 unsigned host;
58 unsigned state;
59};
60
61struct smsm_interrupt_info {
62 uint32_t aArm_en_mask;
63 uint32_t aArm_interrupts_pending;
64 uint32_t aArm_wakeup_reason;
65};
66
67#define SZ_DIAG_ERR_MSG 0xC8
68#define ID_DIAG_ERR_MSG SMEM_DIAG_ERR_MESSAGE
69#define ID_SMD_CHANNELS SMEM_SMD_BASE_ID
70#define ID_SHARED_STATE SMEM_SMSM_SHARED_STATE
71#define ID_CH_ALLOC_TBL SMEM_CHANNEL_ALLOC_TBL
72
73#define SMSM_INIT 0x000001
74#define SMSM_SMDINIT 0x000008
75#define SMSM_RPCINIT 0x000020
76#define SMSM_RESET 0x000040
77#define SMSM_RSA 0x0080
78#define SMSM_RUN 0x000100
79#define SMSM_PWRC 0x0200
80#define SMSM_TIMEWAIT 0x0400
81#define SMSM_TIMEINIT 0x0800
82#define SMSM_PWRC_EARLY_EXIT 0x1000
83#define SMSM_WFPI 0x2000
84#define SMSM_SLEEP 0x4000
85#define SMSM_SLEEPEXIT 0x8000
86#define SMSM_OEMSBL_RELEASE 0x10000
87#define SMSM_PWRC_SUSPEND 0x200000
88
89#define SMSM_WKUP_REASON_RPC 0x00000001
90#define SMSM_WKUP_REASON_INT 0x00000002
91#define SMSM_WKUP_REASON_GPIO 0x00000004
92#define SMSM_WKUP_REASON_TIMER 0x00000008
93#define SMSM_WKUP_REASON_ALARM 0x00000010
94#define SMSM_WKUP_REASON_RESET 0x00000020
95
96void *smem_alloc(unsigned id, unsigned size);
97int smsm_change_state(uint32_t clear_mask, uint32_t set_mask);
98uint32_t smsm_get_state(void);
99int smsm_set_sleep_duration(uint32_t delay);
100int smsm_set_interrupt_info(struct smsm_interrupt_info *info);
101void smsm_print_sleep_info(void);
102
103#define SMEM_NUM_SMD_CHANNELS 64
104
105typedef enum {
106 /* fixed items */
107 SMEM_PROC_COMM = 0,
108 SMEM_HEAP_INFO,
109 SMEM_ALLOCATION_TABLE,
110 SMEM_VERSION_INFO,
111 SMEM_HW_RESET_DETECT,
112 SMEM_AARM_WARM_BOOT,
113 SMEM_DIAG_ERR_MESSAGE,
114 SMEM_SPINLOCK_ARRAY,
115 SMEM_MEMORY_BARRIER_LOCATION,
116
117 /* dynamic items */
118 SMEM_AARM_PARTITION_TABLE,
119 SMEM_AARM_BAD_BLOCK_TABLE,
120 SMEM_RESERVE_BAD_BLOCKS,
121 SMEM_WM_UUID,
122 SMEM_CHANNEL_ALLOC_TBL,
123 SMEM_SMD_BASE_ID,
124 SMEM_SMEM_LOG_IDX = SMEM_SMD_BASE_ID + SMEM_NUM_SMD_CHANNELS,
125 SMEM_SMEM_LOG_EVENTS,
126 SMEM_SMEM_STATIC_LOG_IDX,
127 SMEM_SMEM_STATIC_LOG_EVENTS,
128 SMEM_SMEM_SLOW_CLOCK_SYNC,
129 SMEM_SMEM_SLOW_CLOCK_VALUE,
130 SMEM_BIO_LED_BUF,
131 SMEM_SMSM_SHARED_STATE,
132 SMEM_SMSM_INT_INFO,
133 SMEM_SMSM_SLEEP_DELAY,
134 SMEM_SMSM_LIMIT_SLEEP,
135 SMEM_SLEEP_POWER_COLLAPSE_DISABLED,
136 SMEM_KEYPAD_KEYS_PRESSED,
137 SMEM_KEYPAD_STATE_UPDATED,
138 SMEM_KEYPAD_STATE_IDX,
139 SMEM_GPIO_INT,
140 SMEM_MDDI_LCD_IDX,
141 SMEM_MDDI_HOST_DRIVER_STATE,
142 SMEM_MDDI_LCD_DISP_STATE,
143 SMEM_LCD_CUR_PANEL,
144 SMEM_MARM_BOOT_SEGMENT_INFO,
145 SMEM_AARM_BOOT_SEGMENT_INFO,
146 SMEM_SLEEP_STATIC,
147 SMEM_SCORPION_FREQUENCY,
148 SMEM_SMD_PROFILES,
149 SMEM_TSSC_BUSY,
150 SMEM_HS_SUSPEND_FILTER_INFO,
151 SMEM_BATT_INFO,
152 SMEM_APPS_BOOT_MODE,
153 SMEM_VERSION_FIRST,
154 SMEM_VERSION_LAST = SMEM_VERSION_FIRST + 24,
155 SMEM_OSS_RRCASN1_BUF1,
156 SMEM_OSS_RRCASN1_BUF2,
157 SMEM_ID_VENDOR0,
158 SMEM_ID_VENDOR1,
159 SMEM_ID_VENDOR2,
160 SMEM_HW_SW_BUILD_ID,
161 SMEM_NUM_ITEMS,
162} smem_mem_type;
163
164#endif
diff --git a/drivers/staging/dream/smd/smd_qmi.c b/drivers/staging/dream/smd/smd_qmi.c
deleted file mode 100644
index 76fce5142d9e..000000000000
--- a/drivers/staging/dream/smd/smd_qmi.c
+++ /dev/null
@@ -1,851 +0,0 @@
1/* arch/arm/mach-msm/smd_qmi.c
2 *
3 * QMI Control Driver -- Manages network data connections.
4 *
5 * Copyright (C) 2007 Google, Inc.
6 * Author: Brian Swetland <swetland@google.com>
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19#include <linux/module.h>
20#include <linux/fs.h>
21#include <linux/cdev.h>
22#include <linux/device.h>
23#include <linux/sched.h>
24#include <linux/wait.h>
25#include <linux/miscdevice.h>
26#include <linux/workqueue.h>
27
28#include <linux/uaccess.h>
29#include <mach/msm_smd.h>
30
31#define QMI_CTL 0x00
32#define QMI_WDS 0x01
33#define QMI_DMS 0x02
34#define QMI_NAS 0x03
35
36#define QMI_RESULT_SUCCESS 0x0000
37#define QMI_RESULT_FAILURE 0x0001
38
39struct qmi_msg {
40 unsigned char service;
41 unsigned char client_id;
42 unsigned short txn_id;
43 unsigned short type;
44 unsigned short size;
45 unsigned char *tlv;
46};
47
48#define qmi_ctl_client_id 0
49
50#define STATE_OFFLINE 0
51#define STATE_QUERYING 1
52#define STATE_ONLINE 2
53
54struct qmi_ctxt {
55 struct miscdevice misc;
56
57 struct mutex lock;
58
59 unsigned char ctl_txn_id;
60 unsigned char wds_client_id;
61 unsigned short wds_txn_id;
62
63 unsigned wds_busy;
64 unsigned wds_handle;
65 unsigned state_dirty;
66 unsigned state;
67
68 unsigned char addr[4];
69 unsigned char mask[4];
70 unsigned char gateway[4];
71 unsigned char dns1[4];
72 unsigned char dns2[4];
73
74 smd_channel_t *ch;
75 const char *ch_name;
76
77 struct work_struct open_work;
78 struct work_struct read_work;
79};
80
81static struct qmi_ctxt *qmi_minor_to_ctxt(unsigned n);
82
83static void qmi_read_work(struct work_struct *ws);
84static void qmi_open_work(struct work_struct *work);
85
86void qmi_ctxt_init(struct qmi_ctxt *ctxt, unsigned n)
87{
88 mutex_init(&ctxt->lock);
89 INIT_WORK(&ctxt->read_work, qmi_read_work);
90 INIT_WORK(&ctxt->open_work, qmi_open_work);
91 ctxt->ctl_txn_id = 1;
92 ctxt->wds_txn_id = 1;
93 ctxt->wds_busy = 1;
94 ctxt->state = STATE_OFFLINE;
95
96}
97
98static struct workqueue_struct *qmi_wq;
99
100static int verbose = 0;
101
102/* anyone waiting for a state change waits here */
103static DECLARE_WAIT_QUEUE_HEAD(qmi_wait_queue);
104
105
106static void qmi_dump_msg(struct qmi_msg *msg, const char *prefix)
107{
108 unsigned sz, n;
109 unsigned char *x;
110
111 if (!verbose)
112 return;
113
114 printk(KERN_INFO
115 "qmi: %s: svc=%02x cid=%02x tid=%04x type=%04x size=%04x\n",
116 prefix, msg->service, msg->client_id,
117 msg->txn_id, msg->type, msg->size);
118
119 x = msg->tlv;
120 sz = msg->size;
121
122 while (sz >= 3) {
123 sz -= 3;
124
125 n = x[1] | (x[2] << 8);
126 if (n > sz)
127 break;
128
129 printk(KERN_INFO "qmi: %s: tlv: %02x %04x { ",
130 prefix, x[0], n);
131 x += 3;
132 sz -= n;
133 while (n-- > 0)
134 printk("%02x ", *x++);
135 printk("}\n");
136 }
137}
138
139int qmi_add_tlv(struct qmi_msg *msg,
140 unsigned type, unsigned size, const void *data)
141{
142 unsigned char *x = msg->tlv + msg->size;
143
144 x[0] = type;
145 x[1] = size;
146 x[2] = size >> 8;
147
148 memcpy(x + 3, data, size);
149
150 msg->size += (size + 3);
151
152 return 0;
153}
154
155/* Extract a tagged item from a qmi message buffer,
156** taking care not to overrun the buffer.
157*/
158static int qmi_get_tlv(struct qmi_msg *msg,
159 unsigned type, unsigned size, void *data)
160{
161 unsigned char *x = msg->tlv;
162 unsigned len = msg->size;
163 unsigned n;
164
165 while (len >= 3) {
166 len -= 3;
167
168 /* size of this item */
169 n = x[1] | (x[2] << 8);
170 if (n > len)
171 break;
172
173 if (x[0] == type) {
174 if (n != size)
175 return -1;
176 memcpy(data, x + 3, size);
177 return 0;
178 }
179
180 x += (n + 3);
181 len -= n;
182 }
183
184 return -1;
185}
186
187static unsigned qmi_get_status(struct qmi_msg *msg, unsigned *error)
188{
189 unsigned short status[2];
190 if (qmi_get_tlv(msg, 0x02, sizeof(status), status)) {
191 *error = 0;
192 return QMI_RESULT_FAILURE;
193 } else {
194 *error = status[1];
195 return status[0];
196 }
197}
198
199/* 0x01 <qmux-header> <payload> */
200#define QMUX_HEADER 13
201
202/* should be >= HEADER + FOOTER */
203#define QMUX_OVERHEAD 16
204
205static int qmi_send(struct qmi_ctxt *ctxt, struct qmi_msg *msg)
206{
207 unsigned char *data;
208 unsigned hlen;
209 unsigned len;
210 int r;
211
212 qmi_dump_msg(msg, "send");
213
214 if (msg->service == QMI_CTL)
215 hlen = QMUX_HEADER - 1;
216 else
217 hlen = QMUX_HEADER;
218
219 /* QMUX length is total header + total payload - IFC selector */
220 len = hlen + msg->size - 1;
221 if (len > 0xffff)
222 return -1;
223
224 data = msg->tlv - hlen;
225
226 /* prepend encap and qmux header */
227 *data++ = 0x01; /* ifc selector */
228
229 /* qmux header */
230 *data++ = len;
231 *data++ = len >> 8;
232 *data++ = 0x00; /* flags: client */
233 *data++ = msg->service;
234 *data++ = msg->client_id;
235
236 /* qmi header */
237 *data++ = 0x00; /* flags: send */
238 *data++ = msg->txn_id;
239 if (msg->service != QMI_CTL)
240 *data++ = msg->txn_id >> 8;
241
242 *data++ = msg->type;
243 *data++ = msg->type >> 8;
244 *data++ = msg->size;
245 *data++ = msg->size >> 8;
246
247 /* len + 1 takes the interface selector into account */
248 r = smd_write(ctxt->ch, msg->tlv - hlen, len + 1);
249
250 if (r != len)
251 return -1;
252 else
253 return 0;
254}
255
256static void qmi_process_ctl_msg(struct qmi_ctxt *ctxt, struct qmi_msg *msg)
257{
258 unsigned err;
259 if (msg->type == 0x0022) {
260 unsigned char n[2];
261 if (qmi_get_status(msg, &err))
262 return;
263 if (qmi_get_tlv(msg, 0x01, sizeof(n), n))
264 return;
265 if (n[0] == QMI_WDS) {
266 printk(KERN_INFO
267 "qmi: ctl: wds use client_id 0x%02x\n", n[1]);
268 ctxt->wds_client_id = n[1];
269 ctxt->wds_busy = 0;
270 }
271 }
272}
273
274static int qmi_network_get_profile(struct qmi_ctxt *ctxt);
275
276static void swapaddr(unsigned char *src, unsigned char *dst)
277{
278 dst[0] = src[3];
279 dst[1] = src[2];
280 dst[2] = src[1];
281 dst[3] = src[0];
282}
283
284static unsigned char zero[4];
285static void qmi_read_runtime_profile(struct qmi_ctxt *ctxt, struct qmi_msg *msg)
286{
287 unsigned char tmp[4];
288 unsigned r;
289
290 r = qmi_get_tlv(msg, 0x1e, 4, tmp);
291 swapaddr(r ? zero : tmp, ctxt->addr);
292 r = qmi_get_tlv(msg, 0x21, 4, tmp);
293 swapaddr(r ? zero : tmp, ctxt->mask);
294 r = qmi_get_tlv(msg, 0x20, 4, tmp);
295 swapaddr(r ? zero : tmp, ctxt->gateway);
296 r = qmi_get_tlv(msg, 0x15, 4, tmp);
297 swapaddr(r ? zero : tmp, ctxt->dns1);
298 r = qmi_get_tlv(msg, 0x16, 4, tmp);
299 swapaddr(r ? zero : tmp, ctxt->dns2);
300}
301
302static void qmi_process_unicast_wds_msg(struct qmi_ctxt *ctxt,
303 struct qmi_msg *msg)
304{
305 unsigned err;
306 switch (msg->type) {
307 case 0x0021:
308 if (qmi_get_status(msg, &err)) {
309 printk(KERN_ERR
310 "qmi: wds: network stop failed (%04x)\n", err);
311 } else {
312 printk(KERN_INFO
313 "qmi: wds: network stopped\n");
314 ctxt->state = STATE_OFFLINE;
315 ctxt->state_dirty = 1;
316 }
317 break;
318 case 0x0020:
319 if (qmi_get_status(msg, &err)) {
320 printk(KERN_ERR
321 "qmi: wds: network start failed (%04x)\n", err);
322 } else if (qmi_get_tlv(msg, 0x01, sizeof(ctxt->wds_handle), &ctxt->wds_handle)) {
323 printk(KERN_INFO
324 "qmi: wds no handle?\n");
325 } else {
326 printk(KERN_INFO
327 "qmi: wds: got handle 0x%08x\n",
328 ctxt->wds_handle);
329 }
330 break;
331 case 0x002D:
332 printk("qmi: got network profile\n");
333 if (ctxt->state == STATE_QUERYING) {
334 qmi_read_runtime_profile(ctxt, msg);
335 ctxt->state = STATE_ONLINE;
336 ctxt->state_dirty = 1;
337 }
338 break;
339 default:
340 printk(KERN_ERR "qmi: unknown msg type 0x%04x\n", msg->type);
341 }
342 ctxt->wds_busy = 0;
343}
344
345static void qmi_process_broadcast_wds_msg(struct qmi_ctxt *ctxt,
346 struct qmi_msg *msg)
347{
348 if (msg->type == 0x0022) {
349 unsigned char n[2];
350 if (qmi_get_tlv(msg, 0x01, sizeof(n), n))
351 return;
352 switch (n[0]) {
353 case 1:
354 printk(KERN_INFO "qmi: wds: DISCONNECTED\n");
355 ctxt->state = STATE_OFFLINE;
356 ctxt->state_dirty = 1;
357 break;
358 case 2:
359 printk(KERN_INFO "qmi: wds: CONNECTED\n");
360 ctxt->state = STATE_QUERYING;
361 ctxt->state_dirty = 1;
362 qmi_network_get_profile(ctxt);
363 break;
364 case 3:
365 printk(KERN_INFO "qmi: wds: SUSPENDED\n");
366 ctxt->state = STATE_OFFLINE;
367 ctxt->state_dirty = 1;
368 }
369 } else {
370 printk(KERN_ERR "qmi: unknown bcast msg type 0x%04x\n", msg->type);
371 }
372}
373
374static void qmi_process_wds_msg(struct qmi_ctxt *ctxt,
375 struct qmi_msg *msg)
376{
377 printk(KERN_INFO "wds: %04x @ %02x\n", msg->type, msg->client_id);
378 if (msg->client_id == ctxt->wds_client_id) {
379 qmi_process_unicast_wds_msg(ctxt, msg);
380 } else if (msg->client_id == 0xff) {
381 qmi_process_broadcast_wds_msg(ctxt, msg);
382 } else {
383 printk(KERN_ERR
384 "qmi_process_wds_msg client id 0x%02x unknown\n",
385 msg->client_id);
386 }
387}
388
389static void qmi_process_qmux(struct qmi_ctxt *ctxt,
390 unsigned char *buf, unsigned sz)
391{
392 struct qmi_msg msg;
393
394 /* require a full header */
395 if (sz < 5)
396 return;
397
398 /* require a size that matches the buffer size */
399 if (sz != (buf[0] | (buf[1] << 8)))
400 return;
401
402 /* only messages from a service (bit7=1) are allowed */
403 if (buf[2] != 0x80)
404 return;
405
406 msg.service = buf[3];
407 msg.client_id = buf[4];
408
409 /* annoyingly, CTL messages have a shorter TID */
410 if (buf[3] == 0) {
411 if (sz < 7)
412 return;
413 msg.txn_id = buf[6];
414 buf += 7;
415 sz -= 7;
416 } else {
417 if (sz < 8)
418 return;
419 msg.txn_id = buf[6] | (buf[7] << 8);
420 buf += 8;
421 sz -= 8;
422 }
423
424 /* no type and size!? */
425 if (sz < 4)
426 return;
427 sz -= 4;
428
429 msg.type = buf[0] | (buf[1] << 8);
430 msg.size = buf[2] | (buf[3] << 8);
431 msg.tlv = buf + 4;
432
433 if (sz != msg.size)
434 return;
435
436 qmi_dump_msg(&msg, "recv");
437
438 mutex_lock(&ctxt->lock);
439 switch (msg.service) {
440 case QMI_CTL:
441 qmi_process_ctl_msg(ctxt, &msg);
442 break;
443 case QMI_WDS:
444 qmi_process_wds_msg(ctxt, &msg);
445 break;
446 default:
447 printk(KERN_ERR "qmi: msg from unknown svc 0x%02x\n",
448 msg.service);
449 break;
450 }
451 mutex_unlock(&ctxt->lock);
452 wake_up(&qmi_wait_queue);
453}
454
455#define QMI_MAX_PACKET (256 + QMUX_OVERHEAD)
456
457static void qmi_read_work(struct work_struct *ws)
458{
459 struct qmi_ctxt *ctxt = container_of(ws, struct qmi_ctxt, read_work);
460 struct smd_channel *ch = ctxt->ch;
461 unsigned char buf[QMI_MAX_PACKET];
462 int sz;
463
464 for (;;) {
465 sz = smd_cur_packet_size(ch);
466 if (sz == 0)
467 break;
468 if (sz < smd_read_avail(ch))
469 break;
470 if (sz > QMI_MAX_PACKET) {
471 smd_read(ch, 0, sz);
472 continue;
473 }
474 if (smd_read(ch, buf, sz) != sz) {
475 printk(KERN_ERR "qmi: not enough data?!\n");
476 continue;
477 }
478
479 /* interface selector must be 1 */
480 if (buf[0] != 0x01)
481 continue;
482
483 qmi_process_qmux(ctxt, buf + 1, sz - 1);
484 }
485}
486
487static int qmi_request_wds_cid(struct qmi_ctxt *ctxt);
488
489static void qmi_open_work(struct work_struct *ws)
490{
491 struct qmi_ctxt *ctxt = container_of(ws, struct qmi_ctxt, open_work);
492 mutex_lock(&ctxt->lock);
493 qmi_request_wds_cid(ctxt);
494 mutex_unlock(&ctxt->lock);
495}
496
497static void qmi_notify(void *priv, unsigned event)
498{
499 struct qmi_ctxt *ctxt = priv;
500
501 switch (event) {
502 case SMD_EVENT_DATA: {
503 int sz;
504 sz = smd_cur_packet_size(ctxt->ch);
505 if ((sz > 0) && (sz <= smd_read_avail(ctxt->ch)))
506 queue_work(qmi_wq, &ctxt->read_work);
507 break;
508 }
509 case SMD_EVENT_OPEN:
510 printk(KERN_INFO "qmi: smd opened\n");
511 queue_work(qmi_wq, &ctxt->open_work);
512 break;
513 case SMD_EVENT_CLOSE:
514 printk(KERN_INFO "qmi: smd closed\n");
515 break;
516 }
517}
518
519static int qmi_request_wds_cid(struct qmi_ctxt *ctxt)
520{
521 unsigned char data[64 + QMUX_OVERHEAD];
522 struct qmi_msg msg;
523 unsigned char n;
524
525 msg.service = QMI_CTL;
526 msg.client_id = qmi_ctl_client_id;
527 msg.txn_id = ctxt->ctl_txn_id;
528 msg.type = 0x0022;
529 msg.size = 0;
530 msg.tlv = data + QMUX_HEADER;
531
532 ctxt->ctl_txn_id += 2;
533
534 n = QMI_WDS;
535 qmi_add_tlv(&msg, 0x01, 0x01, &n);
536
537 return qmi_send(ctxt, &msg);
538}
539
540static int qmi_network_get_profile(struct qmi_ctxt *ctxt)
541{
542 unsigned char data[96 + QMUX_OVERHEAD];
543 struct qmi_msg msg;
544
545 msg.service = QMI_WDS;
546 msg.client_id = ctxt->wds_client_id;
547 msg.txn_id = ctxt->wds_txn_id;
548 msg.type = 0x002D;
549 msg.size = 0;
550 msg.tlv = data + QMUX_HEADER;
551
552 ctxt->wds_txn_id += 2;
553
554 return qmi_send(ctxt, &msg);
555}
556
557static int qmi_network_up(struct qmi_ctxt *ctxt, char *apn)
558{
559 unsigned char data[96 + QMUX_OVERHEAD];
560 struct qmi_msg msg;
561 char *auth_type;
562 char *user;
563 char *pass;
564
565 for (user = apn; *user; user++) {
566 if (*user == ' ') {
567 *user++ = 0;
568 break;
569 }
570 }
571 for (pass = user; *pass; pass++) {
572 if (*pass == ' ') {
573 *pass++ = 0;
574 break;
575 }
576 }
577
578 for (auth_type = pass; *auth_type; auth_type++) {
579 if (*auth_type == ' ') {
580 *auth_type++ = 0;
581 break;
582 }
583 }
584
585 msg.service = QMI_WDS;
586 msg.client_id = ctxt->wds_client_id;
587 msg.txn_id = ctxt->wds_txn_id;
588 msg.type = 0x0020;
589 msg.size = 0;
590 msg.tlv = data + QMUX_HEADER;
591
592 ctxt->wds_txn_id += 2;
593
594 qmi_add_tlv(&msg, 0x14, strlen(apn), apn);
595 if (*auth_type)
596 qmi_add_tlv(&msg, 0x16, strlen(auth_type), auth_type);
597 if (*user) {
598 if (!*auth_type) {
599 unsigned char x;
600 x = 3;
601 qmi_add_tlv(&msg, 0x16, 1, &x);
602 }
603 qmi_add_tlv(&msg, 0x17, strlen(user), user);
604 if (*pass)
605 qmi_add_tlv(&msg, 0x18, strlen(pass), pass);
606 }
607 return qmi_send(ctxt, &msg);
608}
609
610static int qmi_network_down(struct qmi_ctxt *ctxt)
611{
612 unsigned char data[16 + QMUX_OVERHEAD];
613 struct qmi_msg msg;
614
615 msg.service = QMI_WDS;
616 msg.client_id = ctxt->wds_client_id;
617 msg.txn_id = ctxt->wds_txn_id;
618 msg.type = 0x0021;
619 msg.size = 0;
620 msg.tlv = data + QMUX_HEADER;
621
622 ctxt->wds_txn_id += 2;
623
624 qmi_add_tlv(&msg, 0x01, sizeof(ctxt->wds_handle), &ctxt->wds_handle);
625
626 return qmi_send(ctxt, &msg);
627}
628
629static int qmi_print_state(struct qmi_ctxt *ctxt, char *buf, int max)
630{
631 int i;
632 char *statename;
633
634 if (ctxt->state == STATE_ONLINE) {
635 statename = "up";
636 } else if (ctxt->state == STATE_OFFLINE) {
637 statename = "down";
638 } else {
639 statename = "busy";
640 }
641
642 i = scnprintf(buf, max, "STATE=%s\n", statename);
643 i += scnprintf(buf + i, max - i, "CID=%d\n", ctxt->wds_client_id);
644
645 if (ctxt->state != STATE_ONLINE)
646 return i;
647
648 i += scnprintf(buf + i, max - i, "ADDR=%d.%d.%d.%d\n",
649 ctxt->addr[0], ctxt->addr[1], ctxt->addr[2], ctxt->addr[3]);
650 i += scnprintf(buf + i, max - i, "MASK=%d.%d.%d.%d\n",
651 ctxt->mask[0], ctxt->mask[1], ctxt->mask[2], ctxt->mask[3]);
652 i += scnprintf(buf + i, max - i, "GATEWAY=%d.%d.%d.%d\n",
653 ctxt->gateway[0], ctxt->gateway[1], ctxt->gateway[2],
654 ctxt->gateway[3]);
655 i += scnprintf(buf + i, max - i, "DNS1=%d.%d.%d.%d\n",
656 ctxt->dns1[0], ctxt->dns1[1], ctxt->dns1[2], ctxt->dns1[3]);
657 i += scnprintf(buf + i, max - i, "DNS2=%d.%d.%d.%d\n",
658 ctxt->dns2[0], ctxt->dns2[1], ctxt->dns2[2], ctxt->dns2[3]);
659
660 return i;
661}
662
663static ssize_t qmi_read(struct file *fp, char __user *buf,
664 size_t count, loff_t *pos)
665{
666 struct qmi_ctxt *ctxt = fp->private_data;
667 char msg[256];
668 int len;
669 int r;
670
671 mutex_lock(&ctxt->lock);
672 for (;;) {
673 if (ctxt->state_dirty) {
674 ctxt->state_dirty = 0;
675 len = qmi_print_state(ctxt, msg, 256);
676 break;
677 }
678 mutex_unlock(&ctxt->lock);
679 r = wait_event_interruptible(qmi_wait_queue, ctxt->state_dirty);
680 if (r < 0)
681 return r;
682 mutex_lock(&ctxt->lock);
683 }
684 mutex_unlock(&ctxt->lock);
685
686 if (len > count)
687 len = count;
688
689 if (copy_to_user(buf, msg, len))
690 return -EFAULT;
691
692 return len;
693}
694
695
696static ssize_t qmi_write(struct file *fp, const char __user *buf,
697 size_t count, loff_t *pos)
698{
699 struct qmi_ctxt *ctxt = fp->private_data;
700 unsigned char cmd[64];
701 int len;
702 int r;
703
704 if (count < 1)
705 return 0;
706
707 len = count > 63 ? 63 : count;
708
709 if (copy_from_user(cmd, buf, len))
710 return -EFAULT;
711
712 cmd[len] = 0;
713
714 /* lazy */
715 if (cmd[len-1] == '\n') {
716 cmd[len-1] = 0;
717 len--;
718 }
719
720 if (!strncmp(cmd, "verbose", 7)) {
721 verbose = 1;
722 } else if (!strncmp(cmd, "terse", 5)) {
723 verbose = 0;
724 } else if (!strncmp(cmd, "poll", 4)) {
725 ctxt->state_dirty = 1;
726 wake_up(&qmi_wait_queue);
727 } else if (!strncmp(cmd, "down", 4)) {
728retry_down:
729 mutex_lock(&ctxt->lock);
730 if (ctxt->wds_busy) {
731 mutex_unlock(&ctxt->lock);
732 r = wait_event_interruptible(qmi_wait_queue, !ctxt->wds_busy);
733 if (r < 0)
734 return r;
735 goto retry_down;
736 }
737 ctxt->wds_busy = 1;
738 qmi_network_down(ctxt);
739 mutex_unlock(&ctxt->lock);
740 } else if (!strncmp(cmd, "up:", 3)) {
741retry_up:
742 mutex_lock(&ctxt->lock);
743 if (ctxt->wds_busy) {
744 mutex_unlock(&ctxt->lock);
745 r = wait_event_interruptible(qmi_wait_queue, !ctxt->wds_busy);
746 if (r < 0)
747 return r;
748 goto retry_up;
749 }
750 ctxt->wds_busy = 1;
751 qmi_network_up(ctxt, cmd+3);
752 mutex_unlock(&ctxt->lock);
753 } else {
754 return -EINVAL;
755 }
756
757 return count;
758}
759
760static int qmi_open(struct inode *ip, struct file *fp)
761{
762 struct qmi_ctxt *ctxt = qmi_minor_to_ctxt(MINOR(ip->i_rdev));
763 int r = 0;
764
765 if (!ctxt) {
766 printk(KERN_ERR "unknown qmi misc %d\n", MINOR(ip->i_rdev));
767 return -ENODEV;
768 }
769
770 fp->private_data = ctxt;
771
772 mutex_lock(&ctxt->lock);
773 if (ctxt->ch == 0)
774 r = smd_open(ctxt->ch_name, &ctxt->ch, ctxt, qmi_notify);
775 if (r == 0)
776 wake_up(&qmi_wait_queue);
777 mutex_unlock(&ctxt->lock);
778
779 return r;
780}
781
782static int qmi_release(struct inode *ip, struct file *fp)
783{
784 return 0;
785}
786
787static struct file_operations qmi_fops = {
788 .owner = THIS_MODULE,
789 .read = qmi_read,
790 .write = qmi_write,
791 .open = qmi_open,
792 .release = qmi_release,
793};
794
795static struct qmi_ctxt qmi_device0 = {
796 .ch_name = "SMD_DATA5_CNTL",
797 .misc = {
798 .minor = MISC_DYNAMIC_MINOR,
799 .name = "qmi0",
800 .fops = &qmi_fops,
801 }
802};
803static struct qmi_ctxt qmi_device1 = {
804 .ch_name = "SMD_DATA6_CNTL",
805 .misc = {
806 .minor = MISC_DYNAMIC_MINOR,
807 .name = "qmi1",
808 .fops = &qmi_fops,
809 }
810};
811static struct qmi_ctxt qmi_device2 = {
812 .ch_name = "SMD_DATA7_CNTL",
813 .misc = {
814 .minor = MISC_DYNAMIC_MINOR,
815 .name = "qmi2",
816 .fops = &qmi_fops,
817 }
818};
819
820static struct qmi_ctxt *qmi_minor_to_ctxt(unsigned n)
821{
822 if (n == qmi_device0.misc.minor)
823 return &qmi_device0;
824 if (n == qmi_device1.misc.minor)
825 return &qmi_device1;
826 if (n == qmi_device2.misc.minor)
827 return &qmi_device2;
828 return 0;
829}
830
831static int __init qmi_init(void)
832{
833 int ret;
834
835 qmi_wq = create_singlethread_workqueue("qmi");
836 if (qmi_wq == 0)
837 return -ENOMEM;
838
839 qmi_ctxt_init(&qmi_device0, 0);
840 qmi_ctxt_init(&qmi_device1, 1);
841 qmi_ctxt_init(&qmi_device2, 2);
842
843 ret = misc_register(&qmi_device0.misc);
844 if (ret == 0)
845 ret = misc_register(&qmi_device1.misc);
846 if (ret == 0)
847 ret = misc_register(&qmi_device2.misc);
848 return ret;
849}
850
851module_init(qmi_init);
diff --git a/drivers/staging/dream/smd/smd_rpcrouter.c b/drivers/staging/dream/smd/smd_rpcrouter.c
deleted file mode 100644
index 8744a6e499cb..000000000000
--- a/drivers/staging/dream/smd/smd_rpcrouter.c
+++ /dev/null
@@ -1,1261 +0,0 @@
1/* arch/arm/mach-msm/smd_rpcrouter.c
2 *
3 * Copyright (C) 2007 Google, Inc.
4 * Copyright (c) 2007-2009 QUALCOMM Incorporated.
5 * Author: San Mehat <san@android.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18/* TODO: handle cases where smd_write() will tempfail due to full fifo */
19/* TODO: thread priority? schedule a work to bump it? */
20/* TODO: maybe make server_list_lock a mutex */
21/* TODO: pool fragments to avoid kmalloc/kfree churn */
22
23#include <linux/module.h>
24#include <linux/kernel.h>
25#include <linux/string.h>
26#include <linux/errno.h>
27#include <linux/cdev.h>
28#include <linux/init.h>
29#include <linux/device.h>
30#include <linux/types.h>
31#include <linux/delay.h>
32#include <linux/fs.h>
33#include <linux/err.h>
34#include <linux/sched.h>
35#include <linux/poll.h>
36#include <linux/slab.h>
37#include <asm/uaccess.h>
38#include <asm/byteorder.h>
39#include <linux/platform_device.h>
40#include <linux/uaccess.h>
41
42#include <mach/msm_smd.h>
43#include "smd_rpcrouter.h"
44
45#define TRACE_R2R_MSG 0
46#define TRACE_R2R_RAW 0
47#define TRACE_RPC_MSG 0
48#define TRACE_NOTIFY_MSG 0
49
50#define MSM_RPCROUTER_DEBUG 0
51#define MSM_RPCROUTER_DEBUG_PKT 0
52#define MSM_RPCROUTER_R2R_DEBUG 0
53#define DUMP_ALL_RECEIVED_HEADERS 0
54
55#define DIAG(x...) printk("[RR] ERROR " x)
56
57#if MSM_RPCROUTER_DEBUG
58#define D(x...) printk(x)
59#else
60#define D(x...) do {} while (0)
61#endif
62
63#if TRACE_R2R_MSG
64#define RR(x...) printk("[RR] "x)
65#else
66#define RR(x...) do {} while (0)
67#endif
68
69#if TRACE_RPC_MSG
70#define IO(x...) printk("[RPC] "x)
71#else
72#define IO(x...) do {} while (0)
73#endif
74
75#if TRACE_NOTIFY_MSG
76#define NTFY(x...) printk(KERN_ERR "[NOTIFY] "x)
77#else
78#define NTFY(x...) do {} while (0)
79#endif
80
81static LIST_HEAD(local_endpoints);
82static LIST_HEAD(remote_endpoints);
83
84static LIST_HEAD(server_list);
85
86static smd_channel_t *smd_channel;
87static int initialized;
88static wait_queue_head_t newserver_wait;
89static wait_queue_head_t smd_wait;
90
91static DEFINE_SPINLOCK(local_endpoints_lock);
92static DEFINE_SPINLOCK(remote_endpoints_lock);
93static DEFINE_SPINLOCK(server_list_lock);
94static DEFINE_SPINLOCK(smd_lock);
95
96static struct workqueue_struct *rpcrouter_workqueue;
97static int rpcrouter_need_len;
98
99static atomic_t next_xid = ATOMIC_INIT(1);
100static uint8_t next_pacmarkid;
101
102static void do_read_data(struct work_struct *work);
103static void do_create_pdevs(struct work_struct *work);
104static void do_create_rpcrouter_pdev(struct work_struct *work);
105
106static DECLARE_WORK(work_read_data, do_read_data);
107static DECLARE_WORK(work_create_pdevs, do_create_pdevs);
108static DECLARE_WORK(work_create_rpcrouter_pdev, do_create_rpcrouter_pdev);
109
110#define RR_STATE_IDLE 0
111#define RR_STATE_HEADER 1
112#define RR_STATE_BODY 2
113#define RR_STATE_ERROR 3
114
115struct rr_context {
116 struct rr_packet *pkt;
117 uint8_t *ptr;
118 uint32_t state; /* current assembly state */
119 uint32_t count; /* bytes needed in this state */
120};
121
122static struct rr_context the_rr_context;
123
124static struct platform_device rpcrouter_pdev = {
125 .name = "oncrpc_router",
126 .id = -1,
127};
128
129
130static int rpcrouter_send_control_msg(union rr_control_msg *msg)
131{
132 struct rr_header hdr;
133 unsigned long flags;
134 int need;
135
136 if (!(msg->cmd == RPCROUTER_CTRL_CMD_HELLO) && !initialized) {
137 printk(KERN_ERR "rpcrouter_send_control_msg(): Warning, "
138 "router not initialized\n");
139 return -EINVAL;
140 }
141
142 hdr.version = RPCROUTER_VERSION;
143 hdr.type = msg->cmd;
144 hdr.src_pid = RPCROUTER_PID_LOCAL;
145 hdr.src_cid = RPCROUTER_ROUTER_ADDRESS;
146 hdr.confirm_rx = 0;
147 hdr.size = sizeof(*msg);
148 hdr.dst_pid = 0;
149 hdr.dst_cid = RPCROUTER_ROUTER_ADDRESS;
150
151 /* TODO: what if channel is full? */
152
153 need = sizeof(hdr) + hdr.size;
154 spin_lock_irqsave(&smd_lock, flags);
155 while (smd_write_avail(smd_channel) < need) {
156 spin_unlock_irqrestore(&smd_lock, flags);
157 msleep(250);
158 spin_lock_irqsave(&smd_lock, flags);
159 }
160 smd_write(smd_channel, &hdr, sizeof(hdr));
161 smd_write(smd_channel, msg, hdr.size);
162 spin_unlock_irqrestore(&smd_lock, flags);
163 return 0;
164}
165
166static struct rr_server *rpcrouter_create_server(uint32_t pid,
167 uint32_t cid,
168 uint32_t prog,
169 uint32_t ver)
170{
171 struct rr_server *server;
172 unsigned long flags;
173 int rc;
174
175 server = kmalloc(sizeof(struct rr_server), GFP_KERNEL);
176 if (!server)
177 return ERR_PTR(-ENOMEM);
178
179 memset(server, 0, sizeof(struct rr_server));
180 server->pid = pid;
181 server->cid = cid;
182 server->prog = prog;
183 server->vers = ver;
184
185 spin_lock_irqsave(&server_list_lock, flags);
186 list_add_tail(&server->list, &server_list);
187 spin_unlock_irqrestore(&server_list_lock, flags);
188
189 if (pid == RPCROUTER_PID_REMOTE) {
190 rc = msm_rpcrouter_create_server_cdev(server);
191 if (rc < 0)
192 goto out_fail;
193 }
194 return server;
195out_fail:
196 spin_lock_irqsave(&server_list_lock, flags);
197 list_del(&server->list);
198 spin_unlock_irqrestore(&server_list_lock, flags);
199 kfree(server);
200 return ERR_PTR(rc);
201}
202
203static void rpcrouter_destroy_server(struct rr_server *server)
204{
205 unsigned long flags;
206
207 spin_lock_irqsave(&server_list_lock, flags);
208 list_del(&server->list);
209 spin_unlock_irqrestore(&server_list_lock, flags);
210 device_destroy(msm_rpcrouter_class, server->device_number);
211 kfree(server);
212}
213
214static struct rr_server *rpcrouter_lookup_server(uint32_t prog, uint32_t ver)
215{
216 struct rr_server *server;
217 unsigned long flags;
218
219 spin_lock_irqsave(&server_list_lock, flags);
220 list_for_each_entry(server, &server_list, list) {
221 if (server->prog == prog
222 && server->vers == ver) {
223 spin_unlock_irqrestore(&server_list_lock, flags);
224 return server;
225 }
226 }
227 spin_unlock_irqrestore(&server_list_lock, flags);
228 return NULL;
229}
230
231static struct rr_server *rpcrouter_lookup_server_by_dev(dev_t dev)
232{
233 struct rr_server *server;
234 unsigned long flags;
235
236 spin_lock_irqsave(&server_list_lock, flags);
237 list_for_each_entry(server, &server_list, list) {
238 if (server->device_number == dev) {
239 spin_unlock_irqrestore(&server_list_lock, flags);
240 return server;
241 }
242 }
243 spin_unlock_irqrestore(&server_list_lock, flags);
244 return NULL;
245}
246
247struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev)
248{
249 struct msm_rpc_endpoint *ept;
250 unsigned long flags;
251
252 ept = kmalloc(sizeof(struct msm_rpc_endpoint), GFP_KERNEL);
253 if (!ept)
254 return NULL;
255 memset(ept, 0, sizeof(struct msm_rpc_endpoint));
256
257 /* mark no reply outstanding */
258 ept->reply_pid = 0xffffffff;
259
260 ept->cid = (uint32_t) ept;
261 ept->pid = RPCROUTER_PID_LOCAL;
262 ept->dev = dev;
263
264 if ((dev != msm_rpcrouter_devno) && (dev != MKDEV(0, 0))) {
265 struct rr_server *srv;
266 /*
267 * This is a userspace client which opened
268 * a program/ver devicenode. Bind the client
269 * to that destination
270 */
271 srv = rpcrouter_lookup_server_by_dev(dev);
272 /* TODO: bug? really? */
273 BUG_ON(!srv);
274
275 ept->dst_pid = srv->pid;
276 ept->dst_cid = srv->cid;
277 ept->dst_prog = cpu_to_be32(srv->prog);
278 ept->dst_vers = cpu_to_be32(srv->vers);
279
280 D("Creating local ept %p @ %08x:%08x\n", ept, srv->prog, srv->vers);
281 } else {
282 /* mark not connected */
283 ept->dst_pid = 0xffffffff;
284 D("Creating a master local ept %p\n", ept);
285 }
286
287 init_waitqueue_head(&ept->wait_q);
288 INIT_LIST_HEAD(&ept->read_q);
289 spin_lock_init(&ept->read_q_lock);
290 INIT_LIST_HEAD(&ept->incomplete);
291
292 spin_lock_irqsave(&local_endpoints_lock, flags);
293 list_add_tail(&ept->list, &local_endpoints);
294 spin_unlock_irqrestore(&local_endpoints_lock, flags);
295 return ept;
296}
297
298int msm_rpcrouter_destroy_local_endpoint(struct msm_rpc_endpoint *ept)
299{
300 int rc;
301 union rr_control_msg msg;
302
303 msg.cmd = RPCROUTER_CTRL_CMD_REMOVE_CLIENT;
304 msg.cli.pid = ept->pid;
305 msg.cli.cid = ept->cid;
306
307 RR("x REMOVE_CLIENT id=%d:%08x\n", ept->pid, ept->cid);
308 rc = rpcrouter_send_control_msg(&msg);
309 if (rc < 0)
310 return rc;
311
312 list_del(&ept->list);
313 kfree(ept);
314 return 0;
315}
316
317static int rpcrouter_create_remote_endpoint(uint32_t cid)
318{
319 struct rr_remote_endpoint *new_c;
320 unsigned long flags;
321
322 new_c = kmalloc(sizeof(struct rr_remote_endpoint), GFP_KERNEL);
323 if (!new_c)
324 return -ENOMEM;
325 memset(new_c, 0, sizeof(struct rr_remote_endpoint));
326
327 new_c->cid = cid;
328 new_c->pid = RPCROUTER_PID_REMOTE;
329 init_waitqueue_head(&new_c->quota_wait);
330 spin_lock_init(&new_c->quota_lock);
331
332 spin_lock_irqsave(&remote_endpoints_lock, flags);
333 list_add_tail(&new_c->list, &remote_endpoints);
334 spin_unlock_irqrestore(&remote_endpoints_lock, flags);
335 return 0;
336}
337
338static struct msm_rpc_endpoint *rpcrouter_lookup_local_endpoint(uint32_t cid)
339{
340 struct msm_rpc_endpoint *ept;
341 unsigned long flags;
342
343 spin_lock_irqsave(&local_endpoints_lock, flags);
344 list_for_each_entry(ept, &local_endpoints, list) {
345 if (ept->cid == cid) {
346 spin_unlock_irqrestore(&local_endpoints_lock, flags);
347 return ept;
348 }
349 }
350 spin_unlock_irqrestore(&local_endpoints_lock, flags);
351 return NULL;
352}
353
354static struct rr_remote_endpoint *rpcrouter_lookup_remote_endpoint(uint32_t cid)
355{
356 struct rr_remote_endpoint *ept;
357 unsigned long flags;
358
359 spin_lock_irqsave(&remote_endpoints_lock, flags);
360 list_for_each_entry(ept, &remote_endpoints, list) {
361 if (ept->cid == cid) {
362 spin_unlock_irqrestore(&remote_endpoints_lock, flags);
363 return ept;
364 }
365 }
366 spin_unlock_irqrestore(&remote_endpoints_lock, flags);
367 return NULL;
368}
369
370static int process_control_msg(union rr_control_msg *msg, int len)
371{
372 union rr_control_msg ctl;
373 struct rr_server *server;
374 struct rr_remote_endpoint *r_ept;
375 int rc = 0;
376 unsigned long flags;
377
378 if (len != sizeof(*msg)) {
379 printk(KERN_ERR "rpcrouter: r2r msg size %d != %d\n",
380 len, sizeof(*msg));
381 return -EINVAL;
382 }
383
384 switch (msg->cmd) {
385 case RPCROUTER_CTRL_CMD_HELLO:
386 RR("o HELLO\n");
387
388 RR("x HELLO\n");
389 memset(&ctl, 0, sizeof(ctl));
390 ctl.cmd = RPCROUTER_CTRL_CMD_HELLO;
391 rpcrouter_send_control_msg(&ctl);
392
393 initialized = 1;
394
395 /* Send list of servers one at a time */
396 ctl.cmd = RPCROUTER_CTRL_CMD_NEW_SERVER;
397
398 /* TODO: long time to hold a spinlock... */
399 spin_lock_irqsave(&server_list_lock, flags);
400 list_for_each_entry(server, &server_list, list) {
401 ctl.srv.pid = server->pid;
402 ctl.srv.cid = server->cid;
403 ctl.srv.prog = server->prog;
404 ctl.srv.vers = server->vers;
405
406 RR("x NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
407 server->pid, server->cid,
408 server->prog, server->vers);
409
410 rpcrouter_send_control_msg(&ctl);
411 }
412 spin_unlock_irqrestore(&server_list_lock, flags);
413
414 queue_work(rpcrouter_workqueue, &work_create_rpcrouter_pdev);
415 break;
416
417 case RPCROUTER_CTRL_CMD_RESUME_TX:
418 RR("o RESUME_TX id=%d:%08x\n", msg->cli.pid, msg->cli.cid);
419
420 r_ept = rpcrouter_lookup_remote_endpoint(msg->cli.cid);
421 if (!r_ept) {
422 printk(KERN_ERR
423 "rpcrouter: Unable to resume client\n");
424 break;
425 }
426 spin_lock_irqsave(&r_ept->quota_lock, flags);
427 r_ept->tx_quota_cntr = 0;
428 spin_unlock_irqrestore(&r_ept->quota_lock, flags);
429 wake_up(&r_ept->quota_wait);
430 break;
431
432 case RPCROUTER_CTRL_CMD_NEW_SERVER:
433 RR("o NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
434 msg->srv.pid, msg->srv.cid, msg->srv.prog, msg->srv.vers);
435
436 server = rpcrouter_lookup_server(msg->srv.prog, msg->srv.vers);
437
438 if (!server) {
439 server = rpcrouter_create_server(
440 msg->srv.pid, msg->srv.cid,
441 msg->srv.prog, msg->srv.vers);
442 if (!server)
443 return -ENOMEM;
444 /*
445 * XXX: Verify that its okay to add the
446 * client to our remote client list
447 * if we get a NEW_SERVER notification
448 */
449 if (!rpcrouter_lookup_remote_endpoint(msg->srv.cid)) {
450 rc = rpcrouter_create_remote_endpoint(
451 msg->srv.cid);
452 if (rc < 0)
453 printk(KERN_ERR
454 "rpcrouter:Client create"
455 "error (%d)\n", rc);
456 }
457 schedule_work(&work_create_pdevs);
458 wake_up(&newserver_wait);
459 } else {
460 if ((server->pid == msg->srv.pid) &&
461 (server->cid == msg->srv.cid)) {
462 printk(KERN_ERR "rpcrouter: Duplicate svr\n");
463 } else {
464 server->pid = msg->srv.pid;
465 server->cid = msg->srv.cid;
466 }
467 }
468 break;
469
470 case RPCROUTER_CTRL_CMD_REMOVE_SERVER:
471 RR("o REMOVE_SERVER prog=%08x:%d\n",
472 msg->srv.prog, msg->srv.vers);
473 server = rpcrouter_lookup_server(msg->srv.prog, msg->srv.vers);
474 if (server)
475 rpcrouter_destroy_server(server);
476 break;
477
478 case RPCROUTER_CTRL_CMD_REMOVE_CLIENT:
479 RR("o REMOVE_CLIENT id=%d:%08x\n", msg->cli.pid, msg->cli.cid);
480 if (msg->cli.pid != RPCROUTER_PID_REMOTE) {
481 printk(KERN_ERR
482 "rpcrouter: Denying remote removal of "
483 "local client\n");
484 break;
485 }
486 r_ept = rpcrouter_lookup_remote_endpoint(msg->cli.cid);
487 if (r_ept) {
488 spin_lock_irqsave(&remote_endpoints_lock, flags);
489 list_del(&r_ept->list);
490 spin_unlock_irqrestore(&remote_endpoints_lock, flags);
491 kfree(r_ept);
492 }
493
494 /* Notify local clients of this event */
495 printk(KERN_ERR "rpcrouter: LOCAL NOTIFICATION NOT IMP\n");
496 rc = -ENOSYS;
497
498 break;
499 default:
500 RR("o UNKNOWN(%08x)\n", msg->cmd);
501 rc = -ENOSYS;
502 }
503
504 return rc;
505}
506
507static void do_create_rpcrouter_pdev(struct work_struct *work)
508{
509 platform_device_register(&rpcrouter_pdev);
510}
511
512static void do_create_pdevs(struct work_struct *work)
513{
514 unsigned long flags;
515 struct rr_server *server;
516
517 /* TODO: race if destroyed while being registered */
518 spin_lock_irqsave(&server_list_lock, flags);
519 list_for_each_entry(server, &server_list, list) {
520 if (server->pid == RPCROUTER_PID_REMOTE) {
521 if (server->pdev_name[0] == 0) {
522 spin_unlock_irqrestore(&server_list_lock,
523 flags);
524 msm_rpcrouter_create_server_pdev(server);
525 schedule_work(&work_create_pdevs);
526 return;
527 }
528 }
529 }
530 spin_unlock_irqrestore(&server_list_lock, flags);
531}
532
533static void rpcrouter_smdnotify(void *_dev, unsigned event)
534{
535 if (event != SMD_EVENT_DATA)
536 return;
537
538 wake_up(&smd_wait);
539}
540
541static void *rr_malloc(unsigned sz)
542{
543 void *ptr = kmalloc(sz, GFP_KERNEL);
544 if (ptr)
545 return ptr;
546
547 printk(KERN_ERR "rpcrouter: kmalloc of %d failed, retrying...\n", sz);
548 do {
549 ptr = kmalloc(sz, GFP_KERNEL);
550 } while (!ptr);
551
552 return ptr;
553}
554
555/* TODO: deal with channel teardown / restore */
556static int rr_read(void *data, int len)
557{
558 int rc;
559 unsigned long flags;
560// printk("rr_read() %d\n", len);
561 for(;;) {
562 spin_lock_irqsave(&smd_lock, flags);
563 if (smd_read_avail(smd_channel) >= len) {
564 rc = smd_read(smd_channel, data, len);
565 spin_unlock_irqrestore(&smd_lock, flags);
566 if (rc == len)
567 return 0;
568 else
569 return -EIO;
570 }
571 rpcrouter_need_len = len;
572 spin_unlock_irqrestore(&smd_lock, flags);
573
574// printk("rr_read: waiting (%d)\n", len);
575 wait_event(smd_wait, smd_read_avail(smd_channel) >= len);
576 }
577 return 0;
578}
579
580static uint32_t r2r_buf[RPCROUTER_MSGSIZE_MAX];
581
582static void do_read_data(struct work_struct *work)
583{
584 struct rr_header hdr;
585 struct rr_packet *pkt;
586 struct rr_fragment *frag;
587 struct msm_rpc_endpoint *ept;
588 uint32_t pm, mid;
589 unsigned long flags;
590
591 if (rr_read(&hdr, sizeof(hdr)))
592 goto fail_io;
593
594#if TRACE_R2R_RAW
595 RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
596 hdr.version, hdr.type, hdr.src_pid, hdr.src_cid,
597 hdr.confirm_rx, hdr.size, hdr.dst_pid, hdr.dst_cid);
598#endif
599
600 if (hdr.version != RPCROUTER_VERSION) {
601 DIAG("version %d != %d\n", hdr.version, RPCROUTER_VERSION);
602 goto fail_data;
603 }
604 if (hdr.size > RPCROUTER_MSGSIZE_MAX) {
605 DIAG("msg size %d > max %d\n", hdr.size, RPCROUTER_MSGSIZE_MAX);
606 goto fail_data;
607 }
608
609 if (hdr.dst_cid == RPCROUTER_ROUTER_ADDRESS) {
610 if (rr_read(r2r_buf, hdr.size))
611 goto fail_io;
612 process_control_msg((void*) r2r_buf, hdr.size);
613 goto done;
614 }
615
616 if (hdr.size < sizeof(pm)) {
617 DIAG("runt packet (no pacmark)\n");
618 goto fail_data;
619 }
620 if (rr_read(&pm, sizeof(pm)))
621 goto fail_io;
622
623 hdr.size -= sizeof(pm);
624
625 frag = rr_malloc(hdr.size + sizeof(*frag));
626 frag->next = NULL;
627 frag->length = hdr.size;
628 if (rr_read(frag->data, hdr.size))
629 goto fail_io;
630
631 ept = rpcrouter_lookup_local_endpoint(hdr.dst_cid);
632 if (!ept) {
633 DIAG("no local ept for cid %08x\n", hdr.dst_cid);
634 kfree(frag);
635 goto done;
636 }
637
638 /* See if there is already a partial packet that matches our mid
639 * and if so, append this fragment to that packet.
640 */
641 mid = PACMARK_MID(pm);
642 list_for_each_entry(pkt, &ept->incomplete, list) {
643 if (pkt->mid == mid) {
644 pkt->last->next = frag;
645 pkt->last = frag;
646 pkt->length += frag->length;
647 if (PACMARK_LAST(pm)) {
648 list_del(&pkt->list);
649 goto packet_complete;
650 }
651 goto done;
652 }
653 }
654 /* This mid is new -- create a packet for it, and put it on
655 * the incomplete list if this fragment is not a last fragment,
656 * otherwise put it on the read queue.
657 */
658 pkt = rr_malloc(sizeof(struct rr_packet));
659 pkt->first = frag;
660 pkt->last = frag;
661 memcpy(&pkt->hdr, &hdr, sizeof(hdr));
662 pkt->mid = mid;
663 pkt->length = frag->length;
664 if (!PACMARK_LAST(pm)) {
665 list_add_tail(&pkt->list, &ept->incomplete);
666 goto done;
667 }
668
669packet_complete:
670 spin_lock_irqsave(&ept->read_q_lock, flags);
671 list_add_tail(&pkt->list, &ept->read_q);
672 wake_up(&ept->wait_q);
673 spin_unlock_irqrestore(&ept->read_q_lock, flags);
674done:
675
676 if (hdr.confirm_rx) {
677 union rr_control_msg msg;
678
679 msg.cmd = RPCROUTER_CTRL_CMD_RESUME_TX;
680 msg.cli.pid = hdr.dst_pid;
681 msg.cli.cid = hdr.dst_cid;
682
683 RR("x RESUME_TX id=%d:%08x\n", msg.cli.pid, msg.cli.cid);
684 rpcrouter_send_control_msg(&msg);
685 }
686
687 queue_work(rpcrouter_workqueue, &work_read_data);
688 return;
689
690fail_io:
691fail_data:
692 printk(KERN_ERR "rpc_router has died\n");
693}
694
695void msm_rpc_setup_req(struct rpc_request_hdr *hdr, uint32_t prog,
696 uint32_t vers, uint32_t proc)
697{
698 memset(hdr, 0, sizeof(struct rpc_request_hdr));
699 hdr->xid = cpu_to_be32(atomic_add_return(1, &next_xid));
700 hdr->rpc_vers = cpu_to_be32(2);
701 hdr->prog = cpu_to_be32(prog);
702 hdr->vers = cpu_to_be32(vers);
703 hdr->procedure = cpu_to_be32(proc);
704}
705
706struct msm_rpc_endpoint *msm_rpc_open(void)
707{
708 struct msm_rpc_endpoint *ept;
709
710 ept = msm_rpcrouter_create_local_endpoint(MKDEV(0, 0));
711 if (ept == NULL)
712 return ERR_PTR(-ENOMEM);
713
714 return ept;
715}
716
717int msm_rpc_close(struct msm_rpc_endpoint *ept)
718{
719 return msm_rpcrouter_destroy_local_endpoint(ept);
720}
721EXPORT_SYMBOL(msm_rpc_close);
722
723int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count)
724{
725 struct rr_header hdr;
726 uint32_t pacmark;
727 struct rpc_request_hdr *rq = buffer;
728 struct rr_remote_endpoint *r_ept;
729 unsigned long flags;
730 int needed;
731 DEFINE_WAIT(__wait);
732
733 /* TODO: fragmentation for large outbound packets */
734 if (count > (RPCROUTER_MSGSIZE_MAX - sizeof(uint32_t)) || !count)
735 return -EINVAL;
736
737 /* snoop the RPC packet and enforce permissions */
738
739 /* has to have at least the xid and type fields */
740 if (count < (sizeof(uint32_t) * 2)) {
741 printk(KERN_ERR "rr_write: rejecting runt packet\n");
742 return -EINVAL;
743 }
744
745 if (rq->type == 0) {
746 /* RPC CALL */
747 if (count < (sizeof(uint32_t) * 6)) {
748 printk(KERN_ERR
749 "rr_write: rejecting runt call packet\n");
750 return -EINVAL;
751 }
752 if (ept->dst_pid == 0xffffffff) {
753 printk(KERN_ERR "rr_write: not connected\n");
754 return -ENOTCONN;
755 }
756
757#if CONFIG_MSM_AMSS_VERSION >= 6350
758 if ((ept->dst_prog != rq->prog) ||
759 !msm_rpc_is_compatible_version(
760 be32_to_cpu(ept->dst_vers),
761 be32_to_cpu(rq->vers))) {
762#else
763 if (ept->dst_prog != rq->prog || ept->dst_vers != rq->vers) {
764#endif
765 printk(KERN_ERR
766 "rr_write: cannot write to %08x:%d "
767 "(bound to %08x:%d)\n",
768 be32_to_cpu(rq->prog), be32_to_cpu(rq->vers),
769 be32_to_cpu(ept->dst_prog),
770 be32_to_cpu(ept->dst_vers));
771 return -EINVAL;
772 }
773 hdr.dst_pid = ept->dst_pid;
774 hdr.dst_cid = ept->dst_cid;
775 IO("CALL on ept %p to %08x:%08x @ %d:%08x (%d bytes) (xid %x proc %x)\n",
776 ept,
777 be32_to_cpu(rq->prog), be32_to_cpu(rq->vers),
778 ept->dst_pid, ept->dst_cid, count,
779 be32_to_cpu(rq->xid), be32_to_cpu(rq->procedure));
780 } else {
781 /* RPC REPLY */
782 /* TODO: locking */
783 if (ept->reply_pid == 0xffffffff) {
784 printk(KERN_ERR
785 "rr_write: rejecting unexpected reply\n");
786 return -EINVAL;
787 }
788 if (ept->reply_xid != rq->xid) {
789 printk(KERN_ERR
790 "rr_write: rejecting packet w/ bad xid\n");
791 return -EINVAL;
792 }
793
794 hdr.dst_pid = ept->reply_pid;
795 hdr.dst_cid = ept->reply_cid;
796
797 /* consume this reply */
798 ept->reply_pid = 0xffffffff;
799
800 IO("REPLY on ept %p to xid=%d @ %d:%08x (%d bytes)\n",
801 ept,
802 be32_to_cpu(rq->xid), hdr.dst_pid, hdr.dst_cid, count);
803 }
804
805 r_ept = rpcrouter_lookup_remote_endpoint(hdr.dst_cid);
806
807 if (!r_ept) {
808 printk(KERN_ERR
809 "msm_rpc_write(): No route to ept "
810 "[PID %x CID %x]\n", hdr.dst_pid, hdr.dst_cid);
811 return -EHOSTUNREACH;
812 }
813
814 /* Create routing header */
815 hdr.type = RPCROUTER_CTRL_CMD_DATA;
816 hdr.version = RPCROUTER_VERSION;
817 hdr.src_pid = ept->pid;
818 hdr.src_cid = ept->cid;
819 hdr.confirm_rx = 0;
820 hdr.size = count + sizeof(uint32_t);
821
822 for (;;) {
823 prepare_to_wait(&r_ept->quota_wait, &__wait,
824 TASK_INTERRUPTIBLE);
825 spin_lock_irqsave(&r_ept->quota_lock, flags);
826 if (r_ept->tx_quota_cntr < RPCROUTER_DEFAULT_RX_QUOTA)
827 break;
828 if (signal_pending(current) &&
829 (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE)))
830 break;
831 spin_unlock_irqrestore(&r_ept->quota_lock, flags);
832 schedule();
833 }
834 finish_wait(&r_ept->quota_wait, &__wait);
835
836 if (signal_pending(current) &&
837 (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) {
838 spin_unlock_irqrestore(&r_ept->quota_lock, flags);
839 return -ERESTARTSYS;
840 }
841 r_ept->tx_quota_cntr++;
842 if (r_ept->tx_quota_cntr == RPCROUTER_DEFAULT_RX_QUOTA)
843 hdr.confirm_rx = 1;
844
845 /* bump pacmark while interrupts disabled to avoid race
846 * probably should be atomic op instead
847 */
848 pacmark = PACMARK(count, ++next_pacmarkid, 0, 1);
849
850 spin_unlock_irqrestore(&r_ept->quota_lock, flags);
851
852 spin_lock_irqsave(&smd_lock, flags);
853
854 needed = sizeof(hdr) + hdr.size;
855 while (smd_write_avail(smd_channel) < needed) {
856 spin_unlock_irqrestore(&smd_lock, flags);
857 msleep(250);
858 spin_lock_irqsave(&smd_lock, flags);
859 }
860
861 /* TODO: deal with full fifo */
862 smd_write(smd_channel, &hdr, sizeof(hdr));
863 smd_write(smd_channel, &pacmark, sizeof(pacmark));
864 smd_write(smd_channel, buffer, count);
865
866 spin_unlock_irqrestore(&smd_lock, flags);
867
868 return count;
869}
870EXPORT_SYMBOL(msm_rpc_write);
871
872/*
873 * NOTE: It is the responsibility of the caller to kfree buffer
874 */
875int msm_rpc_read(struct msm_rpc_endpoint *ept, void **buffer,
876 unsigned user_len, long timeout)
877{
878 struct rr_fragment *frag, *next;
879 char *buf;
880 int rc;
881
882 rc = __msm_rpc_read(ept, &frag, user_len, timeout);
883 if (rc <= 0)
884 return rc;
885
886 /* single-fragment messages conveniently can be
887 * returned as-is (the buffer is at the front)
888 */
889 if (frag->next == 0) {
890 *buffer = (void*) frag;
891 return rc;
892 }
893
894 /* multi-fragment messages, we have to do it the
895 * hard way, which is rather disgusting right now
896 */
897 buf = rr_malloc(rc);
898 *buffer = buf;
899
900 while (frag != NULL) {
901 memcpy(buf, frag->data, frag->length);
902 next = frag->next;
903 buf += frag->length;
904 kfree(frag);
905 frag = next;
906 }
907
908 return rc;
909}
910
911int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc,
912 void *_request, int request_size,
913 long timeout)
914{
915 return msm_rpc_call_reply(ept, proc,
916 _request, request_size,
917 NULL, 0, timeout);
918}
919EXPORT_SYMBOL(msm_rpc_call);
920
921int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc,
922 void *_request, int request_size,
923 void *_reply, int reply_size,
924 long timeout)
925{
926 struct rpc_request_hdr *req = _request;
927 struct rpc_reply_hdr *reply;
928 int rc;
929
930 if (request_size < sizeof(*req))
931 return -ETOOSMALL;
932
933 if (ept->dst_pid == 0xffffffff)
934 return -ENOTCONN;
935
936 /* We can't use msm_rpc_setup_req() here, because dst_prog and
937 * dst_vers here are already in BE.
938 */
939 memset(req, 0, sizeof(*req));
940 req->xid = cpu_to_be32(atomic_add_return(1, &next_xid));
941 req->rpc_vers = cpu_to_be32(2);
942 req->prog = ept->dst_prog;
943 req->vers = ept->dst_vers;
944 req->procedure = cpu_to_be32(proc);
945
946 rc = msm_rpc_write(ept, req, request_size);
947 if (rc < 0)
948 return rc;
949
950 for (;;) {
951 rc = msm_rpc_read(ept, (void*) &reply, -1, timeout);
952 if (rc < 0)
953 return rc;
954 if (rc < (3 * sizeof(uint32_t))) {
955 rc = -EIO;
956 break;
957 }
958 /* we should not get CALL packets -- ignore them */
959 if (reply->type == 0) {
960 kfree(reply);
961 continue;
962 }
963 /* If an earlier call timed out, we could get the (no
964 * longer wanted) reply for it. Ignore replies that
965 * we don't expect.
966 */
967 if (reply->xid != req->xid) {
968 kfree(reply);
969 continue;
970 }
971 if (reply->reply_stat != 0) {
972 rc = -EPERM;
973 break;
974 }
975 if (reply->data.acc_hdr.accept_stat != 0) {
976 rc = -EINVAL;
977 break;
978 }
979 if (_reply == NULL) {
980 rc = 0;
981 break;
982 }
983 if (rc > reply_size) {
984 rc = -ENOMEM;
985 } else {
986 memcpy(_reply, reply, rc);
987 }
988 break;
989 }
990 kfree(reply);
991 return rc;
992}
993EXPORT_SYMBOL(msm_rpc_call_reply);
994
995
996static inline int ept_packet_available(struct msm_rpc_endpoint *ept)
997{
998 unsigned long flags;
999 int ret;
1000 spin_lock_irqsave(&ept->read_q_lock, flags);
1001 ret = !list_empty(&ept->read_q);
1002 spin_unlock_irqrestore(&ept->read_q_lock, flags);
1003 return ret;
1004}
1005
1006int __msm_rpc_read(struct msm_rpc_endpoint *ept,
1007 struct rr_fragment **frag_ret,
1008 unsigned len, long timeout)
1009{
1010 struct rr_packet *pkt;
1011 struct rpc_request_hdr *rq;
1012 DEFINE_WAIT(__wait);
1013 unsigned long flags;
1014 int rc;
1015
1016 IO("READ on ept %p\n", ept);
1017
1018 if (ept->flags & MSM_RPC_UNINTERRUPTIBLE) {
1019 if (timeout < 0) {
1020 wait_event(ept->wait_q, ept_packet_available(ept));
1021 } else {
1022 rc = wait_event_timeout(
1023 ept->wait_q, ept_packet_available(ept),
1024 timeout);
1025 if (rc == 0)
1026 return -ETIMEDOUT;
1027 }
1028 } else {
1029 if (timeout < 0) {
1030 rc = wait_event_interruptible(
1031 ept->wait_q, ept_packet_available(ept));
1032 if (rc < 0)
1033 return rc;
1034 } else {
1035 rc = wait_event_interruptible_timeout(
1036 ept->wait_q, ept_packet_available(ept),
1037 timeout);
1038 if (rc == 0)
1039 return -ETIMEDOUT;
1040 }
1041 }
1042
1043 spin_lock_irqsave(&ept->read_q_lock, flags);
1044 if (list_empty(&ept->read_q)) {
1045 spin_unlock_irqrestore(&ept->read_q_lock, flags);
1046 return -EAGAIN;
1047 }
1048 pkt = list_first_entry(&ept->read_q, struct rr_packet, list);
1049 if (pkt->length > len) {
1050 spin_unlock_irqrestore(&ept->read_q_lock, flags);
1051 return -ETOOSMALL;
1052 }
1053 list_del(&pkt->list);
1054 spin_unlock_irqrestore(&ept->read_q_lock, flags);
1055
1056 rc = pkt->length;
1057
1058 *frag_ret = pkt->first;
1059 rq = (void*) pkt->first->data;
1060 if ((rc >= (sizeof(uint32_t) * 3)) && (rq->type == 0)) {
1061 IO("READ on ept %p is a CALL on %08x:%08x proc %d xid %d\n",
1062 ept, be32_to_cpu(rq->prog), be32_to_cpu(rq->vers),
1063 be32_to_cpu(rq->procedure),
1064 be32_to_cpu(rq->xid));
1065 /* RPC CALL */
1066 if (ept->reply_pid != 0xffffffff) {
1067 printk(KERN_WARNING
1068 "rr_read: lost previous reply xid...\n");
1069 }
1070 /* TODO: locking? */
1071 ept->reply_pid = pkt->hdr.src_pid;
1072 ept->reply_cid = pkt->hdr.src_cid;
1073 ept->reply_xid = rq->xid;
1074 }
1075#if TRACE_RPC_MSG
1076 else if ((rc >= (sizeof(uint32_t) * 3)) && (rq->type == 1))
1077 IO("READ on ept %p is a REPLY\n", ept);
1078 else IO("READ on ept %p (%d bytes)\n", ept, rc);
1079#endif
1080
1081 kfree(pkt);
1082 return rc;
1083}
1084
1085#if CONFIG_MSM_AMSS_VERSION >= 6350
1086int msm_rpc_is_compatible_version(uint32_t server_version,
1087 uint32_t client_version)
1088{
1089 if ((server_version & RPC_VERSION_MODE_MASK) !=
1090 (client_version & RPC_VERSION_MODE_MASK))
1091 return 0;
1092
1093 if (server_version & RPC_VERSION_MODE_MASK)
1094 return server_version == client_version;
1095
1096 return ((server_version & RPC_VERSION_MAJOR_MASK) ==
1097 (client_version & RPC_VERSION_MAJOR_MASK)) &&
1098 ((server_version & RPC_VERSION_MINOR_MASK) >=
1099 (client_version & RPC_VERSION_MINOR_MASK));
1100}
1101EXPORT_SYMBOL(msm_rpc_is_compatible_version);
1102
1103static int msm_rpc_get_compatible_server(uint32_t prog,
1104 uint32_t ver,
1105 uint32_t *found_vers)
1106{
1107 struct rr_server *server;
1108 unsigned long flags;
1109 if (found_vers == NULL)
1110 return 0;
1111
1112 spin_lock_irqsave(&server_list_lock, flags);
1113 list_for_each_entry(server, &server_list, list) {
1114 if ((server->prog == prog) &&
1115 msm_rpc_is_compatible_version(server->vers, ver)) {
1116 *found_vers = server->vers;
1117 spin_unlock_irqrestore(&server_list_lock, flags);
1118 return 0;
1119 }
1120 }
1121 spin_unlock_irqrestore(&server_list_lock, flags);
1122 return -1;
1123}
1124#endif
1125
1126struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog, uint32_t vers, unsigned flags)
1127{
1128 struct msm_rpc_endpoint *ept;
1129 struct rr_server *server;
1130
1131#if CONFIG_MSM_AMSS_VERSION >= 6350
1132 if (!(vers & RPC_VERSION_MODE_MASK)) {
1133 uint32_t found_vers;
1134 if (msm_rpc_get_compatible_server(prog, vers, &found_vers) < 0)
1135 return ERR_PTR(-EHOSTUNREACH);
1136 if (found_vers != vers) {
1137 D("RPC using new version %08x:{%08x --> %08x}\n",
1138 prog, vers, found_vers);
1139 vers = found_vers;
1140 }
1141 }
1142#endif
1143
1144 server = rpcrouter_lookup_server(prog, vers);
1145 if (!server)
1146 return ERR_PTR(-EHOSTUNREACH);
1147
1148 ept = msm_rpc_open();
1149 if (IS_ERR(ept))
1150 return ept;
1151
1152 ept->flags = flags;
1153 ept->dst_pid = server->pid;
1154 ept->dst_cid = server->cid;
1155 ept->dst_prog = cpu_to_be32(prog);
1156 ept->dst_vers = cpu_to_be32(vers);
1157
1158 return ept;
1159}
1160EXPORT_SYMBOL(msm_rpc_connect);
1161
1162uint32_t msm_rpc_get_vers(struct msm_rpc_endpoint *ept)
1163{
1164 return be32_to_cpu(ept->dst_vers);
1165}
1166EXPORT_SYMBOL(msm_rpc_get_vers);
1167
1168/* TODO: permission check? */
1169int msm_rpc_register_server(struct msm_rpc_endpoint *ept,
1170 uint32_t prog, uint32_t vers)
1171{
1172 int rc;
1173 union rr_control_msg msg;
1174 struct rr_server *server;
1175
1176 server = rpcrouter_create_server(ept->pid, ept->cid,
1177 prog, vers);
1178 if (!server)
1179 return -ENODEV;
1180
1181 msg.srv.cmd = RPCROUTER_CTRL_CMD_NEW_SERVER;
1182 msg.srv.pid = ept->pid;
1183 msg.srv.cid = ept->cid;
1184 msg.srv.prog = prog;
1185 msg.srv.vers = vers;
1186
1187 RR("x NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
1188 ept->pid, ept->cid, prog, vers);
1189
1190 rc = rpcrouter_send_control_msg(&msg);
1191 if (rc < 0)
1192 return rc;
1193
1194 return 0;
1195}
1196
1197/* TODO: permission check -- disallow unreg of somebody else's server */
1198int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept,
1199 uint32_t prog, uint32_t vers)
1200{
1201 struct rr_server *server;
1202 server = rpcrouter_lookup_server(prog, vers);
1203
1204 if (!server)
1205 return -ENOENT;
1206 rpcrouter_destroy_server(server);
1207 return 0;
1208}
1209
1210static int msm_rpcrouter_probe(struct platform_device *pdev)
1211{
1212 int rc;
1213
1214 /* Initialize what we need to start processing */
1215 INIT_LIST_HEAD(&local_endpoints);
1216 INIT_LIST_HEAD(&remote_endpoints);
1217
1218 init_waitqueue_head(&newserver_wait);
1219 init_waitqueue_head(&smd_wait);
1220
1221 rpcrouter_workqueue = create_singlethread_workqueue("rpcrouter");
1222 if (!rpcrouter_workqueue)
1223 return -ENOMEM;
1224
1225 rc = msm_rpcrouter_init_devices();
1226 if (rc < 0)
1227 goto fail_destroy_workqueue;
1228
1229 /* Open up SMD channel 2 */
1230 initialized = 0;
1231 rc = smd_open("SMD_RPCCALL", &smd_channel, NULL, rpcrouter_smdnotify);
1232 if (rc < 0)
1233 goto fail_remove_devices;
1234
1235 queue_work(rpcrouter_workqueue, &work_read_data);
1236 return 0;
1237
1238 fail_remove_devices:
1239 msm_rpcrouter_exit_devices();
1240 fail_destroy_workqueue:
1241 destroy_workqueue(rpcrouter_workqueue);
1242 return rc;
1243}
1244
1245static struct platform_driver msm_smd_channel2_driver = {
1246 .probe = msm_rpcrouter_probe,
1247 .driver = {
1248 .name = "SMD_RPCCALL",
1249 .owner = THIS_MODULE,
1250 },
1251};
1252
1253static int __init rpcrouter_init(void)
1254{
1255 return platform_driver_register(&msm_smd_channel2_driver);
1256}
1257
1258module_init(rpcrouter_init);
1259MODULE_DESCRIPTION("MSM RPC Router");
1260MODULE_AUTHOR("San Mehat <san@android.com>");
1261MODULE_LICENSE("GPL");
diff --git a/drivers/staging/dream/smd/smd_rpcrouter.h b/drivers/staging/dream/smd/smd_rpcrouter.h
deleted file mode 100644
index 86ab997b1b79..000000000000
--- a/drivers/staging/dream/smd/smd_rpcrouter.h
+++ /dev/null
@@ -1,193 +0,0 @@
1/** arch/arm/mach-msm/smd_rpcrouter.h
2 *
3 * Copyright (C) 2007 Google, Inc.
4 * Copyright (c) 2007-2008 QUALCOMM Incorporated.
5 * Author: San Mehat <san@android.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#ifndef _ARCH_ARM_MACH_MSM_SMD_RPCROUTER_H
19#define _ARCH_ARM_MACH_MSM_SMD_RPCROUTER_H
20
21#include <linux/types.h>
22#include <linux/list.h>
23#include <linux/cdev.h>
24#include <linux/platform_device.h>
25
26#include <mach/msm_smd.h>
27#include <mach/msm_rpcrouter.h>
28
29/* definitions for the R2R wire protcol */
30
31#define RPCROUTER_VERSION 1
32#define RPCROUTER_PROCESSORS_MAX 4
33#define RPCROUTER_MSGSIZE_MAX 512
34
35#define RPCROUTER_CLIENT_BCAST_ID 0xffffffff
36#define RPCROUTER_ROUTER_ADDRESS 0xfffffffe
37
38#define RPCROUTER_PID_LOCAL 1
39#define RPCROUTER_PID_REMOTE 0
40
41#define RPCROUTER_CTRL_CMD_DATA 1
42#define RPCROUTER_CTRL_CMD_HELLO 2
43#define RPCROUTER_CTRL_CMD_BYE 3
44#define RPCROUTER_CTRL_CMD_NEW_SERVER 4
45#define RPCROUTER_CTRL_CMD_REMOVE_SERVER 5
46#define RPCROUTER_CTRL_CMD_REMOVE_CLIENT 6
47#define RPCROUTER_CTRL_CMD_RESUME_TX 7
48#define RPCROUTER_CTRL_CMD_EXIT 8
49
50#define RPCROUTER_DEFAULT_RX_QUOTA 5
51
52union rr_control_msg {
53 uint32_t cmd;
54 struct {
55 uint32_t cmd;
56 uint32_t prog;
57 uint32_t vers;
58 uint32_t pid;
59 uint32_t cid;
60 } srv;
61 struct {
62 uint32_t cmd;
63 uint32_t pid;
64 uint32_t cid;
65 } cli;
66};
67
68struct rr_header {
69 uint32_t version;
70 uint32_t type;
71 uint32_t src_pid;
72 uint32_t src_cid;
73 uint32_t confirm_rx;
74 uint32_t size;
75 uint32_t dst_pid;
76 uint32_t dst_cid;
77};
78
79/* internals */
80
81#define RPCROUTER_MAX_REMOTE_SERVERS 100
82
83struct rr_fragment {
84 unsigned char data[RPCROUTER_MSGSIZE_MAX];
85 uint32_t length;
86 struct rr_fragment *next;
87};
88
89struct rr_packet {
90 struct list_head list;
91 struct rr_fragment *first;
92 struct rr_fragment *last;
93 struct rr_header hdr;
94 uint32_t mid;
95 uint32_t length;
96};
97
98#define PACMARK_LAST(n) ((n) & 0x80000000)
99#define PACMARK_MID(n) (((n) >> 16) & 0xFF)
100#define PACMARK_LEN(n) ((n) & 0xFFFF)
101
102static inline uint32_t PACMARK(uint32_t len, uint32_t mid, uint32_t first,
103 uint32_t last)
104{
105 return (len & 0xFFFF) |
106 ((mid & 0xFF) << 16) |
107 ((!!first) << 30) |
108 ((!!last) << 31);
109}
110
111struct rr_server {
112 struct list_head list;
113
114 uint32_t pid;
115 uint32_t cid;
116 uint32_t prog;
117 uint32_t vers;
118
119 dev_t device_number;
120 struct cdev cdev;
121 struct device *device;
122 struct rpcsvr_platform_device p_device;
123 char pdev_name[32];
124};
125
126struct rr_remote_endpoint {
127 uint32_t pid;
128 uint32_t cid;
129
130 int tx_quota_cntr;
131 spinlock_t quota_lock;
132 wait_queue_head_t quota_wait;
133
134 struct list_head list;
135};
136
137struct msm_rpc_endpoint {
138 struct list_head list;
139
140 /* incomplete packets waiting for assembly */
141 struct list_head incomplete;
142
143 /* complete packets waiting to be read */
144 struct list_head read_q;
145 spinlock_t read_q_lock;
146 wait_queue_head_t wait_q;
147 unsigned flags;
148
149 /* endpoint address */
150 uint32_t pid;
151 uint32_t cid;
152
153 /* bound remote address
154 * if not connected (dst_pid == 0xffffffff) RPC_CALL writes fail
155 * RPC_CALLs must be to the prog/vers below or they will fail
156 */
157 uint32_t dst_pid;
158 uint32_t dst_cid;
159 uint32_t dst_prog; /* be32 */
160 uint32_t dst_vers; /* be32 */
161
162 /* reply remote address
163 * if reply_pid == 0xffffffff, none available
164 * RPC_REPLY writes may only go to the pid/cid/xid of the
165 * last RPC_CALL we received.
166 */
167 uint32_t reply_pid;
168 uint32_t reply_cid;
169 uint32_t reply_xid; /* be32 */
170 uint32_t next_pm; /* Pacmark sequence */
171
172 /* device node if this endpoint is accessed via userspace */
173 dev_t dev;
174};
175
176/* shared between smd_rpcrouter*.c */
177
178int __msm_rpc_read(struct msm_rpc_endpoint *ept,
179 struct rr_fragment **frag,
180 unsigned len, long timeout);
181
182struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev);
183int msm_rpcrouter_destroy_local_endpoint(struct msm_rpc_endpoint *ept);
184
185int msm_rpcrouter_create_server_cdev(struct rr_server *server);
186int msm_rpcrouter_create_server_pdev(struct rr_server *server);
187
188int msm_rpcrouter_init_devices(void);
189void msm_rpcrouter_exit_devices(void);
190
191extern dev_t msm_rpcrouter_devno;
192extern struct class *msm_rpcrouter_class;
193#endif
diff --git a/drivers/staging/dream/smd/smd_rpcrouter_device.c b/drivers/staging/dream/smd/smd_rpcrouter_device.c
deleted file mode 100644
index e9c28eddce31..000000000000
--- a/drivers/staging/dream/smd/smd_rpcrouter_device.c
+++ /dev/null
@@ -1,377 +0,0 @@
1/* arch/arm/mach-msm/smd_rpcrouter_device.c
2 *
3 * Copyright (C) 2007 Google, Inc.
4 * Copyright (c) 2007-2009 QUALCOMM Incorporated.
5 * Author: San Mehat <san@android.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17#include <linux/module.h>
18#include <linux/kernel.h>
19#include <linux/string.h>
20#include <linux/errno.h>
21#include <linux/cdev.h>
22#include <linux/init.h>
23#include <linux/device.h>
24#include <linux/types.h>
25#include <linux/delay.h>
26#include <linux/fs.h>
27#include <linux/err.h>
28#include <linux/sched.h>
29#include <linux/poll.h>
30#include <linux/platform_device.h>
31#include <linux/msm_rpcrouter.h>
32#include <linux/slab.h>
33
34#include <asm/uaccess.h>
35#include <asm/byteorder.h>
36
37#include "smd_rpcrouter.h"
38
39#define SAFETY_MEM_SIZE 65536
40
41/* Next minor # available for a remote server */
42static int next_minor = 1;
43
44struct class *msm_rpcrouter_class;
45dev_t msm_rpcrouter_devno;
46
47static struct cdev rpcrouter_cdev;
48static struct device *rpcrouter_device;
49
50static int rpcrouter_open(struct inode *inode, struct file *filp)
51{
52 int rc;
53 struct msm_rpc_endpoint *ept;
54
55 rc = nonseekable_open(inode, filp);
56 if (rc < 0)
57 return rc;
58
59 ept = msm_rpcrouter_create_local_endpoint(inode->i_rdev);
60 if (!ept)
61 return -ENOMEM;
62
63 filp->private_data = ept;
64 return 0;
65}
66
67static int rpcrouter_release(struct inode *inode, struct file *filp)
68{
69 struct msm_rpc_endpoint *ept;
70 ept = (struct msm_rpc_endpoint *) filp->private_data;
71
72 return msm_rpcrouter_destroy_local_endpoint(ept);
73}
74
75static ssize_t rpcrouter_read(struct file *filp, char __user *buf,
76 size_t count, loff_t *ppos)
77{
78 struct msm_rpc_endpoint *ept;
79 struct rr_fragment *frag, *next;
80 int rc;
81
82 ept = (struct msm_rpc_endpoint *) filp->private_data;
83
84 rc = __msm_rpc_read(ept, &frag, count, -1);
85 if (rc < 0)
86 return rc;
87
88 count = rc;
89
90 while (frag != NULL) {
91 if (copy_to_user(buf, frag->data, frag->length)) {
92 printk(KERN_ERR
93 "rpcrouter: could not copy all read data to user!\n");
94 rc = -EFAULT;
95 }
96 buf += frag->length;
97 next = frag->next;
98 kfree(frag);
99 frag = next;
100 }
101
102 return rc;
103}
104
105static ssize_t rpcrouter_write(struct file *filp, const char __user *buf,
106 size_t count, loff_t *ppos)
107{
108 struct msm_rpc_endpoint *ept;
109 int rc = 0;
110 void *k_buffer;
111
112 ept = (struct msm_rpc_endpoint *) filp->private_data;
113
114 /* A check for safety, this seems non-standard */
115 if (count > SAFETY_MEM_SIZE)
116 return -EINVAL;
117
118 k_buffer = kmalloc(count, GFP_KERNEL);
119 if (!k_buffer)
120 return -ENOMEM;
121
122 if (copy_from_user(k_buffer, buf, count)) {
123 rc = -EFAULT;
124 goto write_out_free;
125 }
126
127 rc = msm_rpc_write(ept, k_buffer, count);
128 if (rc < 0)
129 goto write_out_free;
130
131 rc = count;
132write_out_free:
133 kfree(k_buffer);
134 return rc;
135}
136
137static unsigned int rpcrouter_poll(struct file *filp,
138 struct poll_table_struct *wait)
139{
140 struct msm_rpc_endpoint *ept;
141 unsigned mask = 0;
142 ept = (struct msm_rpc_endpoint *) filp->private_data;
143
144 /* If there's data already in the read queue, return POLLIN.
145 * Else, wait for the requested amount of time, and check again.
146 */
147
148 if (!list_empty(&ept->read_q))
149 mask |= POLLIN;
150
151 if (!mask) {
152 poll_wait(filp, &ept->wait_q, wait);
153 if (!list_empty(&ept->read_q))
154 mask |= POLLIN;
155 }
156
157 return mask;
158}
159
160static long rpcrouter_ioctl(struct file *filp, unsigned int cmd,
161 unsigned long arg)
162{
163 struct msm_rpc_endpoint *ept;
164 struct rpcrouter_ioctl_server_args server_args;
165 int rc = 0;
166 uint32_t n;
167
168 ept = (struct msm_rpc_endpoint *) filp->private_data;
169 switch (cmd) {
170
171 case RPC_ROUTER_IOCTL_GET_VERSION:
172 n = RPC_ROUTER_VERSION_V1;
173 rc = put_user(n, (unsigned int *) arg);
174 break;
175
176 case RPC_ROUTER_IOCTL_GET_MTU:
177 /* the pacmark word reduces the actual payload
178 * possible per message
179 */
180 n = RPCROUTER_MSGSIZE_MAX - sizeof(uint32_t);
181 rc = put_user(n, (unsigned int *) arg);
182 break;
183
184 case RPC_ROUTER_IOCTL_REGISTER_SERVER:
185 rc = copy_from_user(&server_args, (void *) arg,
186 sizeof(server_args));
187 if (rc < 0)
188 break;
189 msm_rpc_register_server(ept,
190 server_args.prog,
191 server_args.vers);
192 break;
193
194 case RPC_ROUTER_IOCTL_UNREGISTER_SERVER:
195 rc = copy_from_user(&server_args, (void *) arg,
196 sizeof(server_args));
197 if (rc < 0)
198 break;
199
200 msm_rpc_unregister_server(ept,
201 server_args.prog,
202 server_args.vers);
203 break;
204
205 case RPC_ROUTER_IOCTL_GET_MINOR_VERSION:
206 n = MSM_RPC_GET_MINOR(msm_rpc_get_vers(ept));
207 rc = put_user(n, (unsigned int *)arg);
208 break;
209
210 default:
211 rc = -EINVAL;
212 break;
213 }
214
215 return rc;
216}
217
218static struct file_operations rpcrouter_server_fops = {
219 .owner = THIS_MODULE,
220 .open = rpcrouter_open,
221 .release = rpcrouter_release,
222 .read = rpcrouter_read,
223 .write = rpcrouter_write,
224 .poll = rpcrouter_poll,
225 .unlocked_ioctl = rpcrouter_ioctl,
226};
227
228static struct file_operations rpcrouter_router_fops = {
229 .owner = THIS_MODULE,
230 .open = rpcrouter_open,
231 .release = rpcrouter_release,
232 .read = rpcrouter_read,
233 .write = rpcrouter_write,
234 .poll = rpcrouter_poll,
235 .unlocked_ioctl = rpcrouter_ioctl,
236};
237
238int msm_rpcrouter_create_server_cdev(struct rr_server *server)
239{
240 int rc;
241 uint32_t dev_vers;
242
243 if (next_minor == RPCROUTER_MAX_REMOTE_SERVERS) {
244 printk(KERN_ERR
245 "rpcrouter: Minor numbers exhausted - Increase "
246 "RPCROUTER_MAX_REMOTE_SERVERS\n");
247 return -ENOBUFS;
248 }
249
250#if CONFIG_MSM_AMSS_VERSION >= 6350
251 /* Servers with bit 31 set are remote msm servers with hashkey version.
252 * Servers with bit 31 not set are remote msm servers with
253 * backwards compatible version type in which case the minor number
254 * (lower 16 bits) is set to zero.
255 *
256 */
257 if ((server->vers & RPC_VERSION_MODE_MASK))
258 dev_vers = server->vers;
259 else
260 dev_vers = server->vers & RPC_VERSION_MAJOR_MASK;
261#else
262 dev_vers = server->vers;
263#endif
264
265 server->device_number =
266 MKDEV(MAJOR(msm_rpcrouter_devno), next_minor++);
267
268 server->device =
269 device_create(msm_rpcrouter_class, rpcrouter_device,
270 server->device_number, NULL, "%.8x:%.8x",
271 server->prog, dev_vers);
272 if (IS_ERR(server->device)) {
273 printk(KERN_ERR
274 "rpcrouter: Unable to create device (%ld)\n",
275 PTR_ERR(server->device));
276 return PTR_ERR(server->device);;
277 }
278
279 cdev_init(&server->cdev, &rpcrouter_server_fops);
280 server->cdev.owner = THIS_MODULE;
281
282 rc = cdev_add(&server->cdev, server->device_number, 1);
283 if (rc < 0) {
284 printk(KERN_ERR
285 "rpcrouter: Unable to add chrdev (%d)\n", rc);
286 device_destroy(msm_rpcrouter_class, server->device_number);
287 return rc;
288 }
289 return 0;
290}
291
292/* for backward compatible version type (31st bit cleared)
293 * clearing minor number (lower 16 bits) in device name
294 * is neccessary for driver binding
295 */
296int msm_rpcrouter_create_server_pdev(struct rr_server *server)
297{
298 sprintf(server->pdev_name, "rs%.8x:%.8x",
299 server->prog,
300#if CONFIG_MSM_AMSS_VERSION >= 6350
301 (server->vers & RPC_VERSION_MODE_MASK) ? server->vers :
302 (server->vers & RPC_VERSION_MAJOR_MASK));
303#else
304 server->vers);
305#endif
306
307 server->p_device.base.id = -1;
308 server->p_device.base.name = server->pdev_name;
309
310 server->p_device.prog = server->prog;
311 server->p_device.vers = server->vers;
312
313 platform_device_register(&server->p_device.base);
314 return 0;
315}
316
317int msm_rpcrouter_init_devices(void)
318{
319 int rc;
320 int major;
321
322 /* Create the device nodes */
323 msm_rpcrouter_class = class_create(THIS_MODULE, "oncrpc");
324 if (IS_ERR(msm_rpcrouter_class)) {
325 rc = -ENOMEM;
326 printk(KERN_ERR
327 "rpcrouter: failed to create oncrpc class\n");
328 goto fail;
329 }
330
331 rc = alloc_chrdev_region(&msm_rpcrouter_devno, 0,
332 RPCROUTER_MAX_REMOTE_SERVERS + 1,
333 "oncrpc");
334 if (rc < 0) {
335 printk(KERN_ERR
336 "rpcrouter: Failed to alloc chardev region (%d)\n", rc);
337 goto fail_destroy_class;
338 }
339
340 major = MAJOR(msm_rpcrouter_devno);
341 rpcrouter_device = device_create(msm_rpcrouter_class, NULL,
342 msm_rpcrouter_devno, NULL, "%.8x:%d",
343 0, 0);
344 if (IS_ERR(rpcrouter_device)) {
345 rc = -ENOMEM;
346 goto fail_unregister_cdev_region;
347 }
348
349 cdev_init(&rpcrouter_cdev, &rpcrouter_router_fops);
350 rpcrouter_cdev.owner = THIS_MODULE;
351
352 rc = cdev_add(&rpcrouter_cdev, msm_rpcrouter_devno, 1);
353 if (rc < 0)
354 goto fail_destroy_device;
355
356 return 0;
357
358fail_destroy_device:
359 device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
360fail_unregister_cdev_region:
361 unregister_chrdev_region(msm_rpcrouter_devno,
362 RPCROUTER_MAX_REMOTE_SERVERS + 1);
363fail_destroy_class:
364 class_destroy(msm_rpcrouter_class);
365fail:
366 return rc;
367}
368
369void msm_rpcrouter_exit_devices(void)
370{
371 cdev_del(&rpcrouter_cdev);
372 device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
373 unregister_chrdev_region(msm_rpcrouter_devno,
374 RPCROUTER_MAX_REMOTE_SERVERS + 1);
375 class_destroy(msm_rpcrouter_class);
376}
377
diff --git a/drivers/staging/dream/smd/smd_rpcrouter_servers.c b/drivers/staging/dream/smd/smd_rpcrouter_servers.c
deleted file mode 100644
index bec3ee9371b3..000000000000
--- a/drivers/staging/dream/smd/smd_rpcrouter_servers.c
+++ /dev/null
@@ -1,226 +0,0 @@
1/* arch/arm/mach-msm/rpc_servers.c
2 *
3 * Copyright (C) 2007 Google, Inc.
4 * Author: Iliyan Malchev <ibm@android.com>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/kernel.h>
19#include <linux/string.h>
20#include <linux/errno.h>
21#include <linux/cdev.h>
22#include <linux/init.h>
23#include <linux/device.h>
24#include <linux/types.h>
25#include <linux/fs.h>
26#include <linux/kthread.h>
27#include <linux/delay.h>
28#include <linux/platform_device.h>
29#include <linux/wakelock.h>
30#include <linux/slab.h>
31
32#include <linux/msm_rpcrouter.h>
33#include <linux/uaccess.h>
34
35#include <mach/msm_rpcrouter.h>
36#include "smd_rpcrouter.h"
37
38static struct msm_rpc_endpoint *endpoint;
39
40#define FLAG_REGISTERED 0x0001
41
42static LIST_HEAD(rpc_server_list);
43static DEFINE_MUTEX(rpc_server_list_lock);
44static int rpc_servers_active;
45
46static void rpc_server_register(struct msm_rpc_server *server)
47{
48 int rc;
49 rc = msm_rpc_register_server(endpoint, server->prog, server->vers);
50 if (rc < 0)
51 printk(KERN_ERR "[rpcserver] error registering %p @ %08x:%d\n",
52 server, server->prog, server->vers);
53}
54
55static struct msm_rpc_server *rpc_server_find(uint32_t prog, uint32_t vers)
56{
57 struct msm_rpc_server *server;
58
59 mutex_lock(&rpc_server_list_lock);
60 list_for_each_entry(server, &rpc_server_list, list) {
61 if ((server->prog == prog) &&
62#if CONFIG_MSM_AMSS_VERSION >= 6350
63 msm_rpc_is_compatible_version(server->vers, vers)) {
64#else
65 server->vers == vers) {
66#endif
67 mutex_unlock(&rpc_server_list_lock);
68 return server;
69 }
70 }
71 mutex_unlock(&rpc_server_list_lock);
72 return NULL;
73}
74
75static void rpc_server_register_all(void)
76{
77 struct msm_rpc_server *server;
78
79 mutex_lock(&rpc_server_list_lock);
80 list_for_each_entry(server, &rpc_server_list, list) {
81 if (!(server->flags & FLAG_REGISTERED)) {
82 rpc_server_register(server);
83 server->flags |= FLAG_REGISTERED;
84 }
85 }
86 mutex_unlock(&rpc_server_list_lock);
87}
88
89int msm_rpc_create_server(struct msm_rpc_server *server)
90{
91 /* make sure we're in a sane state first */
92 server->flags = 0;
93 INIT_LIST_HEAD(&server->list);
94
95 mutex_lock(&rpc_server_list_lock);
96 list_add(&server->list, &rpc_server_list);
97 if (rpc_servers_active) {
98 rpc_server_register(server);
99 server->flags |= FLAG_REGISTERED;
100 }
101 mutex_unlock(&rpc_server_list_lock);
102
103 return 0;
104}
105
106static int rpc_send_accepted_void_reply(struct msm_rpc_endpoint *client,
107 uint32_t xid, uint32_t accept_status)
108{
109 int rc = 0;
110 uint8_t reply_buf[sizeof(struct rpc_reply_hdr)];
111 struct rpc_reply_hdr *reply = (struct rpc_reply_hdr *)reply_buf;
112
113 reply->xid = cpu_to_be32(xid);
114 reply->type = cpu_to_be32(1); /* reply */
115 reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
116
117 reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
118 reply->data.acc_hdr.verf_flavor = 0;
119 reply->data.acc_hdr.verf_length = 0;
120
121 rc = msm_rpc_write(client, reply_buf, sizeof(reply_buf));
122 if (rc < 0)
123 printk(KERN_ERR
124 "%s: could not write response: %d\n",
125 __FUNCTION__, rc);
126
127 return rc;
128}
129
130static int rpc_servers_thread(void *data)
131{
132 void *buffer;
133 struct rpc_request_hdr *req;
134 struct msm_rpc_server *server;
135 int rc;
136
137 for (;;) {
138 rc = wait_event_interruptible(endpoint->wait_q,
139 !list_empty(&endpoint->read_q));
140 rc = msm_rpc_read(endpoint, &buffer, -1, -1);
141 if (rc < 0) {
142 printk(KERN_ERR "%s: could not read: %d\n",
143 __FUNCTION__, rc);
144 break;
145 }
146 req = (struct rpc_request_hdr *)buffer;
147
148 req->type = be32_to_cpu(req->type);
149 req->xid = be32_to_cpu(req->xid);
150 req->rpc_vers = be32_to_cpu(req->rpc_vers);
151 req->prog = be32_to_cpu(req->prog);
152 req->vers = be32_to_cpu(req->vers);
153 req->procedure = be32_to_cpu(req->procedure);
154
155 server = rpc_server_find(req->prog, req->vers);
156
157 if (req->rpc_vers != 2)
158 continue;
159 if (req->type != 0)
160 continue;
161 if (!server) {
162 rpc_send_accepted_void_reply(
163 endpoint, req->xid,
164 RPC_ACCEPTSTAT_PROG_UNAVAIL);
165 continue;
166 }
167
168 rc = server->rpc_call(server, req, rc);
169
170 switch (rc) {
171 case 0:
172 rpc_send_accepted_void_reply(
173 endpoint, req->xid,
174 RPC_ACCEPTSTAT_SUCCESS);
175 break;
176 default:
177 rpc_send_accepted_void_reply(
178 endpoint, req->xid,
179 RPC_ACCEPTSTAT_PROG_UNAVAIL);
180 break;
181 }
182
183 kfree(buffer);
184 }
185
186 do_exit(0);
187}
188
189static int rpcservers_probe(struct platform_device *pdev)
190{
191 struct task_struct *server_thread;
192
193 endpoint = msm_rpc_open();
194 if (IS_ERR(endpoint))
195 return PTR_ERR(endpoint);
196
197 /* we're online -- register any servers installed beforehand */
198 rpc_servers_active = 1;
199 rpc_server_register_all();
200
201 /* start the kernel thread */
202 server_thread = kthread_run(rpc_servers_thread, NULL, "krpcserversd");
203 if (IS_ERR(server_thread))
204 return PTR_ERR(server_thread);
205
206 return 0;
207}
208
209static struct platform_driver rpcservers_driver = {
210 .probe = rpcservers_probe,
211 .driver = {
212 .name = "oncrpc_router",
213 .owner = THIS_MODULE,
214 },
215};
216
217static int __init rpc_servers_init(void)
218{
219 return platform_driver_register(&rpcservers_driver);
220}
221
222module_init(rpc_servers_init);
223
224MODULE_DESCRIPTION("MSM RPC Servers");
225MODULE_AUTHOR("Iliyan Malchev <ibm@android.com>");
226MODULE_LICENSE("GPL");
diff --git a/drivers/staging/dream/smd/smd_tty.c b/drivers/staging/dream/smd/smd_tty.c
deleted file mode 100644
index f40944958d44..000000000000
--- a/drivers/staging/dream/smd/smd_tty.c
+++ /dev/null
@@ -1,208 +0,0 @@
1/* arch/arm/mach-msm/smd_tty.c
2 *
3 * Copyright (C) 2007 Google, Inc.
4 * Author: Brian Swetland <swetland@google.com>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/fs.h>
19#include <linux/cdev.h>
20#include <linux/device.h>
21#include <linux/wait.h>
22
23#include <linux/tty.h>
24#include <linux/tty_driver.h>
25#include <linux/tty_flip.h>
26
27#include <mach/msm_smd.h>
28
29#define MAX_SMD_TTYS 32
30
31static DEFINE_MUTEX(smd_tty_lock);
32
33struct smd_tty_info {
34 smd_channel_t *ch;
35 struct tty_struct *tty;
36 int open_count;
37};
38
39static struct smd_tty_info smd_tty[MAX_SMD_TTYS];
40
41
42static void smd_tty_notify(void *priv, unsigned event)
43{
44 unsigned char *ptr;
45 int avail;
46 struct smd_tty_info *info = priv;
47 struct tty_struct *tty = info->tty;
48
49 if (!tty)
50 return;
51
52 if (event != SMD_EVENT_DATA)
53 return;
54
55 for (;;) {
56 if (test_bit(TTY_THROTTLED, &tty->flags)) break;
57 avail = smd_read_avail(info->ch);
58 if (avail == 0) break;
59
60 avail = tty_prepare_flip_string(tty, &ptr, avail);
61
62 if (smd_read(info->ch, ptr, avail) != avail) {
63 /* shouldn't be possible since we're in interrupt
64 ** context here and nobody else could 'steal' our
65 ** characters.
66 */
67 printk(KERN_ERR "OOPS - smd_tty_buffer mismatch?!");
68 }
69
70 tty_flip_buffer_push(tty);
71 }
72
73 /* XXX only when writable and necessary */
74 tty_wakeup(tty);
75}
76
77static int smd_tty_open(struct tty_struct *tty, struct file *f)
78{
79 int res = 0;
80 int n = tty->index;
81 struct smd_tty_info *info;
82 const char *name;
83
84 if (n == 0) {
85 name = "SMD_DS";
86 } else if (n == 27) {
87 name = "SMD_GPSNMEA";
88 } else {
89 return -ENODEV;
90 }
91
92 info = smd_tty + n;
93
94 mutex_lock(&smd_tty_lock);
95 tty->driver_data = info;
96
97 if (info->open_count++ == 0) {
98 info->tty = tty;
99 if (info->ch) {
100 smd_kick(info->ch);
101 } else {
102 res = smd_open(name, &info->ch, info, smd_tty_notify);
103 }
104 }
105 mutex_unlock(&smd_tty_lock);
106
107 return res;
108}
109
110static void smd_tty_close(struct tty_struct *tty, struct file *f)
111{
112 struct smd_tty_info *info = tty->driver_data;
113
114 if (info == 0)
115 return;
116
117 mutex_lock(&smd_tty_lock);
118 if (--info->open_count == 0) {
119 info->tty = 0;
120 tty->driver_data = 0;
121 if (info->ch) {
122 smd_close(info->ch);
123 info->ch = 0;
124 }
125 }
126 mutex_unlock(&smd_tty_lock);
127}
128
129static int smd_tty_write(struct tty_struct *tty, const unsigned char *buf, int len)
130{
131 struct smd_tty_info *info = tty->driver_data;
132 int avail;
133
134 /* if we're writing to a packet channel we will
135 ** never be able to write more data than there
136 ** is currently space for
137 */
138 avail = smd_write_avail(info->ch);
139 if (len > avail)
140 len = avail;
141
142 return smd_write(info->ch, buf, len);
143}
144
145static int smd_tty_write_room(struct tty_struct *tty)
146{
147 struct smd_tty_info *info = tty->driver_data;
148 return smd_write_avail(info->ch);
149}
150
151static int smd_tty_chars_in_buffer(struct tty_struct *tty)
152{
153 struct smd_tty_info *info = tty->driver_data;
154 return smd_read_avail(info->ch);
155}
156
157static void smd_tty_unthrottle(struct tty_struct *tty)
158{
159 struct smd_tty_info *info = tty->driver_data;
160 smd_kick(info->ch);
161}
162
163static struct tty_operations smd_tty_ops = {
164 .open = smd_tty_open,
165 .close = smd_tty_close,
166 .write = smd_tty_write,
167 .write_room = smd_tty_write_room,
168 .chars_in_buffer = smd_tty_chars_in_buffer,
169 .unthrottle = smd_tty_unthrottle,
170};
171
172static struct tty_driver *smd_tty_driver;
173
174static int __init smd_tty_init(void)
175{
176 int ret;
177
178 smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
179 if (smd_tty_driver == 0)
180 return -ENOMEM;
181
182 smd_tty_driver->owner = THIS_MODULE;
183 smd_tty_driver->driver_name = "smd_tty_driver";
184 smd_tty_driver->name = "smd";
185 smd_tty_driver->major = 0;
186 smd_tty_driver->minor_start = 0;
187 smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
188 smd_tty_driver->subtype = SERIAL_TYPE_NORMAL;
189 smd_tty_driver->init_termios = tty_std_termios;
190 smd_tty_driver->init_termios.c_iflag = 0;
191 smd_tty_driver->init_termios.c_oflag = 0;
192 smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
193 smd_tty_driver->init_termios.c_lflag = 0;
194 smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS |
195 TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
196 tty_set_operations(smd_tty_driver, &smd_tty_ops);
197
198 ret = tty_register_driver(smd_tty_driver);
199 if (ret) return ret;
200
201 /* this should be dynamic */
202 tty_register_device(smd_tty_driver, 0, 0);
203 tty_register_device(smd_tty_driver, 27, 0);
204
205 return 0;
206}
207
208module_init(smd_tty_init);