aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core/sdio_cis.c
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2007-06-16 02:06:47 -0400
committerPierre Ossman <drzeus@drzeus.cx>2007-09-23 14:31:43 -0400
commitb1538bcf75e2e11459947ec4d4329ed04fbe2b2c (patch)
treeb190714969b66b1ca0cef1d96cb0547d5e959d0d /drivers/mmc/core/sdio_cis.c
parentb726126196d54cbbba0924191e5c4dd5ba747fa2 (diff)
sdio: link unknown CIS tuples to the sdio_func structure
This way those tuples that the core cares about are consumed by the core code, and tuples that only function drivers might make sense of are available to drivers. Signed-off-by: Nicolas Pitre <npitre@mvista.com> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
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