Root/drivers/misc/tifm_core.c

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

Archive Download this file



interactive