Commit b1538bcf authored by Nicolas Pitre's avatar Nicolas Pitre Committed by Pierre Ossman

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: default avatarNicolas Pitre <npitre@mvista.com>
Signed-off-by: default avatarPierre Ossman <drzeus@drzeus.cx>
parent b7261261
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
#include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_func.h>
#include "sdio_cis.h"
#include "sdio_bus.h" #include "sdio_bus.h"
#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) #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,6 +95,8 @@ static void sdio_release_func(struct device *dev)
{ {
struct sdio_func *func = dev_to_sdio_func(dev); struct sdio_func *func = dev_to_sdio_func(dev);
sdio_free_cis(func);
kfree(func); kfree(func);
} }
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
* Created: June 11, 2007 * Created: June 11, 2007
* Copyright: MontaVista Software Inc. * Copyright: MontaVista Software Inc.
* *
* Copyright 2007 Pierre Ossman
*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at * 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,7 +51,7 @@ static const struct cis_tpl cis_tpl_list[] = {
int sdio_read_cis(struct sdio_func *func) int sdio_read_cis(struct sdio_func *func)
{ {
int ret; int ret;
unsigned char *buf; struct sdio_func_tuple *this, **prev;
unsigned i, ptr = 0; unsigned i, ptr = 0;
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
...@@ -61,13 +63,11 @@ int sdio_read_cis(struct sdio_func *func) ...@@ -61,13 +63,11 @@ int sdio_read_cis(struct sdio_func *func)
ptr |= x << (i * 8); ptr |= x << (i * 8);
} }
buf = kmalloc(256, GFP_KERNEL); /* find the list tail */
if (!buf) for (prev = &func->tuples; *prev; prev = &(*prev)->next);
return -ENOMEM;
do { do {
unsigned char tpl_code, tpl_link; unsigned char tpl_code, tpl_link;
const struct cis_tpl *tpl;
ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_code); ret = mmc_io_rw_direct(func->card, 0, 0, ptr++, 0, &tpl_code);
if (ret) if (ret)
...@@ -81,39 +81,64 @@ int sdio_read_cis(struct sdio_func *func) ...@@ -81,39 +81,64 @@ int sdio_read_cis(struct sdio_func *func)
if (ret) if (ret)
break; break;
for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++) this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL);
if (cis_tpl_list[i].code == tpl_code) if (!this)
return -ENOMEM;
for (i = 0; i < tpl_link; i++) {
ret = mmc_io_rw_direct(func->card, 0, 0,
ptr + i, 0, &this->data[i]);
if (ret)
break; break;
if (i >= ARRAY_SIZE(cis_tpl_list)) {
printk(KERN_WARNING
"%s: unknown CIS tuple 0x%02x of length %u\n",
sdio_func_id(func), tpl_code, tpl_link);
ptr += tpl_link;
continue;
} }
tpl = cis_tpl_list + i; if (ret) {
kfree(this);
if (tpl_link < tpl->min_size) {
printk(KERN_ERR
"%s: bad CIS tuple 0x%02x (length = %u, expected >= %u\n",
sdio_func_id(func), tpl_code, tpl_link, tpl->min_size);
ret = -EINVAL;
break; break;
} }
for (i = 0; i < tpl_link; i++) { for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++)
ret = mmc_io_rw_direct(func->card, 0, 0, ptr + i, 0, &buf[i]); if (cis_tpl_list[i].code == tpl_code)
if (ret)
break; break;
if (i >= ARRAY_SIZE(cis_tpl_list)) {
/* this tuple is unknown to the core */
this->next = NULL;
this->code = tpl_code;
this->size = tpl_link;
*prev = this;
prev = &this->next;
printk(KERN_DEBUG
"%s: queuing CIS tuple 0x%02x length %u\n",
sdio_func_id(func), tpl_code, tpl_link);
} else {
const struct cis_tpl *tpl = cis_tpl_list + i;
if (tpl_link < tpl->min_size) {
printk(KERN_ERR
"%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n",
sdio_func_id(func), tpl_code, tpl_link, tpl->min_size);
ret = -EINVAL;
} else if (tpl->parse)
ret = tpl->parse(func, this->data, tpl_link);
kfree(this);
} }
if (ret)
break;
ptr += tpl_link;
if (tpl->parse) ptr += tpl_link;
ret = tpl->parse(func, buf, tpl_link);
} while (!ret); } while (!ret);
kfree(buf);
return ret; return ret;
} }
void sdio_free_cis(struct sdio_func *func)
{
struct sdio_func_tuple *tuple, *victim;
tuple = func->tuples;
while (tuple) {
victim = tuple;
tuple = tuple->next;
kfree(victim);
}
func->tuples = NULL;
}
...@@ -15,5 +15,6 @@ ...@@ -15,5 +15,6 @@
#define _MMC_SDIO_CIS_H #define _MMC_SDIO_CIS_H
int sdio_read_cis(struct sdio_func *func); int sdio_read_cis(struct sdio_func *func);
void sdio_free_cis(struct sdio_func *func);
#endif #endif
...@@ -14,6 +14,16 @@ ...@@ -14,6 +14,16 @@
struct mmc_card; struct mmc_card;
/*
* SDIO function CIS tuple (unknown to the core)
*/
struct sdio_func_tuple {
struct sdio_func_tuple *next;
unsigned char code;
unsigned char size;
unsigned char data[0];
};
/* /*
* SDIO function devices * SDIO function devices
*/ */
...@@ -28,6 +38,8 @@ struct sdio_func { ...@@ -28,6 +38,8 @@ struct sdio_func {
unsigned int state; /* function state */ unsigned int state; /* function state */
#define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */ #define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */
struct sdio_func_tuple *tuples;
}; };
#define sdio_func_present(f) ((f)->state & SDIO_STATE_PRESENT) #define sdio_func_present(f) ((f)->state & SDIO_STATE_PRESENT)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment