aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
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
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')
-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
3 files changed, 58 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