[PATCH] pcmcia: remove dev_list from drivers
[cascardo/linux.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/cs_types.h>
51 #include <pcmcia/cs.h>
52 #include <pcmcia/cistpl.h>
53 #include <pcmcia/ds.h>
54
55 /*====================================================================*/
56
57 /* Module parameters */
58
59 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
60 MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver");
61 MODULE_LICENSE("Dual MPL/GPL");
62
63 #ifdef PCMCIA_DEBUG
64 static int pc_debug = PCMCIA_DEBUG;
65 module_param(pc_debug, int, 0);
66 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
67 static char *version =
68 "fdomain_cs.c 1.47 2001/10/13 00:08:52 (David Hinds)";
69 #else
70 #define DEBUG(n, args...)
71 #endif
72
73 /*====================================================================*/
74
75 typedef struct scsi_info_t {
76     dev_link_t          link;
77     dev_node_t          node;
78     struct Scsi_Host    *host;
79 } scsi_info_t;
80
81
82 static void fdomain_release(dev_link_t *link);
83 static int fdomain_event(event_t event, int priority,
84                         event_callback_args_t *args);
85
86 static dev_link_t *fdomain_attach(void);
87 static void fdomain_detach(struct pcmcia_device *p_dev);
88
89
90 static dev_info_t dev_info = "fdomain_cs";
91
92 static dev_link_t *fdomain_attach(void)
93 {
94     scsi_info_t *info;
95     client_reg_t client_reg;
96     dev_link_t *link;
97     int ret;
98     
99     DEBUG(0, "fdomain_attach()\n");
100
101     /* Create new SCSI device */
102     info = kmalloc(sizeof(*info), GFP_KERNEL);
103     if (!info) return NULL;
104     memset(info, 0, sizeof(*info));
105     link = &info->link; link->priv = info;
106     link->io.NumPorts1 = 0x10;
107     link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
108     link->io.IOAddrLines = 10;
109     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
110     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
111     link->conf.Attributes = CONF_ENABLE_IRQ;
112     link->conf.Vcc = 50;
113     link->conf.IntType = INT_MEMORY_AND_IO;
114     link->conf.Present = PRESENT_OPTION;
115
116     /* Register with Card Services */
117     link->next = NULL;
118     client_reg.dev_info = &dev_info;
119     client_reg.Version = 0x0210;
120     client_reg.event_callback_args.client_data = link;
121     ret = pcmcia_register_client(&link->handle, &client_reg);
122     if (ret != 0) {
123         cs_error(link->handle, RegisterClient, ret);
124         fdomain_detach(link->handle);
125         return NULL;
126     }
127     
128     return link;
129 } /* fdomain_attach */
130
131 /*====================================================================*/
132
133 static void fdomain_detach(struct pcmcia_device *p_dev)
134 {
135         dev_link_t *link = dev_to_instance(p_dev);
136
137         DEBUG(0, "fdomain_detach(0x%p)\n", link);
138
139         if (link->state & DEV_CONFIG)
140                 fdomain_release(link);
141
142         kfree(link->priv);
143 } /* fdomain_detach */
144
145 /*====================================================================*/
146
147 #define CS_CHECK(fn, ret) \
148 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
149
150 static void fdomain_config(dev_link_t *link)
151 {
152     client_handle_t handle = link->handle;
153     scsi_info_t *info = link->priv;
154     tuple_t tuple;
155     cisparse_t parse;
156     int i, last_ret, last_fn;
157     u_char tuple_data[64];
158     char str[16];
159     struct Scsi_Host *host;
160
161     DEBUG(0, "fdomain_config(0x%p)\n", link);
162
163     tuple.DesiredTuple = CISTPL_CONFIG;
164     tuple.TupleData = tuple_data;
165     tuple.TupleDataMax = 64;
166     tuple.TupleOffset = 0;
167     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
168     CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
169     CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
170     link->conf.ConfigBase = parse.config.base;
171
172     /* Configure card */
173     link->state |= DEV_CONFIG;
174     
175     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
176     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
177     while (1) {
178         if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
179                 pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
180             goto next_entry;
181         link->conf.ConfigIndex = parse.cftable_entry.index;
182         link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
183         i = pcmcia_request_io(handle, &link->io);
184         if (i == CS_SUCCESS) break;
185     next_entry:
186         CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
187     }
188
189     CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
190     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
191     
192     /* A bad hack... */
193     release_region(link->io.BasePort1, link->io.NumPorts1);
194
195     /* Set configuration options for the fdomain driver */
196     sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ);
197     fdomain_setup(str);
198     
199     host = __fdomain_16x0_detect(&fdomain_driver_template);
200     if (!host) {
201         printk(KERN_INFO "fdomain_cs: no SCSI devices found\n");
202         goto cs_failed;
203     }
204  
205     scsi_add_host(host, NULL); /* XXX handle failure */
206     scsi_scan_host(host);
207
208     sprintf(info->node.dev_name, "scsi%d", host->host_no);
209     link->dev = &info->node;
210     info->host = host;
211     
212     link->state &= ~DEV_CONFIG_PENDING;
213     return;
214     
215 cs_failed:
216     cs_error(link->handle, last_fn, last_ret);
217     fdomain_release(link);
218     return;
219     
220 } /* fdomain_config */
221
222 /*====================================================================*/
223
224 static void fdomain_release(dev_link_t *link)
225 {
226     scsi_info_t *info = link->priv;
227
228     DEBUG(0, "fdomain_release(0x%p)\n", link);
229
230     scsi_remove_host(info->host);
231     link->dev = NULL;
232     
233     pcmcia_release_configuration(link->handle);
234     pcmcia_release_io(link->handle, &link->io);
235     pcmcia_release_irq(link->handle, &link->irq);
236
237     scsi_unregister(info->host);
238
239     link->state &= ~DEV_CONFIG;
240 }
241
242 /*====================================================================*/
243
244 static int fdomain_suspend(struct pcmcia_device *dev)
245 {
246         dev_link_t *link = dev_to_instance(dev);
247
248         link->state |= DEV_SUSPEND;
249         if (link->state & DEV_CONFIG)
250                 pcmcia_release_configuration(link->handle);
251
252         return 0;
253 }
254
255 static int fdomain_resume(struct pcmcia_device *dev)
256 {
257         dev_link_t *link = dev_to_instance(dev);
258
259         link->state &= ~DEV_SUSPEND;
260         if (link->state & DEV_CONFIG) {
261                 pcmcia_request_configuration(link->handle, &link->conf);
262                 fdomain_16x0_bus_reset(NULL);
263         }
264
265         return 0;
266 }
267
268 static int fdomain_event(event_t event, int priority,
269                         event_callback_args_t *args)
270 {
271     dev_link_t *link = args->client_data;
272
273     DEBUG(1, "fdomain_event(0x%06x)\n", event);
274     
275     switch (event) {
276     case CS_EVENT_CARD_INSERTION:
277         link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
278         fdomain_config(link);
279         break;
280     }
281     return 0;
282 } /* fdomain_event */
283
284
285 static struct pcmcia_device_id fdomain_ids[] = {
286         PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88, 0x859cad20),
287         PCMCIA_DEVICE_PROD_ID1("SCSI PCMCIA Adapter Card", 0x8dacb57e),
288         PCMCIA_DEVICE_PROD_ID12(" SIMPLE TECHNOLOGY Corporation", "SCSI PCMCIA Credit Card Controller", 0x182bdafe, 0xc80d106f),
289         PCMCIA_DEVICE_NULL,
290 };
291 MODULE_DEVICE_TABLE(pcmcia, fdomain_ids);
292
293 static struct pcmcia_driver fdomain_cs_driver = {
294         .owner          = THIS_MODULE,
295         .drv            = {
296                 .name   = "fdomain_cs",
297         },
298         .attach         = fdomain_attach,
299         .event          = fdomain_event,
300         .remove         = fdomain_detach,
301         .id_table       = fdomain_ids,
302         .suspend        = fdomain_suspend,
303         .resume         = fdomain_resume,
304 };
305
306 static int __init init_fdomain_cs(void)
307 {
308         return pcmcia_register_driver(&fdomain_cs_driver);
309 }
310
311 static void __exit exit_fdomain_cs(void)
312 {
313         pcmcia_unregister_driver(&fdomain_cs_driver);
314 }
315
316 module_init(init_fdomain_cs);
317 module_exit(exit_fdomain_cs);