diff options
Diffstat (limited to 'drivers/mmc/core/sdio_cis.c')
-rw-r--r-- | drivers/mmc/core/sdio_cis.c | 83 |
1 files changed, 54 insertions, 29 deletions
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[] = { | |||
49 | int sdio_read_cis(struct sdio_func *func) | 51 | int 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 | |||
130 | void 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 | |||