]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/scsi/pcmcia/fdomain_stub.c
d2281eba790d2b2af9e6f39ef07c2fac4aec661a
[mv-sheeva.git] / drivers / scsi / pcmcia / fdomain_stub.c
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.Version = 0x0210;
124     client_reg.event_callback_args.client_data = link;
125     ret = pcmcia_register_client(&link->handle, &client_reg);
126     if (ret != 0) {
127         cs_error(link->handle, RegisterClient, ret);
128         fdomain_detach(link);
129         return NULL;
130     }
131     
132     return link;
133 } /* fdomain_attach */
134
135 /*====================================================================*/
136
137 static void fdomain_detach(dev_link_t *link)
138 {
139     dev_link_t **linkp;
140
141     DEBUG(0, "fdomain_detach(0x%p)\n", link);
142     
143     /* Locate device structure */
144     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
145         if (*linkp == link) break;
146     if (*linkp == NULL)
147         return;
148
149     if (link->state & DEV_CONFIG)
150         fdomain_release(link);
151
152     if (link->handle)
153         pcmcia_deregister_client(link->handle);
154     
155     /* Unlink device structure, free bits */
156     *linkp = link->next;
157     kfree(link->priv);
158     
159 } /* fdomain_detach */
160
161 /*====================================================================*/
162
163 #define CS_CHECK(fn, ret) \
164 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
165
166 static void fdomain_config(dev_link_t *link)
167 {
168     client_handle_t handle = link->handle;
169     scsi_info_t *info = link->priv;
170     tuple_t tuple;
171     cisparse_t parse;
172     int i, last_ret, last_fn;
173     u_char tuple_data[64];
174     char str[16];
175     struct Scsi_Host *host;
176
177     DEBUG(0, "fdomain_config(0x%p)\n", link);
178
179     tuple.DesiredTuple = CISTPL_CONFIG;
180     tuple.TupleData = tuple_data;
181     tuple.TupleDataMax = 64;
182     tuple.TupleOffset = 0;
183     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
184     CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
185     CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
186     link->conf.ConfigBase = parse.config.base;
187
188     /* Configure card */
189     link->state |= DEV_CONFIG;
190     
191     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
192     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
193     while (1) {
194         if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
195                 pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
196             goto next_entry;
197         link->conf.ConfigIndex = parse.cftable_entry.index;
198         link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
199         i = pcmcia_request_io(handle, &link->io);
200         if (i == CS_SUCCESS) break;
201     next_entry:
202         CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
203     }
204
205     CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
206     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
207     
208     /* A bad hack... */
209     release_region(link->io.BasePort1, link->io.NumPorts1);
210
211     /* Set configuration options for the fdomain driver */
212     sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ);
213     fdomain_setup(str);
214     
215     host = __fdomain_16x0_detect(&fdomain_driver_template);
216     if (!host) {
217         printk(KERN_INFO "fdomain_cs: no SCSI devices found\n");
218         goto cs_failed;
219     }
220  
221     scsi_add_host(host, NULL); /* XXX handle failure */
222     scsi_scan_host(host);
223
224     sprintf(info->node.dev_name, "scsi%d", host->host_no);
225     link->dev = &info->node;
226     info->host = host;
227     
228     link->state &= ~DEV_CONFIG_PENDING;
229     return;
230     
231 cs_failed:
232     cs_error(link->handle, last_fn, last_ret);
233     fdomain_release(link);
234     return;
235     
236 } /* fdomain_config */
237
238 /*====================================================================*/
239
240 static void fdomain_release(dev_link_t *link)
241 {
242     scsi_info_t *info = link->priv;
243
244     DEBUG(0, "fdomain_release(0x%p)\n", link);
245
246     scsi_remove_host(info->host);
247     link->dev = NULL;
248     
249     pcmcia_release_configuration(link->handle);
250     pcmcia_release_io(link->handle, &link->io);
251     pcmcia_release_irq(link->handle, &link->irq);
252
253     scsi_unregister(info->host);
254
255     link->state &= ~DEV_CONFIG;
256 }
257
258 /*====================================================================*/
259
260 static int fdomain_event(event_t event, int priority,
261                         event_callback_args_t *args)
262 {
263     dev_link_t *link = args->client_data;
264
265     DEBUG(1, "fdomain_event(0x%06x)\n", event);
266     
267     switch (event) {
268     case CS_EVENT_CARD_REMOVAL:
269         link->state &= ~DEV_PRESENT;
270         if (link->state & DEV_CONFIG)
271             fdomain_release(link);
272         break;
273     case CS_EVENT_CARD_INSERTION:
274         link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
275         fdomain_config(link);
276         break;
277     case CS_EVENT_PM_SUSPEND:
278         link->state |= DEV_SUSPEND;
279         /* Fall through... */
280     case CS_EVENT_RESET_PHYSICAL:
281         if (link->state & DEV_CONFIG)
282             pcmcia_release_configuration(link->handle);
283         break;
284     case CS_EVENT_PM_RESUME:
285         link->state &= ~DEV_SUSPEND;
286         /* Fall through... */
287     case CS_EVENT_CARD_RESET:
288         if (link->state & DEV_CONFIG) {
289             pcmcia_request_configuration(link->handle, &link->conf);
290             fdomain_16x0_bus_reset(NULL);
291         }
292         break;
293     }
294     return 0;
295 } /* fdomain_event */
296
297
298 static struct pcmcia_device_id fdomain_ids[] = {
299         PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88, 0x859cad20),
300         PCMCIA_DEVICE_PROD_ID1("SCSI PCMCIA Adapter Card", 0x8dacb57e),
301         PCMCIA_DEVICE_PROD_ID12(" SIMPLE TECHNOLOGY Corporation", "SCSI PCMCIA Credit Card Controller", 0x182bdafe, 0xc80d106f),
302         PCMCIA_DEVICE_NULL,
303 };
304 MODULE_DEVICE_TABLE(pcmcia, fdomain_ids);
305
306 static struct pcmcia_driver fdomain_cs_driver = {
307         .owner          = THIS_MODULE,
308         .drv            = {
309                 .name   = "fdomain_cs",
310         },
311         .attach         = fdomain_attach,
312         .event          = fdomain_event,
313         .detach         = fdomain_detach,
314         .id_table       = fdomain_ids,
315 };
316
317 static int __init init_fdomain_cs(void)
318 {
319         return pcmcia_register_driver(&fdomain_cs_driver);
320 }
321
322 static void __exit exit_fdomain_cs(void)
323 {
324         pcmcia_unregister_driver(&fdomain_cs_driver);
325         BUG_ON(dev_list != NULL);
326 }
327
328 module_init(init_fdomain_cs);
329 module_exit(exit_fdomain_cs);