brintos

brintos / linux-shallow public Read only

0
0
Text · 8.1 KiB · 12355d3 Raw
367 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  tifm_core.c - TI FlashMedia driver4 *5 *  Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>6 */7 8#include <linux/tifm.h>9#include <linux/slab.h>10#include <linux/init.h>11#include <linux/idr.h>12#include <linux/module.h>13 14#define DRIVER_NAME "tifm_core"15#define DRIVER_VERSION "0.8"16 17static struct workqueue_struct *workqueue;18static DEFINE_IDR(tifm_adapter_idr);19static DEFINE_SPINLOCK(tifm_adapter_lock);20 21static const char *tifm_media_type_name(unsigned char type, unsigned char nt)22{23	const char *card_type_name[3][3] = {24		{ "SmartMedia/xD", "MemoryStick", "MMC/SD" },25		{ "XD", "MS", "SD"},26		{ "xd", "ms", "sd"}27	};28 29	if (nt > 2 || type < 1 || type > 3)30		return NULL;31	return card_type_name[nt][type - 1];32}33 34static int tifm_dev_match(struct tifm_dev *sock, struct tifm_device_id *id)35{36	if (sock->type == id->type)37		return 1;38	return 0;39}40 41static int tifm_bus_match(struct device *dev, const struct device_driver *drv)42{43	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);44	const struct tifm_driver *fm_drv = container_of_const(drv, struct tifm_driver,45							      driver);46	struct tifm_device_id *ids = fm_drv->id_table;47 48	if (ids) {49		while (ids->type) {50			if (tifm_dev_match(sock, ids))51				return 1;52			++ids;53		}54	}55	return 0;56}57 58static int tifm_uevent(const struct device *dev, struct kobj_uevent_env *env)59{60	const struct tifm_dev *sock = container_of_const(dev, struct tifm_dev, dev);61 62	if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1)))63		return -ENOMEM;64 65	return 0;66}67 68static int tifm_device_probe(struct device *dev)69{70	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);71	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,72					       driver);73	int rc = -ENODEV;74 75	get_device(dev);76	if (dev->driver && drv->probe) {77		rc = drv->probe(sock);78		if (!rc)79			return 0;80	}81	put_device(dev);82	return rc;83}84 85static void tifm_dummy_event(struct tifm_dev *sock)86{87	return;88}89 90static void tifm_device_remove(struct device *dev)91{92	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);93	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,94					       driver);95 96	if (dev->driver && drv->remove) {97		sock->card_event = tifm_dummy_event;98		sock->data_event = tifm_dummy_event;99		drv->remove(sock);100		sock->dev.driver = NULL;101	}102 103	put_device(dev);104}105 106#ifdef CONFIG_PM107 108static int tifm_device_suspend(struct device *dev, pm_message_t state)109{110	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);111	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,112					       driver);113 114	if (dev->driver && drv->suspend)115		return drv->suspend(sock, state);116	return 0;117}118 119static int tifm_device_resume(struct device *dev)120{121	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);122	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,123					       driver);124 125	if (dev->driver && drv->resume)126		return drv->resume(sock);127	return 0;128}129 130#else131 132#define tifm_device_suspend NULL133#define tifm_device_resume NULL134 135#endif /* CONFIG_PM */136 137static ssize_t type_show(struct device *dev, struct device_attribute *attr,138			 char *buf)139{140	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);141	return sprintf(buf, "%x", sock->type);142}143static DEVICE_ATTR_RO(type);144 145static struct attribute *tifm_dev_attrs[] = {146	&dev_attr_type.attr,147	NULL,148};149ATTRIBUTE_GROUPS(tifm_dev);150 151static const struct bus_type tifm_bus_type = {152	.name      = "tifm",153	.dev_groups = tifm_dev_groups,154	.match     = tifm_bus_match,155	.uevent    = tifm_uevent,156	.probe     = tifm_device_probe,157	.remove    = tifm_device_remove,158	.suspend   = tifm_device_suspend,159	.resume    = tifm_device_resume160};161 162static void tifm_free(struct device *dev)163{164	struct tifm_adapter *fm = container_of(dev, struct tifm_adapter, dev);165 166	kfree(fm);167}168 169static const struct class tifm_adapter_class = {170	.name    = "tifm_adapter",171	.dev_release = tifm_free172};173 174struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,175					struct device *dev)176{177	struct tifm_adapter *fm;178 179	fm = kzalloc(struct_size(fm, sockets, num_sockets), GFP_KERNEL);180	if (fm) {181		fm->dev.class = &tifm_adapter_class;182		fm->dev.parent = dev;183		device_initialize(&fm->dev);184		spin_lock_init(&fm->lock);185		fm->num_sockets = num_sockets;186	}187	return fm;188}189EXPORT_SYMBOL(tifm_alloc_adapter);190 191int tifm_add_adapter(struct tifm_adapter *fm)192{193	int rc;194 195	idr_preload(GFP_KERNEL);196	spin_lock(&tifm_adapter_lock);197	rc = idr_alloc(&tifm_adapter_idr, fm, 0, 0, GFP_NOWAIT);198	if (rc >= 0)199		fm->id = rc;200	spin_unlock(&tifm_adapter_lock);201	idr_preload_end();202	if (rc < 0)203		return rc;204 205	dev_set_name(&fm->dev, "tifm%u", fm->id);206	rc = device_add(&fm->dev);207	if (rc) {208		spin_lock(&tifm_adapter_lock);209		idr_remove(&tifm_adapter_idr, fm->id);210		spin_unlock(&tifm_adapter_lock);211	}212 213	return rc;214}215EXPORT_SYMBOL(tifm_add_adapter);216 217void tifm_remove_adapter(struct tifm_adapter *fm)218{219	unsigned int cnt;220 221	flush_workqueue(workqueue);222	for (cnt = 0; cnt < fm->num_sockets; ++cnt) {223		if (fm->sockets[cnt])224			device_unregister(&fm->sockets[cnt]->dev);225	}226 227	spin_lock(&tifm_adapter_lock);228	idr_remove(&tifm_adapter_idr, fm->id);229	spin_unlock(&tifm_adapter_lock);230	device_del(&fm->dev);231}232EXPORT_SYMBOL(tifm_remove_adapter);233 234void tifm_free_adapter(struct tifm_adapter *fm)235{236	put_device(&fm->dev);237}238EXPORT_SYMBOL(tifm_free_adapter);239 240void tifm_free_device(struct device *dev)241{242	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);243	kfree(sock);244}245EXPORT_SYMBOL(tifm_free_device);246 247struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id,248				   unsigned char type)249{250	struct tifm_dev *sock = NULL;251 252	if (!tifm_media_type_name(type, 0))253		return sock;254 255	sock = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);256	if (sock) {257		spin_lock_init(&sock->lock);258		sock->type = type;259		sock->socket_id = id;260		sock->card_event = tifm_dummy_event;261		sock->data_event = tifm_dummy_event;262 263		sock->dev.parent = fm->dev.parent;264		sock->dev.bus = &tifm_bus_type;265		sock->dev.dma_mask = fm->dev.parent->dma_mask;266		sock->dev.release = tifm_free_device;267 268		dev_set_name(&sock->dev, "tifm_%s%u:%u",269			     tifm_media_type_name(type, 2), fm->id, id);270		printk(KERN_INFO DRIVER_NAME271		       ": %s card detected in socket %u:%u\n",272		       tifm_media_type_name(type, 0), fm->id, id);273	}274	return sock;275}276EXPORT_SYMBOL(tifm_alloc_device);277 278void tifm_eject(struct tifm_dev *sock)279{280	struct tifm_adapter *fm = dev_get_drvdata(sock->dev.parent);281	fm->eject(fm, sock);282}283EXPORT_SYMBOL(tifm_eject);284 285int tifm_has_ms_pif(struct tifm_dev *sock)286{287	struct tifm_adapter *fm = dev_get_drvdata(sock->dev.parent);288	return fm->has_ms_pif(fm, sock);289}290EXPORT_SYMBOL(tifm_has_ms_pif);291 292int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,293		int direction)294{295	return dma_map_sg(&to_pci_dev(sock->dev.parent)->dev, sg, nents,296			  direction);297}298EXPORT_SYMBOL(tifm_map_sg);299 300void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,301		   int direction)302{303	dma_unmap_sg(&to_pci_dev(sock->dev.parent)->dev, sg, nents, direction);304}305EXPORT_SYMBOL(tifm_unmap_sg);306 307void tifm_queue_work(struct work_struct *work)308{309	queue_work(workqueue, work);310}311EXPORT_SYMBOL(tifm_queue_work);312 313int tifm_register_driver(struct tifm_driver *drv)314{315	drv->driver.bus = &tifm_bus_type;316 317	return driver_register(&drv->driver);318}319EXPORT_SYMBOL(tifm_register_driver);320 321void tifm_unregister_driver(struct tifm_driver *drv)322{323	driver_unregister(&drv->driver);324}325EXPORT_SYMBOL(tifm_unregister_driver);326 327static int __init tifm_init(void)328{329	int rc;330 331	workqueue = create_freezable_workqueue("tifm");332	if (!workqueue)333		return -ENOMEM;334 335	rc = bus_register(&tifm_bus_type);336 337	if (rc)338		goto err_out_wq;339 340	rc = class_register(&tifm_adapter_class);341	if (!rc)342		return 0;343 344	bus_unregister(&tifm_bus_type);345 346err_out_wq:347	destroy_workqueue(workqueue);348 349	return rc;350}351 352static void __exit tifm_exit(void)353{354	class_unregister(&tifm_adapter_class);355	bus_unregister(&tifm_bus_type);356	destroy_workqueue(workqueue);357}358 359subsys_initcall(tifm_init);360module_exit(tifm_exit);361 362MODULE_LICENSE("GPL");363MODULE_AUTHOR("Alex Dubov");364MODULE_DESCRIPTION("TI FlashMedia core driver");365MODULE_LICENSE("GPL");366MODULE_VERSION(DRIVER_VERSION);367