]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/scsi/pcmcia/fdomain_stub.c
[PATCH] pcmcia: move event handler
[mirror_ubuntu-artful-kernel.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);