diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/scsi/pcmcia/fdomain_stub.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/scsi/pcmcia/fdomain_stub.c')
-rw-r--r-- | drivers/scsi/pcmcia/fdomain_stub.c | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c new file mode 100644 index 000000000000..3df7bc72e354 --- /dev/null +++ b/drivers/scsi/pcmcia/fdomain_stub.c | |||
@@ -0,0 +1,323 @@ | |||
1 | /*====================================================================== | ||
2 | |||
3 | A driver for Future Domain-compatible PCMCIA SCSI cards | ||
4 | |||
5 | fdomain_cs.c 1.47 2001/10/13 00:08:52 | ||
6 | |||
7 | The contents of this file are subject to the Mozilla Public | ||
8 | License Version 1.1 (the "License"); you may not use this file | ||
9 | except in compliance with the License. You may obtain a copy of | ||
10 | the License at http://www.mozilla.org/MPL/ | ||
11 | |||
12 | Software distributed under the License is distributed on an "AS | ||
13 | IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | ||
14 | implied. See the License for the specific language governing | ||
15 | rights and limitations under the License. | ||
16 | |||
17 | The initial developer of the original code is David A. Hinds | ||
18 | <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
19 | are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
20 | |||
21 | Alternatively, the contents of this file may be used under the | ||
22 | terms of the GNU General Public License version 2 (the "GPL"), in | ||
23 | which case the provisions of the GPL are applicable instead of the | ||
24 | above. If you wish to allow the use of your version of this file | ||
25 | only under the terms of the GPL and not to allow others to use | ||
26 | your version of this file under the MPL, indicate your decision | ||
27 | by deleting the provisions above and replace them with the notice | ||
28 | and other provisions required by the GPL. If you do not delete | ||
29 | the provisions above, a recipient may use your version of this | ||
30 | file under either the MPL or the GPL. | ||
31 | |||
32 | ======================================================================*/ | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/sched.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/string.h> | ||
40 | #include <linux/ioport.h> | ||
41 | #include <scsi/scsi.h> | ||
42 | #include <linux/major.h> | ||
43 | #include <linux/blkdev.h> | ||
44 | #include <scsi/scsi_ioctl.h> | ||
45 | |||
46 | #include "scsi.h" | ||
47 | #include <scsi/scsi_host.h> | ||
48 | #include "fdomain.h" | ||
49 | |||
50 | #include <pcmcia/version.h> | ||
51 | #include <pcmcia/cs_types.h> | ||
52 | #include <pcmcia/cs.h> | ||
53 | #include <pcmcia/cistpl.h> | ||
54 | #include <pcmcia/ds.h> | ||
55 | |||
56 | /*====================================================================*/ | ||
57 | |||
58 | /* Module parameters */ | ||
59 | |||
60 | MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); | ||
61 | MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver"); | ||
62 | MODULE_LICENSE("Dual MPL/GPL"); | ||
63 | |||
64 | #ifdef PCMCIA_DEBUG | ||
65 | static int pc_debug = PCMCIA_DEBUG; | ||
66 | module_param(pc_debug, int, 0); | ||
67 | #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) | ||
68 | static char *version = | ||
69 | "fdomain_cs.c 1.47 2001/10/13 00:08:52 (David Hinds)"; | ||
70 | #else | ||
71 | #define DEBUG(n, args...) | ||
72 | #endif | ||
73 | |||
74 | /*====================================================================*/ | ||
75 | |||
76 | typedef struct scsi_info_t { | ||
77 | dev_link_t link; | ||
78 | dev_node_t node; | ||
79 | struct Scsi_Host *host; | ||
80 | } scsi_info_t; | ||
81 | |||
82 | |||
83 | static void fdomain_release(dev_link_t *link); | ||
84 | static int fdomain_event(event_t event, int priority, | ||
85 | event_callback_args_t *args); | ||
86 | |||
87 | static dev_link_t *fdomain_attach(void); | ||
88 | static void fdomain_detach(dev_link_t *); | ||
89 | |||
90 | |||
91 | static dev_link_t *dev_list = NULL; | ||
92 | |||
93 | static dev_info_t dev_info = "fdomain_cs"; | ||
94 | |||
95 | static dev_link_t *fdomain_attach(void) | ||
96 | { | ||
97 | scsi_info_t *info; | ||
98 | client_reg_t client_reg; | ||
99 | dev_link_t *link; | ||
100 | int ret; | ||
101 | |||
102 | DEBUG(0, "fdomain_attach()\n"); | ||
103 | |||
104 | /* Create new SCSI device */ | ||
105 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
106 | if (!info) return NULL; | ||
107 | memset(info, 0, sizeof(*info)); | ||
108 | link = &info->link; link->priv = info; | ||
109 | link->io.NumPorts1 = 0x10; | ||
110 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | ||
111 | link->io.IOAddrLines = 10; | ||
112 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; | ||
113 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
114 | link->conf.Attributes = CONF_ENABLE_IRQ; | ||
115 | link->conf.Vcc = 50; | ||
116 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
117 | link->conf.Present = PRESENT_OPTION; | ||
118 | |||
119 | /* Register with Card Services */ | ||
120 | link->next = dev_list; | ||
121 | dev_list = link; | ||
122 | client_reg.dev_info = &dev_info; | ||
123 | client_reg.event_handler = &fdomain_event; | ||
124 | client_reg.EventMask = | ||
125 | CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | | ||
126 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
127 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
128 | client_reg.Version = 0x0210; | ||
129 | client_reg.event_callback_args.client_data = link; | ||
130 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
131 | if (ret != 0) { | ||
132 | cs_error(link->handle, RegisterClient, ret); | ||
133 | fdomain_detach(link); | ||
134 | return NULL; | ||
135 | } | ||
136 | |||
137 | return link; | ||
138 | } /* fdomain_attach */ | ||
139 | |||
140 | /*====================================================================*/ | ||
141 | |||
142 | static void fdomain_detach(dev_link_t *link) | ||
143 | { | ||
144 | dev_link_t **linkp; | ||
145 | |||
146 | DEBUG(0, "fdomain_detach(0x%p)\n", link); | ||
147 | |||
148 | /* Locate device structure */ | ||
149 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
150 | if (*linkp == link) break; | ||
151 | if (*linkp == NULL) | ||
152 | return; | ||
153 | |||
154 | if (link->state & DEV_CONFIG) | ||
155 | fdomain_release(link); | ||
156 | |||
157 | if (link->handle) | ||
158 | pcmcia_deregister_client(link->handle); | ||
159 | |||
160 | /* Unlink device structure, free bits */ | ||
161 | *linkp = link->next; | ||
162 | kfree(link->priv); | ||
163 | |||
164 | } /* fdomain_detach */ | ||
165 | |||
166 | /*====================================================================*/ | ||
167 | |||
168 | #define CS_CHECK(fn, ret) \ | ||
169 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | ||
170 | |||
171 | static void fdomain_config(dev_link_t *link) | ||
172 | { | ||
173 | client_handle_t handle = link->handle; | ||
174 | scsi_info_t *info = link->priv; | ||
175 | tuple_t tuple; | ||
176 | cisparse_t parse; | ||
177 | int i, last_ret, last_fn; | ||
178 | u_char tuple_data[64]; | ||
179 | char str[16]; | ||
180 | struct Scsi_Host *host; | ||
181 | |||
182 | DEBUG(0, "fdomain_config(0x%p)\n", link); | ||
183 | |||
184 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
185 | tuple.TupleData = tuple_data; | ||
186 | tuple.TupleDataMax = 64; | ||
187 | tuple.TupleOffset = 0; | ||
188 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
189 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | ||
190 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); | ||
191 | link->conf.ConfigBase = parse.config.base; | ||
192 | |||
193 | /* Configure card */ | ||
194 | link->state |= DEV_CONFIG; | ||
195 | |||
196 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
197 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
198 | while (1) { | ||
199 | if (pcmcia_get_tuple_data(handle, &tuple) != 0 || | ||
200 | pcmcia_parse_tuple(handle, &tuple, &parse) != 0) | ||
201 | goto next_entry; | ||
202 | link->conf.ConfigIndex = parse.cftable_entry.index; | ||
203 | link->io.BasePort1 = parse.cftable_entry.io.win[0].base; | ||
204 | i = pcmcia_request_io(handle, &link->io); | ||
205 | if (i == CS_SUCCESS) break; | ||
206 | next_entry: | ||
207 | CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); | ||
208 | } | ||
209 | |||
210 | CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); | ||
211 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); | ||
212 | |||
213 | /* A bad hack... */ | ||
214 | release_region(link->io.BasePort1, link->io.NumPorts1); | ||
215 | |||
216 | /* Set configuration options for the fdomain driver */ | ||
217 | sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ); | ||
218 | fdomain_setup(str); | ||
219 | |||
220 | host = __fdomain_16x0_detect(&fdomain_driver_template); | ||
221 | if (!host) { | ||
222 | printk(KERN_INFO "fdomain_cs: no SCSI devices found\n"); | ||
223 | goto cs_failed; | ||
224 | } | ||
225 | |||
226 | scsi_add_host(host, NULL); /* XXX handle failure */ | ||
227 | scsi_scan_host(host); | ||
228 | |||
229 | sprintf(info->node.dev_name, "scsi%d", host->host_no); | ||
230 | link->dev = &info->node; | ||
231 | info->host = host; | ||
232 | |||
233 | link->state &= ~DEV_CONFIG_PENDING; | ||
234 | return; | ||
235 | |||
236 | cs_failed: | ||
237 | cs_error(link->handle, last_fn, last_ret); | ||
238 | fdomain_release(link); | ||
239 | return; | ||
240 | |||
241 | } /* fdomain_config */ | ||
242 | |||
243 | /*====================================================================*/ | ||
244 | |||
245 | static void fdomain_release(dev_link_t *link) | ||
246 | { | ||
247 | scsi_info_t *info = link->priv; | ||
248 | |||
249 | DEBUG(0, "fdomain_release(0x%p)\n", link); | ||
250 | |||
251 | scsi_remove_host(info->host); | ||
252 | link->dev = NULL; | ||
253 | |||
254 | pcmcia_release_configuration(link->handle); | ||
255 | pcmcia_release_io(link->handle, &link->io); | ||
256 | pcmcia_release_irq(link->handle, &link->irq); | ||
257 | |||
258 | scsi_unregister(info->host); | ||
259 | |||
260 | link->state &= ~DEV_CONFIG; | ||
261 | } | ||
262 | |||
263 | /*====================================================================*/ | ||
264 | |||
265 | static int fdomain_event(event_t event, int priority, | ||
266 | event_callback_args_t *args) | ||
267 | { | ||
268 | dev_link_t *link = args->client_data; | ||
269 | |||
270 | DEBUG(1, "fdomain_event(0x%06x)\n", event); | ||
271 | |||
272 | switch (event) { | ||
273 | case CS_EVENT_CARD_REMOVAL: | ||
274 | link->state &= ~DEV_PRESENT; | ||
275 | if (link->state & DEV_CONFIG) | ||
276 | fdomain_release(link); | ||
277 | break; | ||
278 | case CS_EVENT_CARD_INSERTION: | ||
279 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
280 | fdomain_config(link); | ||
281 | break; | ||
282 | case CS_EVENT_PM_SUSPEND: | ||
283 | link->state |= DEV_SUSPEND; | ||
284 | /* Fall through... */ | ||
285 | case CS_EVENT_RESET_PHYSICAL: | ||
286 | if (link->state & DEV_CONFIG) | ||
287 | pcmcia_release_configuration(link->handle); | ||
288 | break; | ||
289 | case CS_EVENT_PM_RESUME: | ||
290 | link->state &= ~DEV_SUSPEND; | ||
291 | /* Fall through... */ | ||
292 | case CS_EVENT_CARD_RESET: | ||
293 | if (link->state & DEV_CONFIG) { | ||
294 | pcmcia_request_configuration(link->handle, &link->conf); | ||
295 | fdomain_16x0_bus_reset(NULL); | ||
296 | } | ||
297 | break; | ||
298 | } | ||
299 | return 0; | ||
300 | } /* fdomain_event */ | ||
301 | |||
302 | static struct pcmcia_driver fdomain_cs_driver = { | ||
303 | .owner = THIS_MODULE, | ||
304 | .drv = { | ||
305 | .name = "fdomain_cs", | ||
306 | }, | ||
307 | .attach = fdomain_attach, | ||
308 | .detach = fdomain_detach, | ||
309 | }; | ||
310 | |||
311 | static int __init init_fdomain_cs(void) | ||
312 | { | ||
313 | return pcmcia_register_driver(&fdomain_cs_driver); | ||
314 | } | ||
315 | |||
316 | static void __exit exit_fdomain_cs(void) | ||
317 | { | ||
318 | pcmcia_unregister_driver(&fdomain_cs_driver); | ||
319 | BUG_ON(dev_list != NULL); | ||
320 | } | ||
321 | |||
322 | module_init(init_fdomain_cs); | ||
323 | module_exit(exit_fdomain_cs); | ||