diff options
Diffstat (limited to 'drivers/mmc/core/host.c')
-rw-r--r-- | drivers/mmc/core/host.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c new file mode 100644 index 000000000000..1433d95c40bb --- /dev/null +++ b/drivers/mmc/core/host.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * linux/drivers/mmc/core/host.c | ||
3 | * | ||
4 | * Copyright (C) 2003 Russell King, All Rights Reserved. | ||
5 | * Copyright (C) 2007 Pierre Ossman | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * MMC host class device management | ||
12 | */ | ||
13 | |||
14 | #include <linux/device.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/idr.h> | ||
17 | #include <linux/pagemap.h> | ||
18 | |||
19 | #include <linux/mmc/host.h> | ||
20 | |||
21 | #include "core.h" | ||
22 | #include "host.h" | ||
23 | |||
24 | #define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev) | ||
25 | |||
26 | static void mmc_host_classdev_release(struct device *dev) | ||
27 | { | ||
28 | struct mmc_host *host = cls_dev_to_mmc_host(dev); | ||
29 | kfree(host); | ||
30 | } | ||
31 | |||
32 | static struct class mmc_host_class = { | ||
33 | .name = "mmc_host", | ||
34 | .dev_release = mmc_host_classdev_release, | ||
35 | }; | ||
36 | |||
37 | int mmc_register_host_class(void) | ||
38 | { | ||
39 | return class_register(&mmc_host_class); | ||
40 | } | ||
41 | |||
42 | void mmc_unregister_host_class(void) | ||
43 | { | ||
44 | class_unregister(&mmc_host_class); | ||
45 | } | ||
46 | |||
47 | static DEFINE_IDR(mmc_host_idr); | ||
48 | static DEFINE_SPINLOCK(mmc_host_lock); | ||
49 | |||
50 | /** | ||
51 | * mmc_alloc_host - initialise the per-host structure. | ||
52 | * @extra: sizeof private data structure | ||
53 | * @dev: pointer to host device model structure | ||
54 | * | ||
55 | * Initialise the per-host structure. | ||
56 | */ | ||
57 | struct mmc_host *mmc_alloc_host(int extra, struct device *dev) | ||
58 | { | ||
59 | struct mmc_host *host; | ||
60 | |||
61 | host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); | ||
62 | if (!host) | ||
63 | return NULL; | ||
64 | |||
65 | memset(host, 0, sizeof(struct mmc_host) + extra); | ||
66 | |||
67 | host->parent = dev; | ||
68 | host->class_dev.parent = dev; | ||
69 | host->class_dev.class = &mmc_host_class; | ||
70 | device_initialize(&host->class_dev); | ||
71 | |||
72 | spin_lock_init(&host->lock); | ||
73 | init_waitqueue_head(&host->wq); | ||
74 | INIT_DELAYED_WORK(&host->detect, mmc_rescan); | ||
75 | |||
76 | /* | ||
77 | * By default, hosts do not support SGIO or large requests. | ||
78 | * They have to set these according to their abilities. | ||
79 | */ | ||
80 | host->max_hw_segs = 1; | ||
81 | host->max_phys_segs = 1; | ||
82 | host->max_seg_size = PAGE_CACHE_SIZE; | ||
83 | |||
84 | host->max_req_size = PAGE_CACHE_SIZE; | ||
85 | host->max_blk_size = 512; | ||
86 | host->max_blk_count = PAGE_CACHE_SIZE / 512; | ||
87 | |||
88 | return host; | ||
89 | } | ||
90 | |||
91 | EXPORT_SYMBOL(mmc_alloc_host); | ||
92 | |||
93 | /** | ||
94 | * mmc_add_host - initialise host hardware | ||
95 | * @host: mmc host | ||
96 | */ | ||
97 | int mmc_add_host(struct mmc_host *host) | ||
98 | { | ||
99 | int err; | ||
100 | |||
101 | if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL)) | ||
102 | return -ENOMEM; | ||
103 | |||
104 | spin_lock(&mmc_host_lock); | ||
105 | err = idr_get_new(&mmc_host_idr, host, &host->index); | ||
106 | spin_unlock(&mmc_host_lock); | ||
107 | if (err) | ||
108 | return err; | ||
109 | |||
110 | snprintf(host->class_dev.bus_id, BUS_ID_SIZE, | ||
111 | "mmc%d", host->index); | ||
112 | |||
113 | err = device_add(&host->class_dev); | ||
114 | if (err) | ||
115 | return err; | ||
116 | |||
117 | mmc_start_host(host); | ||
118 | |||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | EXPORT_SYMBOL(mmc_add_host); | ||
123 | |||
124 | /** | ||
125 | * mmc_remove_host - remove host hardware | ||
126 | * @host: mmc host | ||
127 | * | ||
128 | * Unregister and remove all cards associated with this host, | ||
129 | * and power down the MMC bus. | ||
130 | */ | ||
131 | void mmc_remove_host(struct mmc_host *host) | ||
132 | { | ||
133 | mmc_stop_host(host); | ||
134 | |||
135 | device_del(&host->class_dev); | ||
136 | |||
137 | spin_lock(&mmc_host_lock); | ||
138 | idr_remove(&mmc_host_idr, host->index); | ||
139 | spin_unlock(&mmc_host_lock); | ||
140 | } | ||
141 | |||
142 | EXPORT_SYMBOL(mmc_remove_host); | ||
143 | |||
144 | /** | ||
145 | * mmc_free_host - free the host structure | ||
146 | * @host: mmc host | ||
147 | * | ||
148 | * Free the host once all references to it have been dropped. | ||
149 | */ | ||
150 | void mmc_free_host(struct mmc_host *host) | ||
151 | { | ||
152 | put_device(&host->class_dev); | ||
153 | } | ||
154 | |||
155 | EXPORT_SYMBOL(mmc_free_host); | ||
156 | |||