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