PageRenderTime 37ms CodeModel.GetById 13ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/misc/tifm_core.c

http://github.com/mirrors/linux
C | 367 lines | 295 code | 66 blank | 6 comment | 29 complexity | a2846e0b711bbe3033de9c82084f05b6 MD5 | raw file
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 *  tifm_core.c - TI FlashMedia driver
  4 *
  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, struct device_driver *drv)
 42{
 43	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
 44	struct tifm_driver *fm_drv = container_of(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(struct device *dev, struct kobj_uevent_env *env)
 59{
 60	struct tifm_dev *sock = container_of(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 int 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	return 0;
105}
106
107#ifdef CONFIG_PM
108
109static int tifm_device_suspend(struct device *dev, pm_message_t state)
110{
111	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
112	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
113					       driver);
114
115	if (dev->driver && drv->suspend)
116		return drv->suspend(sock, state);
117	return 0;
118}
119
120static int tifm_device_resume(struct device *dev)
121{
122	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
123	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
124					       driver);
125
126	if (dev->driver && drv->resume)
127		return drv->resume(sock);
128	return 0;
129}
130
131#else
132
133#define tifm_device_suspend NULL
134#define tifm_device_resume NULL
135
136#endif /* CONFIG_PM */
137
138static ssize_t type_show(struct device *dev, struct device_attribute *attr,
139			 char *buf)
140{
141	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
142	return sprintf(buf, "%x", sock->type);
143}
144static DEVICE_ATTR_RO(type);
145
146static struct attribute *tifm_dev_attrs[] = {
147	&dev_attr_type.attr,
148	NULL,
149};
150ATTRIBUTE_GROUPS(tifm_dev);
151
152static struct bus_type tifm_bus_type = {
153	.name      = "tifm",
154	.dev_groups = tifm_dev_groups,
155	.match     = tifm_bus_match,
156	.uevent    = tifm_uevent,
157	.probe     = tifm_device_probe,
158	.remove    = tifm_device_remove,
159	.suspend   = tifm_device_suspend,
160	.resume    = tifm_device_resume
161};
162
163static void tifm_free(struct device *dev)
164{
165	struct tifm_adapter *fm = container_of(dev, struct tifm_adapter, dev);
166
167	kfree(fm);
168}
169
170static struct class tifm_adapter_class = {
171	.name    = "tifm_adapter",
172	.dev_release = tifm_free
173};
174
175struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
176					struct device *dev)
177{
178	struct tifm_adapter *fm;
179
180	fm = kzalloc(sizeof(struct tifm_adapter)
181		     + sizeof(struct tifm_dev*) * num_sockets, GFP_KERNEL);
182	if (fm) {
183		fm->dev.class = &tifm_adapter_class;
184		fm->dev.parent = dev;
185		device_initialize(&fm->dev);
186		spin_lock_init(&fm->lock);
187		fm->num_sockets = num_sockets;
188	}
189	return fm;
190}
191EXPORT_SYMBOL(tifm_alloc_adapter);
192
193int tifm_add_adapter(struct tifm_adapter *fm)
194{
195	int rc;
196
197	idr_preload(GFP_KERNEL);
198	spin_lock(&tifm_adapter_lock);
199	rc = idr_alloc(&tifm_adapter_idr, fm, 0, 0, GFP_NOWAIT);
200	if (rc >= 0)
201		fm->id = rc;
202	spin_unlock(&tifm_adapter_lock);
203	idr_preload_end();
204	if (rc < 0)
205		return rc;
206
207	dev_set_name(&fm->dev, "tifm%u", fm->id);
208	rc = device_add(&fm->dev);
209	if (rc) {
210		spin_lock(&tifm_adapter_lock);
211		idr_remove(&tifm_adapter_idr, fm->id);
212		spin_unlock(&tifm_adapter_lock);
213	}
214
215	return rc;
216}
217EXPORT_SYMBOL(tifm_add_adapter);
218
219void tifm_remove_adapter(struct tifm_adapter *fm)
220{
221	unsigned int cnt;
222
223	flush_workqueue(workqueue);
224	for (cnt = 0; cnt < fm->num_sockets; ++cnt) {
225		if (fm->sockets[cnt])
226			device_unregister(&fm->sockets[cnt]->dev);
227	}
228
229	spin_lock(&tifm_adapter_lock);
230	idr_remove(&tifm_adapter_idr, fm->id);
231	spin_unlock(&tifm_adapter_lock);
232	device_del(&fm->dev);
233}
234EXPORT_SYMBOL(tifm_remove_adapter);
235
236void tifm_free_adapter(struct tifm_adapter *fm)
237{
238	put_device(&fm->dev);
239}
240EXPORT_SYMBOL(tifm_free_adapter);
241
242void tifm_free_device(struct device *dev)
243{
244	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
245	kfree(sock);
246}
247EXPORT_SYMBOL(tifm_free_device);
248
249struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id,
250				   unsigned char type)
251{
252	struct tifm_dev *sock = NULL;
253
254	if (!tifm_media_type_name(type, 0))
255		return sock;
256
257	sock = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
258	if (sock) {
259		spin_lock_init(&sock->lock);
260		sock->type = type;
261		sock->socket_id = id;
262		sock->card_event = tifm_dummy_event;
263		sock->data_event = tifm_dummy_event;
264
265		sock->dev.parent = fm->dev.parent;
266		sock->dev.bus = &tifm_bus_type;
267		sock->dev.dma_mask = fm->dev.parent->dma_mask;
268		sock->dev.release = tifm_free_device;
269
270		dev_set_name(&sock->dev, "tifm_%s%u:%u",
271			     tifm_media_type_name(type, 2), fm->id, id);
272		printk(KERN_INFO DRIVER_NAME
273		       ": %s card detected in socket %u:%u\n",
274		       tifm_media_type_name(type, 0), fm->id, id);
275	}
276	return sock;
277}
278EXPORT_SYMBOL(tifm_alloc_device);
279
280void tifm_eject(struct tifm_dev *sock)
281{
282	struct tifm_adapter *fm = dev_get_drvdata(sock->dev.parent);
283	fm->eject(fm, sock);
284}
285EXPORT_SYMBOL(tifm_eject);
286
287int tifm_has_ms_pif(struct tifm_dev *sock)
288{
289	struct tifm_adapter *fm = dev_get_drvdata(sock->dev.parent);
290	return fm->has_ms_pif(fm, sock);
291}
292EXPORT_SYMBOL(tifm_has_ms_pif);
293
294int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
295		int direction)
296{
297	return pci_map_sg(to_pci_dev(sock->dev.parent), sg, nents, direction);
298}
299EXPORT_SYMBOL(tifm_map_sg);
300
301void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
302		   int direction)
303{
304	pci_unmap_sg(to_pci_dev(sock->dev.parent), sg, nents, direction);
305}
306EXPORT_SYMBOL(tifm_unmap_sg);
307
308void tifm_queue_work(struct work_struct *work)
309{
310	queue_work(workqueue, work);
311}
312EXPORT_SYMBOL(tifm_queue_work);
313
314int tifm_register_driver(struct tifm_driver *drv)
315{
316	drv->driver.bus = &tifm_bus_type;
317
318	return driver_register(&drv->driver);
319}
320EXPORT_SYMBOL(tifm_register_driver);
321
322void tifm_unregister_driver(struct tifm_driver *drv)
323{
324	driver_unregister(&drv->driver);
325}
326EXPORT_SYMBOL(tifm_unregister_driver);
327
328static int __init tifm_init(void)
329{
330	int rc;
331
332	workqueue = create_freezable_workqueue("tifm");
333	if (!workqueue)
334		return -ENOMEM;
335
336	rc = bus_register(&tifm_bus_type);
337
338	if (rc)
339		goto err_out_wq;
340
341	rc = class_register(&tifm_adapter_class);
342	if (!rc)
343		return 0;
344
345	bus_unregister(&tifm_bus_type);
346
347err_out_wq:
348	destroy_workqueue(workqueue);
349
350	return rc;
351}
352
353static void __exit tifm_exit(void)
354{
355	class_unregister(&tifm_adapter_class);
356	bus_unregister(&tifm_bus_type);
357	destroy_workqueue(workqueue);
358}
359
360subsys_initcall(tifm_init);
361module_exit(tifm_exit);
362
363MODULE_LICENSE("GPL");
364MODULE_AUTHOR("Alex Dubov");
365MODULE_DESCRIPTION("TI FlashMedia core driver");
366MODULE_LICENSE("GPL");
367MODULE_VERSION(DRIVER_VERSION);