aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core/sdio_cis.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/core/sdio_cis.c')
-rw-r--r--drivers/mmc/core/sdio_cis.c83
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[] = {
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