2009년 10월 14일 수요일

[진행중] Marvell 8686 소스 추적

============================================================================
관련 파일 추측
============================================================================
vim net/wireless/Kconfig
----------------------------------------------------------------------------
WIRELESS_OLD_REGULATORY [*] Old wireless static regulatory definitions
WIRELESS_EXT -*- Wireless extensions
WIRELESS_EXT_SYSFS [*] Wireless extensions sysfs files
LIB80211 -*- Common routines for IEEE802.11 drivers
----------------------------------------------------------------------------
vim net/wireless/Makefile
----------------------------------------------------------------------------
obj-$(CONFIG_WIRELESS_EXT) += wext.o
obj-$(CONFIG_LIB80211) += lib80211.o
----------------------------------------------------------------------------
wext.c
lib80211.c
lib80211_crypt_ccmp.c
lib80211_crypt_tkip.c
lib80211_crypt_wep.c
============================================================================
vim drivers/net/wireless/Kconfig
----------------------------------------------------------------------------
WLAN_PRE80211 [*] Wireless LAN (IEEE 802.11)
LIBERTAS <*> Marvell 8xxx Libertas WLAN driver support
LIBERTAS_SDIO
LIBERTAS_DEBUG [*] Enable full debugging output in the Libertas module.
<*> IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)
[*] Support downloading firmware images with Host AP driver
----------------------------------------------------------------------------
vim drivers/net/wireless/Makefile
vim drivers/net/wireless/libertas/Makefile
----------------------------------------------------------------------------
libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o debugfs.o persistcfg.o ethtool.o assoc.o
libertas_sdio-objs += if_sdio.o
obj-$(CONFIG_LIBERTAS) += libertas.o
obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o
----------------------------------------------------------------------------
11d.c
ethtool.c
persistcfg.c
assoc.c
if_sdio.c
rx.c
built-in.c
libertas.c
scan.c
cmd.c
libertas_sdio.mod.c
tx.c
cmdresp.c
libertas_sdio.c
wext.c
debugfs.c
main.c
============================================================================


============================================================================
drivers/net/wireless/libertas/if_sdio.c
- S3C6410 HSMMC 드라이버와 인터페이스 되는 파일
- 커널에 해당 디바이스 드라이버를 등록
- 펌웨어 다운로드 및 SDIO 인터페이스 초기화
----------------------------------------------------------------------------
module_init(if_sdio_init_module);
sdio_register_driver(&if_sdio_driver);
static struct sdio_driver if_sdio_driver = {
.name = "libertas_sdio",
.id_table = if_sdio_ids,
.probe = if_sdio_probe,
.remove = if_sdio_remove,
};
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━

drivers/mmc/core/sdio_bus.c
int sdio_register_driver(struct sdio_driver *drv)
{
drv->drv.name = drv->name;
drv->drv.bus = &sdio_bus_type;
return driver_register(&drv->drv);
}
EXPORT_SYMBOL_GPL(sdio_register_driver);
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/base/driver.c
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;

if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
other = driver_find(drv->name, drv->bus);
if (other) {
put_driver(other);
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EEXIST;
}
ret = bus_add_driver(drv);
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret)
bus_remove_driver(drv);

return ret;
}
EXPORT_SYMBOL_GPL(driver_register);
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/base/bus.c
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;

bus = bus_get(drv->bus);

if (!bus)
return -EINVAL;

pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);

if (error)
goto out_unregister;

if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
module_add_driver(drv->owner, drv);

error = driver_create_file(drv, &driver_attr_uevent);

if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
error = driver_add_attrs(bus, drv);

if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
__func__, drv->name);
}
error = add_bind_files(drv);

if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}

kobject_uevent(&priv->kobj, KOBJ_ADD);
return error;
out_unregister:
kobject_put(&priv->kobj);
out_put_bus:
bus_put(bus);
return error;
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/base/dd.c
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
EXPORT_SYMBOL_GPL(driver_attach);
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/base/dd.c
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;

//sdio_bus_match
if (drv->bus->match && !drv->bus->match(dev, drv))
return 0;

if (dev->parent) /* Needed for USB */
down(&dev->parent->sem);
down(&dev->sem);

if (!dev->driver)
driver_probe_device(drv, dev);
up(&dev->sem);

if (dev->parent)
up(&dev->parent->sem);

return 0;
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/base/dd.c
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;

if (!device_is_registered(dev))
return -ENODEV;
if (drv->bus->match && !drv->bus->match(dev, drv))////sdio_bus_match
goto done;

pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);

ret = really_probe(dev, drv);

done:
return ret;
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/base/dd.c
static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = 0;

atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
drv->bus->name, __func__, drv->name, dev_name(dev));
WARN_ON(!list_empty(&dev->devres_head));

dev->driver = drv;
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__func__, dev_name(dev));
goto probe_failed;
}

if (dev->bus->probe) {
ret = dev->bus->probe(dev);////sdio_bus_probe
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}

driver_bound(dev);
ret = 1;
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
goto done;

probe_failed:
devres_release_all(dev);
driver_sysfs_remove(dev);
dev->driver = NULL;

if (ret != -ENODEV && ret != -ENXIO) {
/* driver matched but the probe failed */
printk(KERN_WARNING
"%s: probe of %s failed with error %d\n",
drv->name, dev_name(dev), ret);
}
/*
* Ignore errors returned by ->probe so that the next driver can try
* its luck.
*/
ret = 0;
done:
atomic_dec(&probe_count);
wake_up(&probe_waitqueue);
return ret;
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/mmc/core/sdio_bus.c
static int sdio_bus_probe(struct device *dev)
{
struct sdio_driver *drv = to_sdio_driver(dev->driver);
struct sdio_func *func = dev_to_sdio_func(dev);
const struct sdio_device_id *id;
int ret;
printk("==sdio_bus_probe\n");
id = sdio_match_device(func, drv);
if (!id)
return -ENODEV;

/* Set the default block size so the driver is sure it's something
* sensible. */
sdio_claim_host(func);
ret = sdio_set_block_size(func, 0);
sdio_release_host(func);
if (ret)
return ret;

return drv->probe(func, id);////if_sdio_probe
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/mmc/core/sdio_bus.c
static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
struct sdio_driver *sdrv)
{
const struct sdio_device_id *ids;

ids = sdrv->id_table;////if_sdio_ids

if (ids) {
while (ids->class || ids->vendor || ids->device) {
if (sdio_match_one(func, ids))
return ids;
ids++;
}
}

return NULL;
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/mmc/core/sdio_bus.c
static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
const struct sdio_device_id *id)
{////sdio_init_func////
printk("==sdio_match_one\n");////ADDD
printk("\t func->class : %x\n", func->class);////ADDD//0
printk("\t id->class : %x\n", id->class);////ADDD//ff
printk("\t func->vendor : %x\n", func->vendor);////ADDD//32a
printk("\t id->vendor : %x\n", id->vendor);////ADDD//2df
printk("\t func->device : %x\n", func->device);////ADDD//1
printk("\t id->device : %x\n", id->device);////ADDD//9103
if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)
return NULL;
if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)
return NULL;
if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)
return NULL;
return id;
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/net/wireless/libertas/if_sdio.c
static const struct sdio_device_id if_sdio_ids[] = {
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_LIBERTAS) },
{ /* end: all zeroes */ },
};
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/net/wireless/libertas/if_sdio.c
static int if_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
struct if_sdio_card *card;
struct lbs_private *priv;
int ret, i;
unsigned int model;
struct if_sdio_packet *packet;

lbs_deb_enter(LBS_DEB_SDIO);

for (i = 0;i < func->card->num_info;i++) {
if (sscanf(func->card->info[i],
"802.11 SDIO ID: %x", &model) == 1)
break;
if (sscanf(func->card->info[i],
"ID: %x", &model) == 1)
break;
if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) {
model = 4;
break;
}
}

if (i == func->card->num_info) {
lbs_pr_err("unable to identify card model\n");
return -ENODEV;
}

card = kzalloc(sizeof(struct if_sdio_card), GFP_KERNEL);
if (!card)
return -ENOMEM;

card->func = func;
card->model = model;
spin_lock_init(&card->lock);
INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);

for (i = 0;i < ARRAY_SIZE(if_sdio_models);i++) { if (card->model == if_sdio_models[i].model)
break;
}

if (i == ARRAY_SIZE(if_sdio_models)) {
lbs_pr_err("unkown card model 0x%x\n", card->model);
ret = -ENODEV;
goto free;
}

card->helper = if_sdio_models[i].helper;
card->firmware = if_sdio_models[i].firmware;

if (lbs_helper_name) {
lbs_deb_sdio("overriding helper firmware: %s\n",
lbs_helper_name);
card->helper = lbs_helper_name;
}

if (lbs_fw_name) {
lbs_deb_sdio("overriding firmware: %s\n", lbs_fw_name);
card->firmware = lbs_fw_name;
}

sdio_claim_host(func);

ret = sdio_enable_func(func);
if (ret)
goto release;

ret = sdio_claim_irq(func, if_sdio_interrupt);
if (ret)
goto disable;

card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
if (ret)
goto release_int;

card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8; if (ret) goto release_int; card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16; if (ret) goto release_int; sdio_release_host(func); sdio_set_drvdata(func, card); lbs_deb_sdio("class = 0x%X, vendor = 0x%X, " "device = 0x%X, model = 0x%X, ioport = 0x%X\n", func->class, func->vendor, func->device,
model, (unsigned)card->ioport);

ret = if_sdio_prog_firmware(card);
if (ret)
goto reclaim;

priv = lbs_add_card(card, &func->dev);
if (!priv) {
ret = -ENOMEM;
goto reclaim;
}

card->priv = priv;

priv->card = card;
priv->hw_host_to_card = if_sdio_host_to_card;

priv->fw_ready = 1;

/*
* Enable interrupts now that everything is set up
*/
sdio_claim_host(func);
sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
sdio_release_host(func);
if (ret)
goto reclaim;

ret = lbs_start_card(priv);
if (ret)
goto err_activate_card;

out:
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);

return ret;

err_activate_card:
flush_scheduled_work();
free_netdev(priv->dev);
kfree(priv);
reclaim:
sdio_claim_host(func);
release_int:
sdio_release_irq(func);
disable:
sdio_disable_func(func);
release:
sdio_release_host(func);
free:
while (card->packets) {
packet = card->packets;
card->packets = card->packets->next;
kfree(packet);
}

kfree(card);

goto out;
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
include/linux/workqueue.h
INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
#define INIT_WORK(_work, _func) \
do { \
static struct lock_class_key __key; \
\
(_work)->data = (atomic_long_t) WORK_DATA_INIT(); \
lockdep_init_map(&(_work)->lockdep_map, #_work, &__key, 0);\
INIT_LIST_HEAD(&(_work)->entry); \
PREPARE_WORK((_work), (_func)); \
} while (0)

#define PREPARE_WORK(_work, _func) \
do { \
(_work)->func = (_func); \
} while (0)
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/net/wireless/libertas/if_sdio.c
static void if_sdio_host_to_card_worker(struct work_struct *work)
{
struct if_sdio_card *card;
struct if_sdio_packet *packet;
unsigned long timeout;
u8 status;
int ret;
unsigned long flags;

lbs_deb_enter(LBS_DEB_SDIO);

card = container_of(work, struct if_sdio_card, packet_worker);

while (1) {
spin_lock_irqsave(&card->lock, flags);
packet = card->packets;
if (packet)
card->packets = packet->next;
spin_unlock_irqrestore(&card->lock, flags);

if (!packet)
break;

sdio_claim_host(card->func);

timeout = jiffies + HZ;
while (1) {
status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
if (ret)
goto release;
if (status & IF_SDIO_IO_RDY)
break;
if (time_after(jiffies, timeout)) {
ret = -ETIMEDOUT;
goto release;
}
mdelay(1);
}

ret = sdio_writesb(card->func, card->ioport,
packet->buffer, packet->nb);
if (ret)
goto release;
release:
sdio_release_host(card->func);

kfree(packet);
}

lbs_deb_leave(LBS_DEB_SDIO);
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/mmc/core/sdio_io.c
void sdio_claim_host(struct sdio_func *func)
{
BUG_ON(!func);
BUG_ON(!func->card);

mmc_claim_host(func->card->host);
}
EXPORT_SYMBOL_GPL(sdio_claim_host);
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
include/linux/mmc/core.h
static inline void mmc_claim_host(struct mmc_host *host)
{
__mmc_claim_host(host, NULL);
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/mmc/core/core.c
int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
{
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
int stop;

might_sleep();

add_wait_queue(&host->wq, &wait);
spin_lock_irqsave(&host->lock, flags);
while (1) {
set_current_state(TASK_UNINTERRUPTIBLE);
stop = abort ? atomic_read(abort) : 0;
if (stop || !host->claimed)
break;
spin_unlock_irqrestore(&host->lock, flags);
schedule();
spin_lock_irqsave(&host->lock, flags);
}
set_current_state(TASK_RUNNING);
if (!stop)
host->claimed = 1;
else
wake_up(&host->wq);
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
return stop;
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
//// 클라이언트로 붙어있는 SDIO 칩과 의사소통 시작.........
drivers/mmc/core/sdio_io.c
int sdio_enable_func(struct sdio_func *func)
{
int ret;
unsigned char reg;
unsigned long timeout;

BUG_ON(!func);
BUG_ON(!func->card);

pr_debug("SDIO: Enabling device %s...\n", sdio_func_id(func));

ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, ®);
if (ret)
goto err;

reg |= 1 << func->num;

ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL);
if (ret)
goto err;

timeout = jiffies + msecs_to_jiffies(func->enable_timeout);

while (1) {
ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IORx, 0, ®);
if (ret)
goto err;
if (reg & (1 << func->num))
break;
ret = -ETIME;
if (time_after(jiffies, timeout))
goto err;
}

pr_debug("SDIO: Enabled device %s\n", sdio_func_id(func));

return 0;

err:
pr_debug("SDIO: Failed to enable device %s\n", sdio_func_id(func));
return ret;
}
EXPORT_SYMBOL_GPL(sdio_enable_func);
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/mmc/core/sdio_ops.c
int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
unsigned addr, u8 in, u8* out)
{
struct mmc_command cmd;
int err;

BUG_ON(!card);
BUG_ON(fn > 7);

memset(&cmd, 0, sizeof(struct mmc_command));

cmd.opcode = SD_IO_RW_DIRECT;
cmd.arg = write ? 0x80000000 : 0x00000000;
cmd.arg |= fn << 28; cmd.arg |= (write && out) ? 0x08000000 : 0x00000000; cmd.arg |= addr << 9; cmd.arg |= in; cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err)
return err;

if (mmc_host_is_spi(card->host)) {
/* host driver already reported errors */
} else {
if (cmd.resp[0] & R5_ERROR)
return -EIO;
if (cmd.resp[0] & R5_FUNCTION_NUMBER)
return -EINVAL;
if (cmd.resp[0] & R5_OUT_OF_RANGE)
return -ERANGE;
}

if (out) {
if (mmc_host_is_spi(card->host))
*out = (cmd.resp[0] >> 8) & 0xFF;
else
*out = cmd.resp[0] & 0xFF;
}

return 0;
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/mmc/core/sdio_irq.c
int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
{
int ret;
unsigned char reg;

BUG_ON(!func);
BUG_ON(!func->card);

pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func));

if (func->irq_handler) {
pr_debug("SDIO: IRQ for %s already in use.\n", sdio_func_id(func));
return -EBUSY;
}

ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, ®);
if (ret)
return ret;

reg |= 1 << func->num;

reg |= 1; /* Master interrupt enable */

ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
if (ret)
return ret;

func->irq_handler = handler;
ret = sdio_card_irq_get(func->card);
if (ret)
func->irq_handler = NULL;

return ret;
}
EXPORT_SYMBOL_GPL(sdio_claim_irq);
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/mmc/core/sdio_io.c
u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret)
{
int ret;
u8 val;

BUG_ON(!func);

if (err_ret)
*err_ret = 0;

ret = mmc_io_rw_direct(func->card, 0, func->num, addr, 0, &val);
if (ret) {
if (err_ret)
*err_ret = ret;
return 0xFF;
}

return val;
}
EXPORT_SYMBOL_GPL(sdio_readb);
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/mmc/core/sdio_io.c
void sdio_release_host(struct sdio_func *func)
{
BUG_ON(!func);
BUG_ON(!func->card);

mmc_release_host(func->card->host);
}
EXPORT_SYMBOL_GPL(sdio_release_host);
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/mmc/core/core.c
void mmc_release_host(struct mmc_host *host)
{
unsigned long flags;

WARN_ON(!host->claimed);

spin_lock_irqsave(&host->lock, flags);
host->claimed = 0;
spin_unlock_irqrestore(&host->lock, flags);

wake_up(&host->wq);
}
EXPORT_SYMBOL(mmc_release_host);
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
include/linux/mmc/sdio_func.h
#define sdio_set_drvdata(f,d) dev_set_drvdata(&(f)->dev, d)
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
include/linux/device.h
static inline void dev_set_drvdata(struct device *dev, void *data)
{
dev->driver_data = data;
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/net/wireless/libertas/if_sdio.c
static int if_sdio_prog_firmware(struct if_sdio_card *card)
{
int ret;
u16 scratch;

lbs_deb_enter(LBS_DEB_SDIO);

sdio_claim_host(card->func);
scratch = if_sdio_read_scratch(card, &ret);
sdio_release_host(card->func);

if (ret)
goto out;

if (scratch == IF_SDIO_FIRMWARE_OK) {
lbs_deb_sdio("firmware already loaded\n");
goto success;
}

ret = if_sdio_prog_helper(card);
if (ret)
goto out;

ret = if_sdio_prog_real(card);
if (ret)
goto out;

success:
ret = 0;

out:
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);

return ret;
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/net/wireless/libertas/if_sdio.c
static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err)
{
int ret, reg;
u16 scratch;

if (card->model == 0x04)
reg = IF_SDIO_SCRATCH_OLD;
else
reg = IF_SDIO_SCRATCH;

scratch = sdio_readb(card->func, reg, &ret);
if (!ret)
scratch |= sdio_readb(card->func, reg + 1, &ret) << 8; if (err) *err = ret; if (ret) return 0xffff; return scratch; } ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ drivers/net/wireless/libertas/if_sdio.c static int if_sdio_prog_helper(struct if_sdio_card *card) { int ret; u8 status; const struct firmware *fw; unsigned long timeout; u8 *chunk_buffer; u32 chunk_size; const u8 *firmware; size_t size; lbs_deb_enter(LBS_DEB_SDIO); ret = request_firmware(&fw, card->helper, &card->func->dev);
if (ret) {
lbs_pr_err("can't load helper firmware\n");
goto out;
}

chunk_buffer = kzalloc(64, GFP_KERNEL);
if (!chunk_buffer) {
ret = -ENOMEM;
goto release_fw;
}

sdio_claim_host(card->func);

ret = sdio_set_block_size(card->func, 32);
if (ret)
goto release;

firmware = fw->data;
size = fw->size;

while (size) {
timeout = jiffies + HZ;
while (1) {
status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
if (ret)
goto release;
if ((status & IF_SDIO_IO_RDY) &&
(status & IF_SDIO_DL_RDY))
break;
if (time_after(jiffies, timeout)) {
ret = -ETIMEDOUT;
goto release;
}
mdelay(1);
}

chunk_size = min(size, (size_t)60);

*((__le32*)chunk_buffer) = cpu_to_le32(chunk_size);
memcpy(chunk_buffer + 4, firmware, chunk_size);
/*
lbs_deb_sdio("sending %d bytes chunk\n", chunk_size);
*/
ret = sdio_writesb(card->func, card->ioport,
chunk_buffer, 64);
if (ret)
goto release;

firmware += chunk_size;
size -= chunk_size;
}

/* an empty block marks the end of the transfer */
memset(chunk_buffer, 0, 4);
ret = sdio_writesb(card->func, card->ioport, chunk_buffer, 64);
if (ret)
goto release;

lbs_deb_sdio("waiting for helper to boot...\n");

/* wait for the helper to boot by looking at the size register */
timeout = jiffies + HZ;
while (1) {
u16 req_size;

req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
if (ret)
goto release;

req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8; if (ret) goto release; if (req_size != 0) break; if (time_after(jiffies, timeout)) { ret = -ETIMEDOUT; goto release; } msleep(10); } ret = 0; release: sdio_set_block_size(card->func, 0);
sdio_release_host(card->func);
kfree(chunk_buffer);
release_fw:
release_firmware(fw);

out:
if (ret)
lbs_pr_err("failed to load helper firmware\n");

lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);

return ret;
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/net/wireless/libertas/if_sdio.c
static int if_sdio_prog_real(struct if_sdio_card *card)
{
int ret;
u8 status;
const struct firmware *fw;
unsigned long timeout;
u8 *chunk_buffer;
u32 chunk_size;
const u8 *firmware;
size_t size, req_size;

lbs_deb_enter(LBS_DEB_SDIO);

ret = request_firmware(&fw, card->firmware, &card->func->dev);
if (ret) {
lbs_pr_err("can't load firmware\n");
goto out;
}

chunk_buffer = kzalloc(512, GFP_KERNEL);
if (!chunk_buffer) {
ret = -ENOMEM;
goto release_fw;
}

sdio_claim_host(card->func);

ret = sdio_set_block_size(card->func, 32);
if (ret)
goto release;

firmware = fw->data;
size = fw->size;

while (size) {
timeout = jiffies + HZ;
while (1) {
status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
if (ret)
goto release;
if ((status & IF_SDIO_IO_RDY) &&
(status & IF_SDIO_DL_RDY))
break;
if (time_after(jiffies, timeout)) {
ret = -ETIMEDOUT;
goto release;
}
mdelay(1);
}

req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
if (ret)
goto release;

req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8; if (ret) goto release; /* lbs_deb_sdio("firmware wants %d bytes\n", (int)req_size); */ if (req_size == 0) { lbs_deb_sdio("firmware helper gave up early\n"); ret = -EIO; goto release; } if (req_size & 0x01) { lbs_deb_sdio("firmware helper signalled error\n"); ret = -EIO; goto release; } if (req_size > size)
req_size = size;

while (req_size) {
chunk_size = min(req_size, (size_t)512);

memcpy(chunk_buffer, firmware, chunk_size);
/*
lbs_deb_sdio("sending %d bytes (%d bytes) chunk\n",
chunk_size, (chunk_size + 31) / 32 * 32);
*/
ret = sdio_writesb(card->func, card->ioport,
chunk_buffer, roundup(chunk_size, 32));
if (ret)
goto release;

firmware += chunk_size;
size -= chunk_size;
req_size -= chunk_size;
}
}

ret = 0;

lbs_deb_sdio("waiting for firmware to boot...\n");

/* wait for the firmware to boot */
timeout = jiffies + HZ;
while (1) {
u16 scratch;

scratch = if_sdio_read_scratch(card, &ret);
if (ret)
goto release;

if (scratch == IF_SDIO_FIRMWARE_OK)
break;

if (time_after(jiffies, timeout)) {
ret = -ETIMEDOUT;
goto release;
}

msleep(10);
}

ret = 0;

release:
sdio_set_block_size(card->func, 0);
sdio_release_host(card->func);
kfree(chunk_buffer);
release_fw:
release_firmware(fw);

out:
if (ret)
lbs_pr_err("failed to load firmware\n");

lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);

return ret;
}
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/net/wireless/libertas/main.c
struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
{
struct net_device *dev = NULL;
struct lbs_private *priv = NULL;

lbs_deb_enter(LBS_DEB_MAIN);

/* Allocate an Ethernet device and register it */
dev = alloc_etherdev(sizeof(struct lbs_private));
if (!dev) {
lbs_pr_err("init ethX device failed\n");
goto done;
}
priv = netdev_priv(dev);
dev->ml_priv = priv;

if (lbs_init_adapter(priv)) {
lbs_pr_err("failed to initialize adapter structure.\n");
goto err_init_adapter;
}

priv->dev = dev;
priv->card = card;
priv->mesh_open = 0;
priv->infra_open = 0;

/* Setup the OS Interface to our functions */
dev->open = lbs_dev_open;
dev->hard_start_xmit = lbs_hard_start_xmit;
dev->stop = lbs_eth_stop;
dev->set_mac_address = lbs_set_mac_address;
dev->tx_timeout = lbs_tx_timeout;
dev->get_stats = lbs_get_stats;
dev->watchdog_timeo = 5 * HZ;
dev->ethtool_ops = &lbs_ethtool_ops;
#ifdef WIRELESS_EXT
dev->wireless_handlers = (struct iw_handler_def *)&lbs_handler_def;
#endif
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
dev->set_multicast_list = lbs_set_multicast_list;

SET_NETDEV_DEV(dev, dmdev);

priv->rtap_net_dev = NULL;

lbs_deb_thread("Starting main thread...\n");
init_waitqueue_head(&priv->waitq);
priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main");
if (IS_ERR(priv->main_thread)) {
lbs_deb_thread("Error creating main thread.\n");
goto err_init_adapter;
}

priv->work_thread = create_singlethread_workqueue("lbs_worker");
INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker);

sprintf(priv->mesh_ssid, "mesh");
priv->mesh_ssid_len = 4;

priv->wol_criteria = 0xffffffff;
priv->wol_gpio = 0xff;

goto done;

err_init_adapter:
lbs_free_adapter(priv);
free_netdev(dev);
priv = NULL;

done:
lbs_deb_leave_args(LBS_DEB_MAIN, "priv %p", priv);
return priv;
}
EXPORT_SYMBOL_GPL(lbs_add_card);
━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━
drivers/net/wireless/libertas/main.c
int lbs_start_card(struct lbs_private *priv)
{
struct net_device *dev = priv->dev;
int ret = -1;

lbs_deb_enter(LBS_DEB_MAIN);

/* poke the firmware */
ret = lbs_setup_firmware(priv);
if (ret)
goto done;

/* init 802.11d */
lbs_init_11d(priv);

if (register_netdev(dev)) {
lbs_pr_err("cannot register ethX device\n");
goto done;
}

lbs_update_channel(priv);

/* 5.0.16p0 is known to NOT support any mesh */
if (priv->fwrelease > 0x05001000) {
/* Enable mesh, if supported, and work out which TLV it uses.
0x100 + 291 is an unofficial value used in 5.110.20.pXX
0x100 + 37 is the official value used in 5.110.21.pXX
but we check them in that order because 20.pXX doesn't
give an error -- it just silently fails. */

/* 5.110.20.pXX firmware will fail the command if the channel
doesn't match the existing channel. But only if the TLV
is correct. If the channel is wrong, _BOTH_ versions will
give an error to 0x100+291, and allow 0x100+37 to succeed.
It's just that 5.110.20.pXX will not have done anything
useful */

priv->mesh_tlv = 0x100 + 291;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel)) {
priv->mesh_tlv = 0x100 + 37;
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel))
priv->mesh_tlv = 0;
}
if (priv->mesh_tlv) {
lbs_add_mesh(priv);

if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
lbs_pr_err("cannot register lbs_mesh attribute\n");

/* While rtap isn't related to mesh, only mesh-enabled
* firmware implements the rtap functionality via
* CMD_802_11_MONITOR_MODE.
*/
if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
lbs_pr_err("cannot register lbs_rtap attribute\n");
}
}

lbs_debugfs_init_one(priv, dev);

lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);

ret = 0;

done:
lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
return ret;
}
EXPORT_SYMBOL_GPL(lbs_start_card);
============================================================================










lib80211.c
module_init(lib80211_init);
static int __init lib80211_init(void)
{
printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION "\n");
return lib80211_register_crypto_ops(&lib80211_crypt_null);
}

lib80211.c
static struct lib80211_crypto_ops lib80211_crypt_null = {
.name = "NULL",
.init = lib80211_crypt_null_init,
.deinit = lib80211_crypt_null_deinit,
.owner = THIS_MODULE,
};

lib80211.c
int lib80211_register_crypto_ops(struct lib80211_crypto_ops *ops)
{
unsigned long flags;
struct lib80211_crypto_alg *alg;

alg = kzalloc(sizeof(*alg), GFP_KERNEL);
if (alg == NULL)
return -ENOMEM;

alg->ops = ops;

spin_lock_irqsave(&lib80211_crypto_lock, flags);
list_add(&alg->list, &lib80211_crypto_algs);
spin_unlock_irqrestore(&lib80211_crypto_lock, flags);

printk(KERN_DEBUG "lib80211_crypt: registered algorithm '%s'\n",
ops->name);

return 0;
}
EXPORT_SYMBOL(lib80211_register_crypto_ops);

댓글 없음:

댓글 쓰기