MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / scsi / pcmcia / fdomain_stub.c
blob59aca6b4234092d4a1c5dd2c0c659a2590374597
1 /*======================================================================
3 A driver for Future Domain-compatible PCMCIA SCSI cards
5 fdomain_cs.c 1.47 2001/10/13 00:08:52
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/
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.
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.
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.
32 ======================================================================*/
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>
46 #include "scsi.h"
47 #include <scsi/scsi_host.h>
48 #include "fdomain.h"
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>
56 /*====================================================================*/
58 /* Module parameters */
60 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
61 MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver");
62 MODULE_LICENSE("Dual MPL/GPL");
64 /* Bit map of interrupts to choose from */
65 static int irq_mask = 0xdeb8;
66 MODULE_PARM(irq_mask, "i");
67 static int irq_list[4] = { -1 };
68 MODULE_PARM(irq_list, "1-4i");
70 #ifdef PCMCIA_DEBUG
71 static int pc_debug = PCMCIA_DEBUG;
72 MODULE_PARM(pc_debug, "i");
73 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
74 static char *version =
75 "fdomain_cs.c 1.47 2001/10/13 00:08:52 (David Hinds)";
76 #else
77 #define DEBUG(n, args...)
78 #endif
80 /*====================================================================*/
82 typedef struct scsi_info_t {
83 dev_link_t link;
84 dev_node_t node;
85 struct Scsi_Host *host;
86 } scsi_info_t;
89 static void fdomain_release(dev_link_t *link);
90 static int fdomain_event(event_t event, int priority,
91 event_callback_args_t *args);
93 static dev_link_t *fdomain_attach(void);
94 static void fdomain_detach(dev_link_t *);
97 static dev_link_t *dev_list = NULL;
99 static dev_info_t dev_info = "fdomain_cs";
101 static dev_link_t *fdomain_attach(void)
103 scsi_info_t *info;
104 client_reg_t client_reg;
105 dev_link_t *link;
106 int i, ret;
108 DEBUG(0, "fdomain_attach()\n");
110 /* Create new SCSI device */
111 info = kmalloc(sizeof(*info), GFP_KERNEL);
112 if (!info) return NULL;
113 memset(info, 0, sizeof(*info));
114 link = &info->link; link->priv = info;
115 link->io.NumPorts1 = 0x10;
116 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
117 link->io.IOAddrLines = 10;
118 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
119 link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
120 if (irq_list[0] == -1)
121 link->irq.IRQInfo2 = irq_mask;
122 else
123 for (i = 0; i < 4; i++)
124 link->irq.IRQInfo2 |= 1 << irq_list[i];
125 link->conf.Attributes = CONF_ENABLE_IRQ;
126 link->conf.Vcc = 50;
127 link->conf.IntType = INT_MEMORY_AND_IO;
128 link->conf.Present = PRESENT_OPTION;
130 /* Register with Card Services */
131 link->next = dev_list;
132 dev_list = link;
133 client_reg.dev_info = &dev_info;
134 client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
135 client_reg.event_handler = &fdomain_event;
136 client_reg.EventMask =
137 CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
138 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
139 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
140 client_reg.Version = 0x0210;
141 client_reg.event_callback_args.client_data = link;
142 ret = pcmcia_register_client(&link->handle, &client_reg);
143 if (ret != 0) {
144 cs_error(link->handle, RegisterClient, ret);
145 fdomain_detach(link);
146 return NULL;
149 return link;
150 } /* fdomain_attach */
152 /*====================================================================*/
154 static void fdomain_detach(dev_link_t *link)
156 dev_link_t **linkp;
158 DEBUG(0, "fdomain_detach(0x%p)\n", link);
160 /* Locate device structure */
161 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
162 if (*linkp == link) break;
163 if (*linkp == NULL)
164 return;
166 if (link->state & DEV_CONFIG)
167 fdomain_release(link);
169 if (link->handle)
170 pcmcia_deregister_client(link->handle);
172 /* Unlink device structure, free bits */
173 *linkp = link->next;
174 kfree(link->priv);
176 } /* fdomain_detach */
178 /*====================================================================*/
180 #define CS_CHECK(fn, ret) \
181 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
183 static void fdomain_config(dev_link_t *link)
185 client_handle_t handle = link->handle;
186 scsi_info_t *info = link->priv;
187 tuple_t tuple;
188 cisparse_t parse;
189 int i, last_ret, last_fn;
190 u_char tuple_data[64];
191 char str[16];
192 struct Scsi_Host *host;
194 DEBUG(0, "fdomain_config(0x%p)\n", link);
196 tuple.DesiredTuple = CISTPL_CONFIG;
197 tuple.TupleData = tuple_data;
198 tuple.TupleDataMax = 64;
199 tuple.TupleOffset = 0;
200 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
201 CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
202 CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
203 link->conf.ConfigBase = parse.config.base;
205 /* Configure card */
206 link->state |= DEV_CONFIG;
208 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
209 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
210 while (1) {
211 if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
212 pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
213 goto next_entry;
214 link->conf.ConfigIndex = parse.cftable_entry.index;
215 link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
216 i = pcmcia_request_io(handle, &link->io);
217 if (i == CS_SUCCESS) break;
218 next_entry:
219 CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
222 CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
223 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
225 /* A bad hack... */
226 release_region(link->io.BasePort1, link->io.NumPorts1);
228 /* Set configuration options for the fdomain driver */
229 sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ);
230 fdomain_setup(str);
232 host = __fdomain_16x0_detect(&fdomain_driver_template);
233 if (!host) {
234 printk(KERN_INFO "fdomain_cs: no SCSI devices found\n");
235 goto cs_failed;
238 scsi_add_host(host, NULL); /* XXX handle failure */
239 scsi_scan_host(host);
241 sprintf(info->node.dev_name, "scsi%d", host->host_no);
242 link->dev = &info->node;
243 info->host = host;
245 link->state &= ~DEV_CONFIG_PENDING;
246 return;
248 cs_failed:
249 cs_error(link->handle, last_fn, last_ret);
250 fdomain_release(link);
251 return;
253 } /* fdomain_config */
255 /*====================================================================*/
257 static void fdomain_release(dev_link_t *link)
259 scsi_info_t *info = link->priv;
261 DEBUG(0, "fdomain_release(0x%p)\n", link);
263 scsi_remove_host(info->host);
264 link->dev = NULL;
266 pcmcia_release_configuration(link->handle);
267 pcmcia_release_io(link->handle, &link->io);
268 pcmcia_release_irq(link->handle, &link->irq);
270 scsi_unregister(info->host);
272 link->state &= ~DEV_CONFIG;
275 /*====================================================================*/
277 static int fdomain_event(event_t event, int priority,
278 event_callback_args_t *args)
280 dev_link_t *link = args->client_data;
282 DEBUG(1, "fdomain_event(0x%06x)\n", event);
284 switch (event) {
285 case CS_EVENT_CARD_REMOVAL:
286 link->state &= ~DEV_PRESENT;
287 if (link->state & DEV_CONFIG)
288 fdomain_release(link);
289 break;
290 case CS_EVENT_CARD_INSERTION:
291 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
292 fdomain_config(link);
293 break;
294 case CS_EVENT_PM_SUSPEND:
295 link->state |= DEV_SUSPEND;
296 /* Fall through... */
297 case CS_EVENT_RESET_PHYSICAL:
298 if (link->state & DEV_CONFIG)
299 pcmcia_release_configuration(link->handle);
300 break;
301 case CS_EVENT_PM_RESUME:
302 link->state &= ~DEV_SUSPEND;
303 /* Fall through... */
304 case CS_EVENT_CARD_RESET:
305 if (link->state & DEV_CONFIG) {
306 pcmcia_request_configuration(link->handle, &link->conf);
307 fdomain_16x0_bus_reset(NULL);
309 break;
311 return 0;
312 } /* fdomain_event */
314 static struct pcmcia_driver fdomain_cs_driver = {
315 .owner = THIS_MODULE,
316 .drv = {
317 .name = "fdomain_cs",
319 .attach = fdomain_attach,
320 .detach = fdomain_detach,
323 static int __init init_fdomain_cs(void)
325 return pcmcia_register_driver(&fdomain_cs_driver);
328 static void __exit exit_fdomain_cs(void)
330 pcmcia_unregister_driver(&fdomain_cs_driver);
332 /* XXX: this really needs to move into generic code.. */
333 while (dev_list != NULL)
334 fdomain_detach(dev_list);
337 module_init(init_fdomain_cs);
338 module_exit(exit_fdomain_cs);