blob: 94a2d26fc90eaaf6c418a6a55464d16a90ad130d [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13/*
14 * RPCROUTER SDIO XPRT module.
15 */
16
17#include <linux/platform_device.h>
18#include <linux/types.h>
19#include <linux/module.h>
20#include <linux/kernel.h>
21#include <linux/string.h>
22#include <linux/errno.h>
23#include <linux/init.h>
24#include <linux/device.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/wakelock.h>
31#include <asm/uaccess.h>
32#include <linux/slab.h>
33
34#include <mach/sdio_al.h>
35#include "smd_rpcrouter.h"
36
37enum {
38 MSM_SDIO_XPRT_DEBUG = 1U << 0,
39 MSM_SDIO_XPRT_INFO = 1U << 1,
40};
41
42static int msm_sdio_xprt_debug_mask;
43module_param_named(debug_mask, msm_sdio_xprt_debug_mask,
44 int, S_IRUGO | S_IWUSR | S_IWGRP);
45
46#if defined(CONFIG_MSM_RPC_SDIO_DEBUG)
47#define SDIO_XPRT_DBG(x...) do { \
48 if (msm_sdio_xprt_debug_mask & MSM_SDIO_XPRT_DEBUG) \
49 printk(KERN_DEBUG x); \
50 } while (0)
51
52#define SDIO_XPRT_INFO(x...) do { \
53 if (msm_sdio_xprt_debug_mask & MSM_SDIO_XPRT_INFO) \
54 printk(KERN_INFO x); \
55 } while (0)
56#else
57#define SDIO_XPRT_DBG(x...) do { } while (0)
58#define SDIO_XPRT_INFO(x...) do { } while (0)
59#endif
60
61#define MAX_SDIO_WRITE_RETRY 5
62#define SDIO_BUF_SIZE (RPCROUTER_MSGSIZE_MAX + sizeof(struct rr_header) - 8)
63#define NUM_SDIO_BUFS 20
64#define MAX_TX_BUFS 10
65#define MAX_RX_BUFS 10
66
67struct sdio_xprt {
68 struct sdio_channel *handle;
69
70 struct list_head write_list;
71 spinlock_t write_list_lock;
72
73 struct list_head read_list;
74 spinlock_t read_list_lock;
75
76 struct list_head free_list;
77 spinlock_t free_list_lock;
78
79 struct wake_lock read_wakelock;
80};
81
82struct rpcrouter_sdio_xprt {
83 struct rpcrouter_xprt xprt;
84 struct sdio_xprt *channel;
85};
86
87static struct rpcrouter_sdio_xprt sdio_remote_xprt;
88
89static void sdio_xprt_read_data(struct work_struct *work);
90static DECLARE_DELAYED_WORK(work_read_data, sdio_xprt_read_data);
91static struct workqueue_struct *sdio_xprt_read_workqueue;
92
93struct sdio_buf_struct {
94 struct list_head list;
95 uint32_t size;
96 uint32_t read_index;
97 uint32_t write_index;
98 unsigned char data[SDIO_BUF_SIZE];
99};
100
101static void sdio_xprt_write_data(struct work_struct *work);
102static DECLARE_WORK(work_write_data, sdio_xprt_write_data);
103static wait_queue_head_t write_avail_wait_q;
104static uint32_t num_free_bufs;
105static uint32_t num_tx_bufs;
106static uint32_t num_rx_bufs;
107
108static DEFINE_MUTEX(modem_reset_lock);
109static uint32_t modem_reset;
110
111static void free_sdio_xprt(struct sdio_xprt *chnl)
112{
113 struct sdio_buf_struct *buf;
114 unsigned long flags;
115
116 if (!chnl) {
117 printk(KERN_ERR "Invalid chnl to free\n");
118 return;
119 }
120
121 spin_lock_irqsave(&chnl->free_list_lock, flags);
122 while (!list_empty(&chnl->free_list)) {
123 buf = list_first_entry(&chnl->free_list,
124 struct sdio_buf_struct, list);
125 list_del(&buf->list);
126 kfree(buf);
127 }
128 num_free_bufs = 0;
129 spin_unlock_irqrestore(&chnl->free_list_lock, flags);
130
131 spin_lock_irqsave(&chnl->write_list_lock, flags);
132 while (!list_empty(&chnl->write_list)) {
133 buf = list_first_entry(&chnl->write_list,
134 struct sdio_buf_struct, list);
135 list_del(&buf->list);
136 kfree(buf);
137 }
138 num_tx_bufs = 0;
139 spin_unlock_irqrestore(&chnl->write_list_lock, flags);
140
141 spin_lock_irqsave(&chnl->read_list_lock, flags);
142 while (!list_empty(&chnl->read_list)) {
143 buf = list_first_entry(&chnl->read_list,
144 struct sdio_buf_struct, list);
145 list_del(&buf->list);
146 kfree(buf);
147 }
148 num_rx_bufs = 0;
149 spin_unlock_irqrestore(&chnl->read_list_lock, flags);
150 wake_unlock(&chnl->read_wakelock);
151}
152
153static struct sdio_buf_struct *alloc_from_free_list(struct sdio_xprt *chnl)
154{
155 struct sdio_buf_struct *buf;
156 unsigned long flags;
157
158 spin_lock_irqsave(&chnl->free_list_lock, flags);
159 if (list_empty(&chnl->free_list)) {
160 spin_unlock_irqrestore(&chnl->free_list_lock, flags);
161 SDIO_XPRT_DBG("%s: Free list empty\n", __func__);
162 return NULL;
163 }
164 buf = list_first_entry(&chnl->free_list, struct sdio_buf_struct, list);
165 list_del(&buf->list);
166 num_free_bufs--;
167 spin_unlock_irqrestore(&chnl->free_list_lock, flags);
168
169 buf->size = 0;
170 buf->read_index = 0;
171 buf->write_index = 0;
172
173 return buf;
174}
175
176static void return_to_free_list(struct sdio_xprt *chnl,
177 struct sdio_buf_struct *buf)
178{
179 unsigned long flags;
180
181 if (!chnl || !buf) {
182 pr_err("%s: Invalid chnl or buf\n", __func__);
183 return;
184 }
185
186 buf->size = 0;
187 buf->read_index = 0;
188 buf->write_index = 0;
189
190 spin_lock_irqsave(&chnl->free_list_lock, flags);
191 list_add_tail(&buf->list, &chnl->free_list);
192 num_free_bufs++;
193 spin_unlock_irqrestore(&chnl->free_list_lock, flags);
194
195}
196
197static int rpcrouter_sdio_remote_read_avail(void)
198{
199 int read_avail = 0;
200 unsigned long flags;
201 struct sdio_buf_struct *buf;
202
203 spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock, flags);
204 list_for_each_entry(buf, &sdio_remote_xprt.channel->read_list, list) {
205 read_avail += buf->size;
206 }
207 spin_unlock_irqrestore(&sdio_remote_xprt.channel->read_list_lock,
208 flags);
209 return read_avail;
210}
211
212static int rpcrouter_sdio_remote_read(void *data, uint32_t len)
213{
214 struct sdio_buf_struct *buf;
215 unsigned char *buf_data;
216 unsigned long flags;
217
218 SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
219 if (len < 0 || !data)
220 return -EINVAL;
221 else if (len == 0)
222 return 0;
223
224 spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock, flags);
225 if (list_empty(&sdio_remote_xprt.channel->read_list)) {
226 spin_unlock_irqrestore(
227 &sdio_remote_xprt.channel->read_list_lock, flags);
228 return -EINVAL;
229 }
230
231 buf = list_first_entry(&sdio_remote_xprt.channel->read_list,
232 struct sdio_buf_struct, list);
233 if (buf->size < len) {
234 spin_unlock_irqrestore(
235 &sdio_remote_xprt.channel->read_list_lock, flags);
236 return -EINVAL;
237 }
238
239 buf_data = buf->data + buf->read_index;
240 memcpy(data, buf_data, len);
241 buf->read_index += len;
242 buf->size -= len;
243 if (buf->size == 0) {
244 list_del(&buf->list);
245 num_rx_bufs--;
246 return_to_free_list(sdio_remote_xprt.channel, buf);
247 }
248
249 if (list_empty(&sdio_remote_xprt.channel->read_list))
250 wake_unlock(&sdio_remote_xprt.channel->read_wakelock);
251 spin_unlock_irqrestore(&sdio_remote_xprt.channel->read_list_lock,
252 flags);
253 return len;
254}
255
256static int rpcrouter_sdio_remote_write_avail(void)
257{
258 uint32_t write_avail = 0;
259 unsigned long flags;
260
261 SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
262 spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock, flags);
263 write_avail = (MAX_TX_BUFS - num_tx_bufs) * SDIO_BUF_SIZE;
264 spin_unlock_irqrestore(&sdio_remote_xprt.channel->write_list_lock,
265 flags);
266 return write_avail;
267}
268
269static int rpcrouter_sdio_remote_write(void *data, uint32_t len,
270 enum write_data_type type)
271{
272 unsigned long flags;
273 static struct sdio_buf_struct *buf;
274 unsigned char *buf_data;
275
276 switch (type) {
277 case HEADER:
278 spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock,
279 flags);
280 if (num_tx_bufs == MAX_TX_BUFS) {
281 spin_unlock_irqrestore(
282 &sdio_remote_xprt.channel->write_list_lock,
283 flags);
284 return -ENOMEM;
285 }
286 spin_unlock_irqrestore(
287 &sdio_remote_xprt.channel->write_list_lock, flags);
288
289 SDIO_XPRT_DBG("sdio_xprt WRITE HEADER %s\n", __func__);
290 buf = alloc_from_free_list(sdio_remote_xprt.channel);
291 if (!buf) {
292 pr_err("%s: alloc_from_free_list failed\n", __func__);
293 return -ENOMEM;
294 }
295 buf_data = buf->data + buf->write_index;
296 memcpy(buf_data, data, len);
297 buf->write_index += len;
298 buf->size += len;
299 return len;
300 case PACKMARK:
301 SDIO_XPRT_DBG("sdio_xprt WRITE PACKMARK %s\n", __func__);
302 if (!buf) {
303 pr_err("%s: HEADER not written or alloc failed\n",
304 __func__);
305 return -ENOMEM;
306 }
307 buf_data = buf->data + buf->write_index;
308 memcpy(buf_data, data, len);
309 buf->write_index += len;
310 buf->size += len;
311 return len;
312 case PAYLOAD:
313 SDIO_XPRT_DBG("sdio_xprt WRITE PAYLOAD %s\n", __func__);
314 if (!buf) {
315 pr_err("%s: HEADER not written or alloc failed\n",
316 __func__);
317 return -ENOMEM;
318 }
319 buf_data = buf->data + buf->write_index;
320 memcpy(buf_data, data, len);
321 buf->write_index += len;
322 buf->size += len;
323
324 SDIO_XPRT_DBG("sdio_xprt flush %d bytes\n", buf->size);
325 spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock,
326 flags);
327 list_add_tail(&buf->list,
328 &sdio_remote_xprt.channel->write_list);
329 num_tx_bufs++;
330 spin_unlock_irqrestore(
331 &sdio_remote_xprt.channel->write_list_lock, flags);
332 queue_work(sdio_xprt_read_workqueue, &work_write_data);
333 buf = NULL;
334 return len;
335 default:
336 return -EINVAL;
337 }
338}
339
340static void sdio_xprt_write_data(struct work_struct *work)
341{
342 int rc = 0, sdio_write_retry = 0;
343 unsigned long flags;
344 struct sdio_buf_struct *buf;
345
346 mutex_lock(&modem_reset_lock);
347 if (modem_reset) {
348 mutex_unlock(&modem_reset_lock);
349 return;
350 }
351
352 spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock, flags);
353 while (!list_empty(&sdio_remote_xprt.channel->write_list)) {
354 buf = list_first_entry(&sdio_remote_xprt.channel->write_list,
355 struct sdio_buf_struct, list);
356 list_del(&buf->list);
357 spin_unlock_irqrestore(
358 &sdio_remote_xprt.channel->write_list_lock, flags);
359 mutex_unlock(&modem_reset_lock);
360
361 wait_event(write_avail_wait_q,
362 (!(modem_reset) && (sdio_write_avail(
363 sdio_remote_xprt.channel->handle) >=
364 buf->size)));
365
366 mutex_lock(&modem_reset_lock);
367 while (!(modem_reset) &&
368 ((rc = sdio_write(sdio_remote_xprt.channel->handle,
369 buf->data, buf->size)) < 0) &&
370 (sdio_write_retry++ < MAX_SDIO_WRITE_RETRY)) {
371 printk(KERN_ERR "sdio_write failed with RC %d\n", rc);
372 mutex_unlock(&modem_reset_lock);
373 msleep(250);
374 mutex_lock(&modem_reset_lock);
375 }
376 if (modem_reset) {
377 mutex_unlock(&modem_reset_lock);
378 kfree(buf);
379 return;
380 } else {
381 return_to_free_list(sdio_remote_xprt.channel, buf);
382 }
383
384 if (!rc)
385 SDIO_XPRT_DBG("sdio_write %d bytes completed\n",
386 buf->size);
387
388 spin_lock_irqsave(&sdio_remote_xprt.channel->write_list_lock,
389 flags);
390 num_tx_bufs--;
391 }
392 spin_unlock_irqrestore(&sdio_remote_xprt.channel->write_list_lock,
393 flags);
394 mutex_unlock(&modem_reset_lock);
395}
396
397static int rpcrouter_sdio_remote_close(void)
398{
399 SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
400 flush_workqueue(sdio_xprt_read_workqueue);
401 sdio_close(sdio_remote_xprt.channel->handle);
402 free_sdio_xprt(sdio_remote_xprt.channel);
403 return 0;
404}
405
406static void sdio_xprt_read_data(struct work_struct *work)
407{
408 int size = 0, read_avail;
409 unsigned long flags;
410 struct sdio_buf_struct *buf;
411 SDIO_XPRT_DBG("sdio_xprt Called %s\n", __func__);
412
413 mutex_lock(&modem_reset_lock);
414 while (!(modem_reset) &&
415 ((read_avail =
416 sdio_read_avail(sdio_remote_xprt.channel->handle)) > 0)) {
417 spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock,
418 flags);
419 if (num_rx_bufs == MAX_RX_BUFS) {
420 spin_unlock_irqrestore(
421 &sdio_remote_xprt.channel->read_list_lock,
422 flags);
423 queue_delayed_work(sdio_xprt_read_workqueue,
424 &work_read_data,
425 msecs_to_jiffies(100));
426 break;
427 }
428 spin_unlock_irqrestore(
429 &sdio_remote_xprt.channel->read_list_lock, flags);
430
431 buf = alloc_from_free_list(sdio_remote_xprt.channel);
432 if (!buf) {
433 SDIO_XPRT_DBG("%s: Failed to alloc_from_free_list"
434 " Try again later\n", __func__);
435 queue_delayed_work(sdio_xprt_read_workqueue,
436 &work_read_data,
437 msecs_to_jiffies(100));
438 break;
439 }
440
441 size = sdio_read(sdio_remote_xprt.channel->handle,
442 buf->data, read_avail);
443 if (size < 0) {
444 printk(KERN_ERR "sdio_read failed,"
445 " read %d bytes, expected %d\n",
446 size, read_avail);
447 return_to_free_list(sdio_remote_xprt.channel, buf);
448 queue_delayed_work(sdio_xprt_read_workqueue,
449 &work_read_data,
450 msecs_to_jiffies(100));
451 break;
452 }
453
454 if (size == 0)
455 size = read_avail;
456
457 buf->size = size;
458 buf->write_index = size;
459 spin_lock_irqsave(&sdio_remote_xprt.channel->read_list_lock,
460 flags);
461 list_add_tail(&buf->list,
462 &sdio_remote_xprt.channel->read_list);
463 num_rx_bufs++;
464 spin_unlock_irqrestore(
465 &sdio_remote_xprt.channel->read_list_lock, flags);
466 wake_lock(&sdio_remote_xprt.channel->read_wakelock);
467 }
468
469 if (!modem_reset && !list_empty(&sdio_remote_xprt.channel->read_list))
470 msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt,
471 RPCROUTER_XPRT_EVENT_DATA);
472 mutex_unlock(&modem_reset_lock);
473}
474
475static void rpcrouter_sdio_remote_notify(void *_dev, unsigned event)
476{
477 if (event == SDIO_EVENT_DATA_READ_AVAIL) {
478 SDIO_XPRT_DBG("%s Received Notify"
479 "SDIO_EVENT_DATA_READ_AVAIL\n", __func__);
480 queue_delayed_work(sdio_xprt_read_workqueue,
481 &work_read_data, 0);
482 }
483 if (event == SDIO_EVENT_DATA_WRITE_AVAIL) {
484 SDIO_XPRT_DBG("%s Received Notify"
485 "SDIO_EVENT_DATA_WRITE_AVAIL\n", __func__);
486 wake_up(&write_avail_wait_q);
487 }
488}
489
490static int allocate_sdio_xprt(struct sdio_xprt **sdio_xprt_chnl)
491{
492 struct sdio_buf_struct *buf;
493 struct sdio_xprt *chnl;
494 int i;
495 unsigned long flags;
496 int rc = -ENOMEM;
497
498 if (!(*sdio_xprt_chnl)) {
499 chnl = kmalloc(sizeof(struct sdio_xprt), GFP_KERNEL);
500 if (!chnl) {
501 printk(KERN_ERR "sdio_xprt channel"
502 " allocation failed\n");
503 return rc;
504 }
505
506 spin_lock_init(&chnl->write_list_lock);
507 spin_lock_init(&chnl->read_list_lock);
508 spin_lock_init(&chnl->free_list_lock);
509
510 INIT_LIST_HEAD(&chnl->write_list);
511 INIT_LIST_HEAD(&chnl->read_list);
512 INIT_LIST_HEAD(&chnl->free_list);
513 wake_lock_init(&chnl->read_wakelock,
514 WAKE_LOCK_SUSPEND, "rpc_sdio_xprt_read");
515 } else {
516 chnl = *sdio_xprt_chnl;
517 }
518
519 for (i = 0; i < NUM_SDIO_BUFS; i++) {
520 buf = kzalloc(sizeof(struct sdio_buf_struct), GFP_KERNEL);
521 if (!buf) {
522 printk(KERN_ERR "sdio_buf_struct alloc failed\n");
523 goto alloc_failure;
524 }
525 spin_lock_irqsave(&chnl->free_list_lock, flags);
526 list_add_tail(&buf->list, &chnl->free_list);
527 spin_unlock_irqrestore(&chnl->free_list_lock, flags);
528 }
529 num_free_bufs = NUM_SDIO_BUFS;
530
531 *sdio_xprt_chnl = chnl;
532 return 0;
533
534alloc_failure:
535 spin_lock_irqsave(&chnl->free_list_lock, flags);
536 while (!list_empty(&chnl->free_list)) {
537 buf = list_first_entry(&chnl->free_list,
538 struct sdio_buf_struct,
539 list);
540 list_del(&buf->list);
541 kfree(buf);
542 }
543 spin_unlock_irqrestore(&chnl->free_list_lock, flags);
544 wake_lock_destroy(&chnl->read_wakelock);
545
546 kfree(chnl);
547 *sdio_xprt_chnl = NULL;
548 return rc;
549}
550
551static int rpcrouter_sdio_remote_probe(struct platform_device *pdev)
552{
553 int rc;
554
555 SDIO_XPRT_INFO("%s Called\n", __func__);
556
557 mutex_lock(&modem_reset_lock);
558 if (!modem_reset) {
559 sdio_xprt_read_workqueue =
560 create_singlethread_workqueue("sdio_xprt");
561 if (!sdio_xprt_read_workqueue) {
562 mutex_unlock(&modem_reset_lock);
563 return -ENOMEM;
564 }
565
566 sdio_remote_xprt.xprt.name = "rpcrotuer_sdio_xprt";
567 sdio_remote_xprt.xprt.read_avail =
568 rpcrouter_sdio_remote_read_avail;
569 sdio_remote_xprt.xprt.read = rpcrouter_sdio_remote_read;
570 sdio_remote_xprt.xprt.write_avail =
571 rpcrouter_sdio_remote_write_avail;
572 sdio_remote_xprt.xprt.write = rpcrouter_sdio_remote_write;
573 sdio_remote_xprt.xprt.close = rpcrouter_sdio_remote_close;
574 sdio_remote_xprt.xprt.priv = NULL;
575
576 init_waitqueue_head(&write_avail_wait_q);
577 }
Karthikeyan Ramasubramanian4b85a2f2011-07-20 18:04:40 -0600578 modem_reset = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700579
580 rc = allocate_sdio_xprt(&sdio_remote_xprt.channel);
581 if (rc) {
582 destroy_workqueue(sdio_xprt_read_workqueue);
Karthikeyan Ramasubramanian4b85a2f2011-07-20 18:04:40 -0600583 mutex_unlock(&modem_reset_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700584 return rc;
585 }
586
587 /* Open up SDIO channel */
588 rc = sdio_open("SDIO_RPC", &sdio_remote_xprt.channel->handle, NULL,
589 rpcrouter_sdio_remote_notify);
590
591 if (rc < 0) {
592 free_sdio_xprt(sdio_remote_xprt.channel);
593 destroy_workqueue(sdio_xprt_read_workqueue);
Karthikeyan Ramasubramanian4b85a2f2011-07-20 18:04:40 -0600594 mutex_unlock(&modem_reset_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700595 return rc;
596 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700597 mutex_unlock(&modem_reset_lock);
598
599 msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt,
600 RPCROUTER_XPRT_EVENT_OPEN);
601
602 SDIO_XPRT_INFO("%s Completed\n", __func__);
603
604 return 0;
605}
606
607static int rpcrouter_sdio_remote_remove(struct platform_device *pdev)
608{
609 SDIO_XPRT_INFO("%s Called\n", __func__);
610
611 mutex_lock(&modem_reset_lock);
612 modem_reset = 1;
613 wake_up(&write_avail_wait_q);
614 free_sdio_xprt(sdio_remote_xprt.channel);
615 mutex_unlock(&modem_reset_lock);
616
617 msm_rpcrouter_xprt_notify(&sdio_remote_xprt.xprt,
618 RPCROUTER_XPRT_EVENT_CLOSE);
619
620 SDIO_XPRT_INFO("%s Completed\n", __func__);
621
622 return 0;
623}
624
625/*Remove this platform driver after mainline of SDIO_AL update*/
626static struct platform_driver rpcrouter_sdio_remote_driver = {
627 .probe = rpcrouter_sdio_remote_probe,
628 .driver = {
629 .name = "SDIO_AL",
630 .owner = THIS_MODULE,
631 },
632};
633
634static struct platform_driver rpcrouter_sdio_driver = {
635 .probe = rpcrouter_sdio_remote_probe,
636 .remove = rpcrouter_sdio_remote_remove,
637 .driver = {
638 .name = "SDIO_RPC",
639 .owner = THIS_MODULE,
640 },
641};
642
643static int __init rpcrouter_sdio_init(void)
644{
645 int rc;
646 msm_sdio_xprt_debug_mask = 0x2;
647 rc = platform_driver_register(&rpcrouter_sdio_remote_driver);
648 if (rc < 0)
649 return rc;
650 return platform_driver_register(&rpcrouter_sdio_driver);
651}
652
653module_init(rpcrouter_sdio_init);
654MODULE_DESCRIPTION("RPC Router SDIO XPRT");
655MODULE_LICENSE("GPL v2");