📄 mmc_sysfs.c
字号:
/* * linux/drivers/mmc/mmc_sysfs.c * * Copyright (C) 2003 Russell King, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * MMC sysfs/driver model support. */#include <linux/module.h>#include <linux/init.h>#include <linux/device.h>#include <linux/mmc/card.h>#include <linux/mmc/host.h>#include "mmc.h"#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)static void mmc_release_card(struct device *dev){ struct mmc_card *card = dev_to_mmc_card(dev); kfree(card);}/* * This currently matches any MMC driver to any MMC card - drivers * themselves make the decision whether to drive this card in their * probe method. However, we force "bad" cards to fail. */static int mmc_bus_match(struct device *dev, struct device_driver *drv){ struct mmc_card *card = dev_to_mmc_card(dev); return !mmc_card_bad(card);}static intmmc_bus_hotplug(struct device *dev, char **envp, int num_envp, char *buf, int buf_size){ struct mmc_card *card = dev_to_mmc_card(dev); char ccc[13]; int i = 0;#define add_env(fmt,val) \ ({ \ int len, ret = -ENOMEM; \ if (i < num_envp) { \ envp[i++] = buf; \ len = snprintf(buf, buf_size, fmt, val) + 1; \ buf_size -= len; \ buf += len; \ if (buf_size >= 0) \ ret = 0; \ } \ ret; \ }) for (i = 0; i < 12; i++) ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0'; ccc[12] = '\0'; i = 0; add_env("MMC_CCC=%s", ccc); add_env("MMC_MANFID=%06x", card->cid.manfid); add_env("MMC_NAME=%s", mmc_card_name(card)); add_env("MMC_OEMID=%04x", card->cid.oemid); return 0;}static int mmc_bus_suspend(struct device *dev, u32 state){ struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = dev_to_mmc_card(dev); int ret = 0; if (dev->driver && drv->suspend) ret = drv->suspend(card, state); return ret;}static int mmc_bus_resume(struct device *dev){ struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = dev_to_mmc_card(dev); int ret = 0; if (dev->driver && drv->resume) ret = drv->resume(card); return ret;}static struct bus_type mmc_bus_type = { .name = "mmc", .match = mmc_bus_match, .hotplug = mmc_bus_hotplug, .suspend = mmc_bus_suspend, .resume = mmc_bus_resume,};static int mmc_drv_probe(struct device *dev){ struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = dev_to_mmc_card(dev); return drv->probe(card);}static int mmc_drv_remove(struct device *dev){ struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = dev_to_mmc_card(dev); drv->remove(card); return 0;}/** * mmc_register_driver - register a media driver * @drv: MMC media driver */int mmc_register_driver(struct mmc_driver *drv){ drv->drv.bus = &mmc_bus_type; drv->drv.probe = mmc_drv_probe; drv->drv.remove = mmc_drv_remove; return driver_register(&drv->drv);}EXPORT_SYMBOL(mmc_register_driver);/** * mmc_unregister_driver - unregister a media driver * @drv: MMC media driver */void mmc_unregister_driver(struct mmc_driver *drv){ drv->drv.bus = &mmc_bus_type; driver_unregister(&drv->drv);}EXPORT_SYMBOL(mmc_unregister_driver);#define MMC_ATTR(name, fmt, args...) \static ssize_t mmc_dev_show_##name (struct device *dev, char *buf) \{ \ struct mmc_card *card = dev_to_mmc_card(dev); \ return sprintf(buf, fmt, args); \} \static DEVICE_ATTR(name, S_IRUGO, mmc_dev_show_##name, NULL)MMC_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1], card->raw_cid[2], card->raw_cid[3]);MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], card->raw_csd[2], card->raw_csd[3]);MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);MMC_ATTR(manfid, "0x%06x\n", card->cid.manfid);MMC_ATTR(name, "%s\n", card->cid.prod_name);MMC_ATTR(oemid, "0x%04x\n", card->cid.oemid);MMC_ATTR(serial, "0x%08x\n", card->cid.serial);static struct device_attribute *mmc_dev_attributes[] = { &dev_attr_cid, &dev_attr_csd, &dev_attr_scr, &dev_attr_date, &dev_attr_fwrev, &dev_attr_hwrev, &dev_attr_manfid, &dev_attr_name, &dev_attr_oemid, &dev_attr_serial,};/* * Internal function. Initialise a MMC card structure. */void mmc_init_card(struct mmc_card *card, struct mmc_host *host){ memset(card, 0, sizeof(struct mmc_card)); card->host = host; device_initialize(&card->dev); card->dev.parent = card->host->dev; card->dev.bus = &mmc_bus_type; card->dev.release = mmc_release_card;}/* * Internal function. Register a new MMC card with the driver model. */int mmc_register_card(struct mmc_card *card){ int ret, i; snprintf(card->dev.bus_id, sizeof(card->dev.bus_id), "%s:%04x", mmc_hostname(card->host), card->rca); ret = device_add(&card->dev); if (ret == 0) for (i = 0; i < ARRAY_SIZE(mmc_dev_attributes); i++) device_create_file(&card->dev, mmc_dev_attributes[i]); return ret;}/* * Internal function. Unregister a new MMC card with the * driver model, and (eventually) free it. */void mmc_remove_card(struct mmc_card *card){ if (mmc_card_present(card)) device_del(&card->dev); put_device(&card->dev);}static void mmc_host_classdev_release(struct class_device *dev){ struct mmc_host *host = cls_dev_to_mmc_host(dev); kfree(host);}static struct class mmc_host_class = { .name = "mmc_host", .release = mmc_host_classdev_release,};/* * Internal function. Allocate a new MMC host. */struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev){ struct mmc_host *host; host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); if (host) { memset(host, 0, sizeof(struct mmc_host) + extra); host->dev = dev; host->class_dev.dev = host->dev; host->class_dev.class = &mmc_host_class; class_device_initialize(&host->class_dev); } return host;}/* * Internal function. Register a new MMC host with the MMC class. */int mmc_add_host_sysfs(struct mmc_host *host){ static unsigned int host_num; snprintf(host->host_name, sizeof(host->host_name), "mmc%d", host_num++); strlcpy(host->class_dev.class_id, host->host_name, BUS_ID_SIZE); return class_device_add(&host->class_dev);}/* * Internal function. Unregister a MMC host with the MMC class. */void mmc_remove_host_sysfs(struct mmc_host *host){ class_device_del(&host->class_dev);}/* * Internal function. Free a MMC host. */void mmc_free_host_sysfs(struct mmc_host *host){ class_device_put(&host->class_dev);}static int __init mmc_init(void){ int ret = bus_register(&mmc_bus_type); if (ret == 0) { ret = class_register(&mmc_host_class); if (ret) bus_unregister(&mmc_bus_type); } return ret;}static void __exit mmc_exit(void){ class_unregister(&mmc_host_class); bus_unregister(&mmc_bus_type);}module_init(mmc_init);module_exit(mmc_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -