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/blk.h>
45 #include <../drivers/scsi/scsi.h>
46 #include <../drivers/scsi/hosts.h>
47 #include <scsi/scsi_ioctl.h>
48 #include <../drivers/scsi/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 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
66 /* Bit map of interrupts to choose from */
67 INT_MODULE_PARM(irq_mask, 0xdeb8);
68 static int irq_list[4] = { -1 };
69 MODULE_PARM(irq_list, "1-4i");
72 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
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)";
77 #define DEBUG(n, args...)
80 /*====================================================================*/
82 typedef struct scsi_info_t {
88 extern void fdomain_setup(char *str, int *ints);
90 static void fdomain_release(u_long arg);
91 static int fdomain_event(event_t event, int priority,
92 event_callback_args_t *args);
94 static dev_link_t *fdomain_attach(void);
95 static void fdomain_detach(dev_link_t *);
97 static Scsi_Host_Template driver_template = FDOMAIN_16X0;
99 static dev_link_t *dev_list = NULL;
101 static dev_info_t dev_info = "fdomain_cs";
103 /*====================================================================*/
105 static void cs_error(client_handle_t handle, int func, int ret)
107 error_info_t err = { func, ret };
108 CardServices(ReportError, handle, &err);
111 /*====================================================================*/
113 static dev_link_t *fdomain_attach(void)
116 client_reg_t client_reg;
120 DEBUG(0, "fdomain_attach()\n");
122 /* Create new SCSI device */
123 info = kmalloc(sizeof(*info), GFP_KERNEL);
124 if (!info) return NULL;
125 memset(info, 0, sizeof(*info));
126 link = &info->link; link->priv = info;
128 link->io.NumPorts1 = 0x10;
129 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
130 link->io.IOAddrLines = 10;
131 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
132 link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
133 if (irq_list[0] == -1)
134 link->irq.IRQInfo2 = irq_mask;
136 for (i = 0; i < 4; i++)
137 link->irq.IRQInfo2 |= 1 << irq_list[i];
138 link->conf.Attributes = CONF_ENABLE_IRQ;
140 link->conf.IntType = INT_MEMORY_AND_IO;
141 link->conf.Present = PRESENT_OPTION;
143 /* Register with Card Services */
144 link->next = dev_list;
146 client_reg.dev_info = &dev_info;
147 client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
148 client_reg.event_handler = &fdomain_event;
149 client_reg.EventMask =
150 CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
151 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
152 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
153 client_reg.Version = 0x0210;
154 client_reg.event_callback_args.client_data = link;
155 ret = CardServices(RegisterClient, &link->handle, &client_reg);
157 cs_error(link->handle, RegisterClient, ret);
158 fdomain_detach(link);
163 } /* fdomain_attach */
165 /*====================================================================*/
167 static void fdomain_detach(dev_link_t *link)
171 DEBUG(0, "fdomain_detach(0x%p)\n", link);
173 /* Locate device structure */
174 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
175 if (*linkp == link) break;
179 if (link->state & DEV_CONFIG) {
180 fdomain_release((u_long)link);
181 if (link->state & DEV_STALE_CONFIG) {
182 link->state |= DEV_STALE_LINK;
188 CardServices(DeregisterClient, link->handle);
190 /* Unlink device structure, free bits */
194 } /* fdomain_detach */
196 /*====================================================================*/
198 #define CS_CHECK(fn, args...) \
199 while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
201 #define CFG_CHECK(fn, args...) \
202 if (CardServices(fn, args) != 0) goto next_entry
204 static void fdomain_config(dev_link_t *link)
206 client_handle_t handle = link->handle;
207 scsi_info_t *info = link->priv;
210 int i, last_ret, last_fn, ints[3];
211 u_char tuple_data[64];
213 dev_node_t *node, **tail;
215 struct Scsi_Host *host;
217 DEBUG(0, "fdomain_config(0x%p)\n", link);
219 tuple.DesiredTuple = CISTPL_CONFIG;
220 tuple.TupleData = tuple_data;
221 tuple.TupleDataMax = 64;
222 tuple.TupleOffset = 0;
223 CS_CHECK(GetFirstTuple, handle, &tuple);
224 CS_CHECK(GetTupleData, handle, &tuple);
225 CS_CHECK(ParseTuple, handle, &tuple, &parse);
226 link->conf.ConfigBase = parse.config.base;
229 driver_template.module = &__this_module;
230 link->state |= DEV_CONFIG;
232 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
233 CS_CHECK(GetFirstTuple, handle, &tuple);
235 CFG_CHECK(GetTupleData, handle, &tuple);
236 CFG_CHECK(ParseTuple, handle, &tuple, &parse);
237 link->conf.ConfigIndex = parse.cftable_entry.index;
238 link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
239 i = CardServices(RequestIO, handle, &link->io);
240 if (i == CS_SUCCESS) break;
242 CS_CHECK(GetNextTuple, handle, &tuple);
245 CS_CHECK(RequestIRQ, handle, &link->irq);
246 CS_CHECK(RequestConfiguration, handle, &link->conf);
249 release_region(link->io.BasePort1, link->io.NumPorts1);
251 /* Set configuration options for the fdomain driver */
253 ints[1] = link->io.BasePort1;
254 ints[2] = link->irq.AssignedIRQ;
255 sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ);
256 fdomain_setup(str, ints);
258 scsi_register_module(MODULE_SCSI_HA, &driver_template);
262 for (host = scsi_hostlist; host; host = host->next)
263 if (host->hostt == &driver_template)
264 for (dev = host->host_queue; dev; dev = dev->next) {
266 kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
267 id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
268 ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
269 node = &info->node[info->ndev];
273 node->major = SCSI_TAPE_MAJOR;
274 sprintf(node->dev_name, "st#%04lx", id);
278 node->major = SCSI_DISK0_MAJOR;
279 sprintf(node->dev_name, "sd#%04lx", id);
283 node->major = SCSI_CDROM_MAJOR;
284 sprintf(node->dev_name, "sr#%04lx", id);
287 node->major = SCSI_GENERIC_MAJOR;
288 sprintf(node->dev_name, "sg#%04lx", id);
291 *tail = node; tail = &node->next;
296 printk(KERN_INFO "fdomain_cs: no SCSI devices found\n");
298 link->state &= ~DEV_CONFIG_PENDING;
302 cs_error(link->handle, last_fn, last_ret);
303 fdomain_release((u_long)link);
306 } /* fdomain_config */
308 /*====================================================================*/
310 static void fdomain_release(u_long arg)
312 dev_link_t *link = (dev_link_t *)arg;
314 DEBUG(0, "fdomain_release(0x%p)\n", link);
316 if (GET_USE_COUNT(&__this_module) != 0) {
317 DEBUG(1, "fdomain_cs: release postponed, "
318 "device still open\n");
319 link->state |= DEV_STALE_CONFIG;
323 scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
326 CardServices(ReleaseConfiguration, link->handle);
327 CardServices(ReleaseIO, link->handle, &link->io);
328 CardServices(ReleaseIRQ, link->handle, &link->irq);
330 link->state &= ~DEV_CONFIG;
331 if (link->state & DEV_STALE_LINK)
332 fdomain_detach(link);
334 } /* fdomain_release */
336 /*====================================================================*/
338 static int fdomain_event(event_t event, int priority,
339 event_callback_args_t *args)
341 dev_link_t *link = args->client_data;
343 DEBUG(1, "fdomain_event(0x%06x)\n", event);
346 case CS_EVENT_CARD_REMOVAL:
347 link->state &= ~DEV_PRESENT;
348 if (link->state & DEV_CONFIG)
349 fdomain_release((u_long)link);
351 case CS_EVENT_CARD_INSERTION:
352 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
353 fdomain_config(link);
355 case CS_EVENT_PM_SUSPEND:
356 link->state |= DEV_SUSPEND;
357 /* Fall through... */
358 case CS_EVENT_RESET_PHYSICAL:
359 if (link->state & DEV_CONFIG)
360 CardServices(ReleaseConfiguration, link->handle);
362 case CS_EVENT_PM_RESUME:
363 link->state &= ~DEV_SUSPEND;
364 /* Fall through... */
365 case CS_EVENT_CARD_RESET:
366 if (link->state & DEV_CONFIG) {
367 CardServices(RequestConfiguration, link->handle, &link->conf);
368 fdomain_16x0_reset(NULL, 0);
373 } /* fdomain_event */
375 /*====================================================================*/
377 static int __init init_fdomain_cs(void) {
379 DEBUG(0, "%s\n", version);
380 CardServices(GetCardServicesInfo, &serv);
381 if (serv.Revision != CS_RELEASE_CODE) {
382 printk(KERN_NOTICE "fdomain_cs: Card Services release "
383 "does not match!\n");
386 register_pccard_driver(&dev_info, &fdomain_attach, &fdomain_detach);
390 static void __exit exit_fdomain_cs(void) {
391 DEBUG(0, "fdomain_cs: unloading\n");
392 unregister_pccard_driver(&dev_info);
393 while (dev_list != NULL)
394 fdomain_detach(dev_list);
397 module_init(init_fdomain_cs);
398 module_exit(exit_fdomain_cs);