aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/core/sdio_bus.c3
-rw-r--r--drivers/mmc/core/sdio_cis.c83
-rw-r--r--drivers/mmc/core/sdio_cis.h1
-rw-r--r--include/linux/mmc/sdio_func.h12
4 files changed, 70 insertions, 29 deletions
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index fa488cea8594..78e0381f55ac 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -17,6 +17,7 @@
17#include <linux/mmc/card.h> 17#include <linux/mmc/card.h>
18#include <linux/mmc/sdio_func.h> 18#include <linux/mmc/sdio_func.h>
19 19
20#include "sdio_cis.h"
20#include "sdio_bus.h" 21#include "sdio_bus.h"
21 22
22#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) 23#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev)
@@ -94,6 +95,8 @@ static void sdio_release_func(struct device *dev)
94{ 95{
95 struct sdio_func *func = dev_to_sdio_func(dev); 96 struct sdio_func *func = dev_to_sdio_func(dev);
96 97
98 sdio_free_cis(func);
99
97 kfree(func); 100 kfree(func);
98} 101}
99 102
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
index 114b600cd788..b6c7342572c1 100644
--- a/drivers/mmc/core/sdio_cis.c
+++ b/drivers/mmc/core/sdio_cis.c
@@ -5,6 +5,8 @@
5 * Created: June 11, 2007 5 * Created: June 11, 2007
6 * Copyright: MontaVista Software Inc. 6 * Copyright: MontaVista Software Inc.
7 * 7 *
8 * Copyright 2007 Pierre Ossman
9 *
8 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 11 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at 12 * the Free Software Foundation; either version 2 of the License, or (at
@@ -49,7 +51,7 @@ static const struct cis_tpl cis_tpl_list[] = {
49int sdio_read_cis(struct sdio_func *func) 51int sdio_read_cis(struct sdio_func *func)
50{ 52{
51 int ret; 53 int ret;
52 unsigned char *buf; 54 struct sdio_func_tuple *this, **prev;
53 unsigned i, ptr = 0; 55 unsigned i, ptr = 0;
54 56
55 for (i = 0; i < 3; i++) { 57 for (i = 0; i < 3; i++) {
@@ -61,13 +63,11 @@ int sdio_read_cis(struct sdio_func *func)
61 ptr |= x << (i * 8); 63 ptr |= x << (i * 8);
62 } 64 }
63 65
64 buf = kmalloc(256, GFP_KERNEL); 66 /* find the list tail */
65 if (!buf) 67 for (prev = &func->tuples; *prev; prev = &(*prev)->next);
66 return -ENOMEM;
67 68
68 do { 69 do {
69 unsigned char tpl_code, tpl_link; 70 unsigned char tpl_code, tpl_link;
70 const struct cis_tpl *tpl;
71 71
72 ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_code); 72 ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_code);
73 if (ret) 73 if (ret)
@@ -81,39 +81,64 @@ int sdio_read_cis(struct sdio_func *func)
81 if (ret) 81 if (ret)
82 break; 82 break;
83 83
84 for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++) 84 this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL);
85 if (cis_tpl_list[i].code == tpl_code) 85 if (!this)
86 return -ENOMEM;
87
88 for (i = 0; i < tpl_link; i++) {
89 ret = mmc_io_rw_direct(func->card, 0, 0,
90 ptr + i, 0, &this->data[i]);
91 if (ret)
86 break; 92 break;
87 if (i >= ARRAY_SIZE(cis_tpl_list)) {
88 printk(KERN_WARNING
89 "%s: unknown CIS tuple 0x%02x of length %u\n",
90 sdio_func_id(func), tpl_code, tpl_link);
91 ptr += tpl_link;
92 continue;
93 } 93 }
94 tpl = cis_tpl_list + i; 94 if (ret) {
95 95 kfree(this);
96 if (tpl_link < tpl->min_size) {
97 printk(KERN_ERR
98 "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u\n",
99 sdio_func_id(func), tpl_code, tpl_link, tpl->min_size);
100 ret = -EINVAL;
101 break; 96 break;
102 } 97 }
103 98
104 for (i = 0; i < tpl_link; i++) { 99 for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++)
105 ret = mmc_io_rw_direct(func->card, 0, 0, ptr + i, 0, &buf[i]); 100 if (cis_tpl_list[i].code == tpl_code)
106 if (ret)
107 break; 101 break;
102 if (i >= ARRAY_SIZE(cis_tpl_list)) {
103 /* this tuple is unknown to the core */
104 this->next = NULL;
105 this->code = tpl_code;
106 this->size = tpl_link;
107 *prev = this;
108 prev = &this->next;
109 printk(KERN_DEBUG
110 "%s: queuing CIS tuple 0x%02x length %u\n",
111 sdio_func_id(func), tpl_code, tpl_link);
112 } else {
113 const struct cis_tpl *tpl = cis_tpl_list + i;
114 if (tpl_link < tpl->min_size) {
115 printk(KERN_ERR
116 "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n",
117 sdio_func_id(func), tpl_code, tpl_link, tpl->min_size);
118 ret = -EINVAL;
119 } else if (tpl->parse)
120 ret = tpl->parse(func, this->data, tpl_link);
121 kfree(this);
108 } 122 }
109 if (ret)
110 break;
111 ptr += tpl_link;
112 123
113 if (tpl->parse) 124 ptr += tpl_link;
114 ret = tpl->parse(func, buf, tpl_link);
115 } while (!ret); 125 } while (!ret);
116 126
117 kfree(buf);
118 return ret; 127 return ret;
119} 128}
129
130void sdio_free_cis(struct sdio_func *func)
131{
132 struct sdio_func_tuple *tuple, *victim;
133
134 tuple = func->tuples;
135
136 while (tuple) {
137 victim = tuple;
138 tuple = tuple->next;
139 kfree(victim);
140 }
141
142 func->tuples = NULL;
143}
144
diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h
index df21c495d133..863d3d516371 100644
--- a/drivers/mmc/core/sdio_cis.h
+++ b/drivers/mmc/core/sdio_cis.h
@@ -15,5 +15,6 @@
15#define _MMC_SDIO_CIS_H 15#define _MMC_SDIO_CIS_H
16 16
17int sdio_read_cis(struct sdio_func *func); 17int sdio_read_cis(struct sdio_func *func);
18void sdio_free_cis(struct sdio_func *func);
18 19
19#endif 20#endif
diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h
index 4164809a8e63..269067663c8d 100644
--- a/include/linux/mmc/sdio_func.h
+++ b/include/linux/mmc/sdio_func.h
@@ -15,6 +15,16 @@
15struct mmc_card; 15struct mmc_card;
16 16
17/* 17/*
18 * SDIO function CIS tuple (unknown to the core)
19 */
20struct sdio_func_tuple {
21 struct sdio_func_tuple *next;
22 unsigned char code;
23 unsigned char size;
24 unsigned char data[0];
25};
26
27/*
18 * SDIO function devices 28 * SDIO function devices
19 */ 29 */
20struct sdio_func { 30struct sdio_func {
@@ -28,6 +38,8 @@ struct sdio_func {
28 38
29 unsigned int state; /* function state */ 39 unsigned int state; /* function state */
30#define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ 40#define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */
41
42 struct sdio_func_tuple *tuples;
31}; 43};
32 44
33#define sdio_func_present(f) ((f)->state & SDIO_STATE_PRESENT) 45#define sdio_func_present(f) ((f)->state & SDIO_STATE_PRESENT)