This source file includes following definitions.
- wdc_pcmcia_disk_device_interface_callback
- wdc_pcmcia_disk_device_interface
- wdc_pcmcia_lookup
- wdc_pcmcia_match
- wdc_pcmcia_attach
- wdc_pcmcia_detach
- wdc_pcmcia_activate
- wdc_pcmcia_enable
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/conf.h>
44 #include <sys/file.h>
45 #include <sys/stat.h>
46 #include <sys/ioctl.h>
47 #include <sys/buf.h>
48 #include <sys/uio.h>
49 #include <sys/malloc.h>
50 #include <sys/device.h>
51 #include <sys/disklabel.h>
52 #include <sys/disk.h>
53 #include <sys/syslog.h>
54 #include <sys/proc.h>
55
56 #include <uvm/uvm_extern.h>
57
58 #include <machine/cpu.h>
59 #include <machine/intr.h>
60 #include <machine/bus.h>
61
62 #include <dev/pcmcia/pcmciareg.h>
63 #include <dev/pcmcia/pcmciavar.h>
64 #include <dev/pcmcia/pcmciadevs.h>
65
66 #include <dev/ata/atavar.h>
67 #include <dev/ic/wdcvar.h>
68
69 #define WDC_PCMCIA_REG_NPORTS 8
70 #define WDC_PCMCIA_AUXREG_OFFSET (WDC_PCMCIA_REG_NPORTS + 6)
71 #define WDC_PCMCIA_AUXREG_NPORTS 2
72
73 struct wdc_pcmcia_softc {
74 struct wdc_softc sc_wdcdev;
75 struct channel_softc *wdc_chanptr;
76 struct channel_softc wdc_channel;
77 struct pcmcia_io_handle sc_pioh;
78 struct pcmcia_io_handle sc_auxpioh;
79 int sc_iowindow;
80 int sc_auxiowindow;
81 void *sc_ih;
82 struct pcmcia_function *sc_pf;
83 int sc_flags;
84 #define WDC_PCMCIA_ATTACH 0x0001
85 };
86
87 static int wdc_pcmcia_match(struct device *, void *, void *);
88 static void wdc_pcmcia_attach(struct device *, struct device *, void *);
89 int wdc_pcmcia_detach(struct device *, int);
90 int wdc_pcmcia_activate(struct device *, enum devact);
91
92 struct cfattach wdc_pcmcia_ca = {
93 sizeof(struct wdc_pcmcia_softc), wdc_pcmcia_match, wdc_pcmcia_attach,
94 wdc_pcmcia_detach, wdc_pcmcia_activate
95 };
96
97 struct wdc_pcmcia_product {
98 u_int16_t wpp_vendor;
99 u_int16_t wpp_product;
100 int wpp_quirk_flag;
101 #define WDC_PCMCIA_FORCE_16BIT_IO 0x01
102 #define WDC_PCMCIA_NO_EXTRA_RESETS 0x02
103 const char *wpp_cis_info[4];
104 } wdc_pcmcia_pr[] = {
105
106 { 0x0100,
107 PCMCIA_PRODUCT_DIGITAL_MOBILE_MEDIA_CDROM,
108 0, { NULL, "Digital Mobile Media CD-ROM", NULL, NULL }, },
109
110 { PCMCIA_VENDOR_IBM, PCMCIA_PRODUCT_IBM_PORTABLE_CDROM,
111 0, { NULL, "Portable CD-ROM Drive", NULL, NULL }, },
112
113 { PCMCIA_VENDOR_HAGIWARASYSCOM, PCMCIA_PRODUCT_INVALID,
114 WDC_PCMCIA_FORCE_16BIT_IO, { NULL, NULL, NULL, NULL }, },
115
116
117 { PCMCIA_VENDOR_TEAC, PCMCIA_PRODUCT_TEAC_IDECARDII,
118 WDC_PCMCIA_NO_EXTRA_RESETS, PCMCIA_CIS_TEAC_IDECARDII },
119
120
121
122
123
124 { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
125 0, PCMCIA_CIS_EXP_EXPMULTIMEDIA },
126
127
128 { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
129 0, PCMCIA_CIS_SHUTTLE_IDE_ATAPI },
130
131
132 { PCMCIA_VENDOR_ARCHOS, PCMCIA_PRODUCT_ARCHOS_ARC_ATAPI,
133 0, PCMCIA_CIS_ARCHOS_ARC_ATAPI },
134 };
135
136 struct wdc_pcmcia_disk_device_interface_args {
137 int ddi_type;
138 int ddi_reqfn;
139 int ddi_curfn;
140 };
141
142 int wdc_pcmcia_disk_device_interface_callback(struct pcmcia_tuple *,
143 void *);
144 int wdc_pcmcia_disk_device_interface(struct pcmcia_function *);
145 struct wdc_pcmcia_product *
146 wdc_pcmcia_lookup(struct pcmcia_attach_args *);
147
148 int wdc_pcmcia_enable(void *, int);
149
150 int
151 wdc_pcmcia_disk_device_interface_callback(tuple, arg)
152 struct pcmcia_tuple *tuple;
153 void *arg;
154 {
155 struct wdc_pcmcia_disk_device_interface_args *ddi = arg;
156
157 switch (tuple->code) {
158 case PCMCIA_CISTPL_FUNCID:
159 ddi->ddi_curfn++;
160 break;
161
162 case PCMCIA_CISTPL_FUNCE:
163 if (ddi->ddi_reqfn != ddi->ddi_curfn)
164 break;
165
166
167 if (tuple->length < 2)
168 break;
169
170
171 if (pcmcia_tuple_read_1(tuple, 0) !=
172 PCMCIA_TPLFE_TYPE_DISK_DEVICE_INTERFACE)
173 break;
174
175 ddi->ddi_type = pcmcia_tuple_read_1(tuple, 1);
176 return (1);
177 }
178 return (0);
179 }
180
181 int
182 wdc_pcmcia_disk_device_interface(pf)
183 struct pcmcia_function *pf;
184 {
185 struct wdc_pcmcia_disk_device_interface_args ddi;
186
187 ddi.ddi_reqfn = pf->number;
188 ddi.ddi_curfn = -1;
189 if (pcmcia_scan_cis((struct device *)pf->sc,
190 wdc_pcmcia_disk_device_interface_callback, &ddi) > 0)
191 return (ddi.ddi_type);
192 else
193 return (-1);
194 }
195
196 struct wdc_pcmcia_product *
197 wdc_pcmcia_lookup(pa)
198 struct pcmcia_attach_args *pa;
199 {
200 struct wdc_pcmcia_product *wpp;
201 int i, cis_match;
202
203 for (wpp = wdc_pcmcia_pr;
204 wpp < &wdc_pcmcia_pr[sizeof(wdc_pcmcia_pr)/sizeof(wdc_pcmcia_pr[0])];
205 wpp++)
206 if ((wpp->wpp_vendor == PCMCIA_VENDOR_INVALID ||
207 pa->manufacturer == wpp->wpp_vendor) &&
208 (wpp->wpp_product == PCMCIA_PRODUCT_INVALID ||
209 pa->product == wpp->wpp_product)) {
210 cis_match = 1;
211 for (i = 0; i < 4; i++) {
212 if (!(wpp->wpp_cis_info[i] == NULL ||
213 (pa->card->cis1_info[i] != NULL &&
214 strcmp(pa->card->cis1_info[i],
215 wpp->wpp_cis_info[i]) == 0)))
216 cis_match = 0;
217 }
218 if (cis_match)
219 return (wpp);
220 }
221
222 return (NULL);
223 }
224
225 static int
226 wdc_pcmcia_match(parent, match, aux)
227 struct device *parent;
228 void *match, *aux;
229 {
230 struct pcmcia_attach_args *pa = aux;
231 struct pcmcia_softc *sc;
232 int iftype;
233
234 if (wdc_pcmcia_lookup(pa) != NULL)
235 return (1);
236
237 if (pa->pf->function == PCMCIA_FUNCTION_DISK) {
238 sc = pa->pf->sc;
239
240 pcmcia_chip_socket_enable(sc->pct, sc->pch);
241 iftype = wdc_pcmcia_disk_device_interface(pa->pf);
242 pcmcia_chip_socket_disable(sc->pct, sc->pch);
243
244 if (iftype == PCMCIA_TPLFE_DDI_PCCARD_ATA)
245 return (1);
246 }
247
248 return (0);
249 }
250
251 static void
252 wdc_pcmcia_attach(parent, self, aux)
253 struct device *parent;
254 struct device *self;
255 void *aux;
256 {
257 struct wdc_pcmcia_softc *sc = (void *)self;
258 struct pcmcia_attach_args *pa = aux;
259 struct pcmcia_config_entry *cfe;
260 struct wdc_pcmcia_product *wpp;
261 const char *intrstr;
262 int quirks;
263
264 sc->sc_pf = pa->pf;
265
266 for (cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head); cfe != NULL;
267 cfe = SIMPLEQ_NEXT(cfe, cfe_list)) {
268 if (cfe->num_iospace != 1 && cfe->num_iospace != 2)
269 continue;
270
271 if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start,
272 cfe->iospace[0].length,
273 cfe->iospace[0].start == 0 ? cfe->iospace[0].length : 0,
274 &sc->sc_pioh))
275 continue;
276
277 if (cfe->num_iospace == 2) {
278 if (!pcmcia_io_alloc(pa->pf, cfe->iospace[1].start,
279 cfe->iospace[1].length, 0, &sc->sc_auxpioh))
280 break;
281 } else {
282 sc->sc_auxpioh.iot = sc->sc_pioh.iot;
283 if (!bus_space_subregion(sc->sc_pioh.iot,
284 sc->sc_pioh.ioh, WDC_PCMCIA_AUXREG_OFFSET,
285 WDC_PCMCIA_AUXREG_NPORTS, &sc->sc_auxpioh.ioh))
286 break;
287 }
288 pcmcia_io_free(pa->pf, &sc->sc_pioh);
289 }
290
291 if (cfe == NULL) {
292 printf(": can't handle card info\n");
293 goto no_config_entry;
294 }
295
296
297 pcmcia_function_init(pa->pf, cfe);
298 if (pcmcia_function_enable(pa->pf)) {
299 printf(": function enable failed\n");
300 goto enable_failed;
301 }
302
303
304
305
306
307
308
309
310 wpp = wdc_pcmcia_lookup(pa);
311 if (wpp != NULL)
312 quirks = wpp->wpp_quirk_flag;
313 else
314 quirks = 0;
315
316 if (pcmcia_io_map(pa->pf, quirks & WDC_PCMCIA_FORCE_16BIT_IO ?
317 PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_AUTO, 0,
318 sc->sc_pioh.size, &sc->sc_pioh, &sc->sc_iowindow)) {
319 printf(": can't map first I/O space\n");
320 goto iomap_failed;
321 }
322
323
324
325
326
327
328 if (cfe->num_iospace <= 1)
329 sc->sc_auxiowindow = -1;
330 else if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 0,
331 sc->sc_auxpioh.size, &sc->sc_auxpioh, &sc->sc_auxiowindow)) {
332 printf(": can't map second I/O space\n");
333 goto iomapaux_failed;
334 }
335
336 printf(" port 0x%lx/%lu",
337 sc->sc_pioh.addr, (u_long)sc->sc_pioh.size);
338 if (cfe->num_iospace > 1 && sc->sc_auxpioh.size > 0)
339 printf(",0x%lx/%lu",
340 sc->sc_auxpioh.addr, (u_long)sc->sc_auxpioh.size);
341
342 sc->wdc_channel.cmd_iot = sc->sc_pioh.iot;
343 sc->wdc_channel.cmd_ioh = sc->sc_pioh.ioh;
344 sc->wdc_channel.ctl_iot = sc->sc_auxpioh.iot;
345 sc->wdc_channel.ctl_ioh = sc->sc_auxpioh.ioh;
346 sc->wdc_channel.data32iot = sc->wdc_channel.cmd_iot;
347 sc->wdc_channel.data32ioh = sc->wdc_channel.cmd_ioh;
348 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32;
349 sc->sc_wdcdev.PIO_cap = 0;
350 sc->wdc_chanptr = &sc->wdc_channel;
351 sc->sc_wdcdev.channels = &sc->wdc_chanptr;
352 sc->sc_wdcdev.nchannels = 1;
353 sc->wdc_channel.channel = 0;
354 sc->wdc_channel.wdc = &sc->sc_wdcdev;
355 sc->wdc_channel.ch_queue = malloc(sizeof(struct channel_queue),
356 M_DEVBUF, M_NOWAIT);
357 if (sc->wdc_channel.ch_queue == NULL) {
358 printf("can't allocate memory for command queue\n");
359 goto ch_queue_alloc_failed;
360 }
361 if (quirks & WDC_PCMCIA_NO_EXTRA_RESETS)
362 sc->sc_wdcdev.cap |= WDC_CAPABILITY_NO_EXTRA_RESETS;
363
364 #ifdef notyet
365
366 sc->sc_wdcdev.sc_atapi_adapter.scsipi_enable = wdc_pcmcia_enable;
367
368
369
370
371
372 pcmcia_function_disable(pa->pf);
373 #else
374
375 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, wdcintr,
376 &sc->wdc_channel, sc->sc_wdcdev.sc_dev.dv_xname);
377 intrstr = pcmcia_intr_string(sc->sc_pf, sc->sc_ih);
378 if (*intrstr)
379 printf(": %s", intrstr);
380 #endif
381
382 printf("\n");
383
384 sc->sc_flags |= WDC_PCMCIA_ATTACH;
385 wdcattach(&sc->wdc_channel);
386 wdc_print_current_modes(&sc->wdc_channel);
387 sc->sc_flags &= ~WDC_PCMCIA_ATTACH;
388 return;
389
390 ch_queue_alloc_failed:
391
392 if (sc->sc_auxiowindow != -1)
393 pcmcia_io_unmap(sc->sc_pf, sc->sc_auxiowindow);
394
395 iomapaux_failed:
396
397 pcmcia_io_unmap(sc->sc_pf, sc->sc_iowindow);
398
399 iomap_failed:
400
401 pcmcia_function_disable(sc->sc_pf);
402
403 enable_failed:
404
405 pcmcia_io_free(sc->sc_pf, &sc->sc_pioh);
406 if (cfe->num_iospace == 2)
407 pcmcia_io_free(sc->sc_pf, &sc->sc_auxpioh);
408
409 no_config_entry:
410 sc->sc_iowindow = -1;
411 }
412
413 int
414 wdc_pcmcia_detach(self, flags)
415 struct device *self;
416 int flags;
417 {
418 struct wdc_pcmcia_softc *sc = (struct wdc_pcmcia_softc *)self;
419 int error;
420
421 if (sc->sc_iowindow == -1)
422
423 return (0);
424
425 if ((error = wdcdetach(&sc->wdc_channel, flags)) != 0)
426 return (error);
427
428 if (sc->wdc_channel.ch_queue != NULL)
429 free(sc->wdc_channel.ch_queue, M_DEVBUF);
430
431
432 pcmcia_io_unmap(sc->sc_pf, sc->sc_iowindow);
433 pcmcia_io_free(sc->sc_pf, &sc->sc_pioh);
434 if (sc->sc_auxiowindow != -1) {
435 pcmcia_io_unmap(sc->sc_pf, sc->sc_auxiowindow);
436 pcmcia_io_free(sc->sc_pf, &sc->sc_auxpioh);
437 }
438
439 return (0);
440 }
441
442 int
443 wdc_pcmcia_activate(self, act)
444 struct device *self;
445 enum devact act;
446 {
447 struct wdc_pcmcia_softc *sc = (struct wdc_pcmcia_softc *)self;
448 int rv = 0, s;
449
450 s = splbio();
451 switch (act) {
452 case DVACT_ACTIVATE:
453 if (pcmcia_function_enable(sc->sc_pf)) {
454 printf("%s: couldn't enable PCMCIA function\n",
455 sc->sc_wdcdev.sc_dev.dv_xname);
456 rv = EIO;
457 break;
458 }
459
460 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO,
461 wdcintr, &sc->wdc_channel, sc->sc_wdcdev.sc_dev.dv_xname);
462 if (sc->sc_ih == NULL) {
463 printf("%s: "
464 "couldn't establish interrupt handler\n",
465 sc->sc_wdcdev.sc_dev.dv_xname);
466 pcmcia_function_disable(sc->sc_pf);
467 rv = EIO;
468 break;
469 }
470
471 wdcreset(&sc->wdc_channel, VERBOSE);
472 rv = wdcactivate(self, act);
473 break;
474
475 case DVACT_DEACTIVATE:
476 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
477 pcmcia_function_disable(sc->sc_pf);
478 rv = wdcactivate(self, act);
479 break;
480 }
481 splx(s);
482 return (rv);
483 }
484
485 #if 0
486 int
487 wdc_pcmcia_enable(arg, onoff)
488 void *arg;
489 int onoff;
490 {
491 struct wdc_pcmcia_softc *sc = arg;
492
493 if (onoff) {
494 if ((sc->sc_flags & WDC_PCMCIA_ATTACH) == 0) {
495 if (pcmcia_function_enable(sc->sc_pf)) {
496 printf("%s: couldn't enable PCMCIA function\n",
497 sc->sc_wdcdev.sc_dev.dv_xname);
498 return (EIO);
499 }
500
501 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO,
502 wdcintr, &sc->wdc_channel, sc->sc_dev.dv_xname);
503 if (sc->sc_ih == NULL) {
504 printf("%s: "
505 "couldn't establish interrupt handler\n",
506 sc->sc_wdcdev.sc_dev.dv_xname);
507 pcmcia_function_disable(sc->sc_pf);
508 return (EIO);
509 }
510
511 wdcreset(&sc->wdc_channel, VERBOSE);
512 }
513 } else {
514 if ((sc->sc_flags & WDC_PCMCIA_ATTACH) == 0)
515 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
516 pcmcia_function_disable(sc->sc_pf);
517 }
518
519 return (0);
520 }
521 #endif