diff options
author | Daniel Ritz <daniel.ritz@gmx.ch> | 2005-06-23 03:10:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-23 12:45:31 -0400 |
commit | fa912bcb06d5dc9525d8912a145db2bf4b7668c5 (patch) | |
tree | 5c62d9a1ef416c83d3e149ca94c4e646eb29daf2 | |
parent | 7007cab53176dc906e67b4efa62f20ff1432805a (diff) |
[PATCH] yenta TI: turn off interrupts during card power-on #2
- make boot-up card recognition more reliable (ie. redo interrogation
always if there is no valid 'card inserted' state) (and yes, i saw it
happening on an o2micro controller that both CB_CBARD and CB_16BITCARD
bits were set at the same time)
- also redo interrogation before probing the ISA interrupts. it's safer
to do the probing with the socket in a clean state.
- make card insert detect more reliable. yenta_get_status() now returns
SS_PENDING as long as the card is not completley inserted and one of the
voltage bits is set. also !CB_CBARD doesn't mean CB_16BITCARD. there is
CB_NOTACARD as well, so make an explicit check for CB_16BITCARD.
- for TI bridges: disable IRQs during power-on. in all-serial and tied
interrupt mode the interrupts are always disabled for single-slot
controllers. for two-slot contollers the disabling is only done when the
other slot is empty. to force disabling there is a new module parameter
now: pwr_irqs_off=Y (which is a regression for working setups. that's
why it's an option, only use when required)
- modparm to disable ISA interrupt probing (isa_probe, defaults to on)
- remove unneeded code/cleanups (ie. merge yenta_events() into
yenta_interrupts())
Signed-off-by: Daniel Ritz <daniel.ritz@gmx.ch>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/pcmcia/cs.c | 11 | ||||
-rw-r--r-- | drivers/pcmcia/ti113x.h | 167 | ||||
-rw-r--r-- | drivers/pcmcia/yenta_socket.c | 60 | ||||
-rw-r--r-- | include/pcmcia/ss.h | 8 |
4 files changed, 223 insertions, 23 deletions
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 03fc885db1c5..d136b3c8fac9 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c | |||
@@ -508,6 +508,10 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay) | |||
508 | cs_err(skt, "unsupported voltage key.\n"); | 508 | cs_err(skt, "unsupported voltage key.\n"); |
509 | return CS_BAD_TYPE; | 509 | return CS_BAD_TYPE; |
510 | } | 510 | } |
511 | |||
512 | if (skt->power_hook) | ||
513 | skt->power_hook(skt, HOOK_POWER_PRE); | ||
514 | |||
511 | skt->socket.flags = 0; | 515 | skt->socket.flags = 0; |
512 | skt->ops->set_socket(skt, &skt->socket); | 516 | skt->ops->set_socket(skt, &skt->socket); |
513 | 517 | ||
@@ -522,7 +526,12 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay) | |||
522 | return CS_BAD_TYPE; | 526 | return CS_BAD_TYPE; |
523 | } | 527 | } |
524 | 528 | ||
525 | return socket_reset(skt); | 529 | status = socket_reset(skt); |
530 | |||
531 | if (skt->power_hook) | ||
532 | skt->power_hook(skt, HOOK_POWER_POST); | ||
533 | |||
534 | return status; | ||
526 | } | 535 | } |
527 | 536 | ||
528 | /* | 537 | /* |
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h index a8a1d104524a..c7ba99871aca 100644 --- a/drivers/pcmcia/ti113x.h +++ b/drivers/pcmcia/ti113x.h | |||
@@ -611,6 +611,170 @@ out: | |||
611 | } | 611 | } |
612 | } | 612 | } |
613 | 613 | ||
614 | |||
615 | /* Returns true value if the second slot of a two-slot controller is empty */ | ||
616 | static int ti12xx_2nd_slot_empty(struct yenta_socket *socket) | ||
617 | { | ||
618 | struct pci_dev *func; | ||
619 | struct yenta_socket *slot2; | ||
620 | int devfn; | ||
621 | unsigned int state; | ||
622 | int ret = 1; | ||
623 | |||
624 | /* catch the two-slot controllers */ | ||
625 | switch (socket->dev->device) { | ||
626 | case PCI_DEVICE_ID_TI_1220: | ||
627 | case PCI_DEVICE_ID_TI_1221: | ||
628 | case PCI_DEVICE_ID_TI_1225: | ||
629 | case PCI_DEVICE_ID_TI_1251A: | ||
630 | case PCI_DEVICE_ID_TI_1251B: | ||
631 | case PCI_DEVICE_ID_TI_1420: | ||
632 | case PCI_DEVICE_ID_TI_1450: | ||
633 | case PCI_DEVICE_ID_TI_1451A: | ||
634 | case PCI_DEVICE_ID_TI_1520: | ||
635 | case PCI_DEVICE_ID_TI_1620: | ||
636 | case PCI_DEVICE_ID_TI_4520: | ||
637 | case PCI_DEVICE_ID_TI_4450: | ||
638 | case PCI_DEVICE_ID_TI_4451: | ||
639 | /* | ||
640 | * there are way more, but they need to be added in yenta_socket.c | ||
641 | * and pci_ids.h first anyway. | ||
642 | */ | ||
643 | break; | ||
644 | |||
645 | /* single-slot controllers have the 2nd slot empty always :) */ | ||
646 | default: | ||
647 | return 1; | ||
648 | } | ||
649 | |||
650 | /* get other slot */ | ||
651 | devfn = socket->dev->devfn & ~0x07; | ||
652 | func = pci_get_slot(socket->dev->bus, | ||
653 | (socket->dev->devfn & 0x07) ? devfn : devfn | 0x01); | ||
654 | if (!func) | ||
655 | return 1; | ||
656 | |||
657 | slot2 = pci_get_drvdata(func); | ||
658 | if (!slot2) | ||
659 | goto out; | ||
660 | |||
661 | /* check state */ | ||
662 | yenta_get_status(&socket->socket, &state); | ||
663 | if (state & SS_DETECT) { | ||
664 | ret = 0; | ||
665 | goto out; | ||
666 | } | ||
667 | |||
668 | out: | ||
669 | pci_dev_put(func); | ||
670 | return ret; | ||
671 | } | ||
672 | |||
673 | /* | ||
674 | * TI specifiy parts for the power hook. | ||
675 | * | ||
676 | * some TI's with some CB's produces interrupt storm on power on. it has been | ||
677 | * seen with atheros wlan cards on TI1225 and TI1410. solution is simply to | ||
678 | * disable any CB interrupts during this time. | ||
679 | */ | ||
680 | static int ti12xx_power_hook(struct pcmcia_socket *sock, int operation) | ||
681 | { | ||
682 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); | ||
683 | u32 mfunc, devctl, sysctl; | ||
684 | u8 gpio3; | ||
685 | |||
686 | /* only POWER_PRE and POWER_POST are interesting */ | ||
687 | if ((operation != HOOK_POWER_PRE) && (operation != HOOK_POWER_POST)) | ||
688 | return 0; | ||
689 | |||
690 | devctl = config_readb(socket, TI113X_DEVICE_CONTROL); | ||
691 | sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL); | ||
692 | mfunc = config_readl(socket, TI122X_MFUNC); | ||
693 | |||
694 | /* | ||
695 | * all serial/tied: only disable when modparm set. always doing it | ||
696 | * would mean a regression for working setups 'cos it disables the | ||
697 | * interrupts for both both slots on 2-slot controllers | ||
698 | * (and users of single slot controllers where it's save have to | ||
699 | * live with setting the modparm, most don't have to anyway) | ||
700 | */ | ||
701 | if (((devctl & TI113X_DCR_IMODE_MASK) == TI12XX_DCR_IMODE_ALL_SERIAL) && | ||
702 | (pwr_irqs_off || ti12xx_2nd_slot_empty(socket))) { | ||
703 | switch (socket->dev->device) { | ||
704 | case PCI_DEVICE_ID_TI_1250: | ||
705 | case PCI_DEVICE_ID_TI_1251A: | ||
706 | case PCI_DEVICE_ID_TI_1251B: | ||
707 | case PCI_DEVICE_ID_TI_1450: | ||
708 | case PCI_DEVICE_ID_TI_1451A: | ||
709 | case PCI_DEVICE_ID_TI_4450: | ||
710 | case PCI_DEVICE_ID_TI_4451: | ||
711 | /* these chips have no IRQSER setting in MFUNC3 */ | ||
712 | break; | ||
713 | |||
714 | default: | ||
715 | if (operation == HOOK_POWER_PRE) | ||
716 | mfunc = (mfunc & ~TI122X_MFUNC3_MASK); | ||
717 | else | ||
718 | mfunc = (mfunc & ~TI122X_MFUNC3_MASK) | TI122X_MFUNC3_IRQSER; | ||
719 | } | ||
720 | |||
721 | return 0; | ||
722 | } | ||
723 | |||
724 | /* do the job differently for func0/1 */ | ||
725 | if ((PCI_FUNC(socket->dev->devfn) == 0) || | ||
726 | ((sysctl & TI122X_SCR_INTRTIE) && | ||
727 | (pwr_irqs_off || ti12xx_2nd_slot_empty(socket)))) { | ||
728 | /* some bridges are different */ | ||
729 | switch (socket->dev->device) { | ||
730 | case PCI_DEVICE_ID_TI_1250: | ||
731 | case PCI_DEVICE_ID_TI_1251A: | ||
732 | case PCI_DEVICE_ID_TI_1251B: | ||
733 | case PCI_DEVICE_ID_TI_1450: | ||
734 | /* those oldies use gpio3 for INTA */ | ||
735 | gpio3 = config_readb(socket, TI1250_GPIO3_CONTROL); | ||
736 | if (operation == HOOK_POWER_PRE) | ||
737 | gpio3 = (gpio3 & ~TI1250_GPIO_MODE_MASK) | 0x40; | ||
738 | else | ||
739 | gpio3 &= ~TI1250_GPIO_MODE_MASK; | ||
740 | config_writeb(socket, TI1250_GPIO3_CONTROL, gpio3); | ||
741 | break; | ||
742 | |||
743 | default: | ||
744 | /* all new bridges are the same */ | ||
745 | if (operation == HOOK_POWER_PRE) | ||
746 | mfunc &= ~TI122X_MFUNC0_MASK; | ||
747 | else | ||
748 | mfunc |= TI122X_MFUNC0_INTA; | ||
749 | config_writel(socket, TI122X_MFUNC, mfunc); | ||
750 | } | ||
751 | } else { | ||
752 | switch (socket->dev->device) { | ||
753 | case PCI_DEVICE_ID_TI_1251A: | ||
754 | case PCI_DEVICE_ID_TI_1251B: | ||
755 | case PCI_DEVICE_ID_TI_1450: | ||
756 | /* those have INTA elsewhere and INTB in MFUNC0 */ | ||
757 | if (operation == HOOK_POWER_PRE) | ||
758 | mfunc &= ~TI122X_MFUNC0_MASK; | ||
759 | else | ||
760 | mfunc |= TI125X_MFUNC0_INTB; | ||
761 | config_writel(socket, TI122X_MFUNC, mfunc); | ||
762 | |||
763 | break; | ||
764 | |||
765 | default: | ||
766 | /* all new bridges are the same */ | ||
767 | if (operation == HOOK_POWER_PRE) | ||
768 | mfunc &= ~TI122X_MFUNC1_MASK; | ||
769 | else | ||
770 | mfunc |= TI122X_MFUNC1_INTB; | ||
771 | config_writel(socket, TI122X_MFUNC, mfunc); | ||
772 | } | ||
773 | } | ||
774 | |||
775 | return 0; | ||
776 | } | ||
777 | |||
614 | static int ti12xx_override(struct yenta_socket *socket) | 778 | static int ti12xx_override(struct yenta_socket *socket) |
615 | { | 779 | { |
616 | u32 val, val_orig; | 780 | u32 val, val_orig; |
@@ -654,6 +818,9 @@ static int ti12xx_override(struct yenta_socket *socket) | |||
654 | else | 818 | else |
655 | ti12xx_irqroute_func1(socket); | 819 | ti12xx_irqroute_func1(socket); |
656 | 820 | ||
821 | /* install power hook */ | ||
822 | socket->socket.power_hook = ti12xx_power_hook; | ||
823 | |||
657 | return ti_override(socket); | 824 | return ti_override(socket); |
658 | } | 825 | } |
659 | 826 | ||
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 6404d97a12eb..bee05362fd24 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c | |||
@@ -32,6 +32,14 @@ static int disable_clkrun; | |||
32 | module_param(disable_clkrun, bool, 0444); | 32 | module_param(disable_clkrun, bool, 0444); |
33 | MODULE_PARM_DESC(disable_clkrun, "If PC card doesn't function properly, please try this option"); | 33 | MODULE_PARM_DESC(disable_clkrun, "If PC card doesn't function properly, please try this option"); |
34 | 34 | ||
35 | static int isa_probe = 1; | ||
36 | module_param(isa_probe, bool, 0444); | ||
37 | MODULE_PARM_DESC(isa_probe, "If set ISA interrupts are probed (default). Set to N to disable probing"); | ||
38 | |||
39 | static int pwr_irqs_off; | ||
40 | module_param(pwr_irqs_off, bool, 0644); | ||
41 | MODULE_PARM_DESC(pwr_irqs_off, "Force IRQs off during power-on of slot. Use only when seeing IRQ storms!"); | ||
42 | |||
35 | #if 0 | 43 | #if 0 |
36 | #define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args) | 44 | #define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args) |
37 | #else | 45 | #else |
@@ -150,15 +158,16 @@ static int yenta_get_status(struct pcmcia_socket *sock, unsigned int *value) | |||
150 | 158 | ||
151 | val = (state & CB_3VCARD) ? SS_3VCARD : 0; | 159 | val = (state & CB_3VCARD) ? SS_3VCARD : 0; |
152 | val |= (state & CB_XVCARD) ? SS_XVCARD : 0; | 160 | val |= (state & CB_XVCARD) ? SS_XVCARD : 0; |
153 | val |= (state & (CB_CDETECT1 | CB_CDETECT2 | CB_5VCARD | CB_3VCARD | 161 | val |= (state & (CB_5VCARD | CB_3VCARD | CB_XVCARD | CB_YVCARD)) ? 0 : SS_PENDING; |
154 | | CB_XVCARD | CB_YVCARD)) ? 0 : SS_PENDING; | 162 | val |= (state & (CB_CDETECT1 | CB_CDETECT2)) ? SS_PENDING : 0; |
163 | |||
155 | 164 | ||
156 | if (state & CB_CBCARD) { | 165 | if (state & CB_CBCARD) { |
157 | val |= SS_CARDBUS; | 166 | val |= SS_CARDBUS; |
158 | val |= (state & CB_CARDSTS) ? SS_STSCHG : 0; | 167 | val |= (state & CB_CARDSTS) ? SS_STSCHG : 0; |
159 | val |= (state & (CB_CDETECT1 | CB_CDETECT2)) ? 0 : SS_DETECT; | 168 | val |= (state & (CB_CDETECT1 | CB_CDETECT2)) ? 0 : SS_DETECT; |
160 | val |= (state & CB_PWRCYCLE) ? SS_POWERON | SS_READY : 0; | 169 | val |= (state & CB_PWRCYCLE) ? SS_POWERON | SS_READY : 0; |
161 | } else { | 170 | } else if (state & CB_16BITCARD) { |
162 | u8 status = exca_readb(socket, I365_STATUS); | 171 | u8 status = exca_readb(socket, I365_STATUS); |
163 | val |= ((status & I365_CS_DETECT) == I365_CS_DETECT) ? SS_DETECT : 0; | 172 | val |= ((status & I365_CS_DETECT) == I365_CS_DETECT) ? SS_DETECT : 0; |
164 | if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) { | 173 | if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) { |
@@ -405,11 +414,13 @@ static int yenta_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map * | |||
405 | } | 414 | } |
406 | 415 | ||
407 | 416 | ||
408 | static unsigned int yenta_events(struct yenta_socket *socket) | 417 | |
418 | static irqreturn_t yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
409 | { | 419 | { |
420 | unsigned int events; | ||
421 | struct yenta_socket *socket = (struct yenta_socket *) dev_id; | ||
410 | u8 csc; | 422 | u8 csc; |
411 | u32 cb_event; | 423 | u32 cb_event; |
412 | unsigned int events; | ||
413 | 424 | ||
414 | /* Clear interrupt status for the event */ | 425 | /* Clear interrupt status for the event */ |
415 | cb_event = cb_readl(socket, CB_SOCKET_EVENT); | 426 | cb_event = cb_readl(socket, CB_SOCKET_EVENT); |
@@ -426,20 +437,13 @@ static unsigned int yenta_events(struct yenta_socket *socket) | |||
426 | events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0; | 437 | events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0; |
427 | events |= (csc & I365_CSC_READY) ? SS_READY : 0; | 438 | events |= (csc & I365_CSC_READY) ? SS_READY : 0; |
428 | } | 439 | } |
429 | return events; | ||
430 | } | ||
431 | |||
432 | |||
433 | static irqreturn_t yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
434 | { | ||
435 | unsigned int events; | ||
436 | struct yenta_socket *socket = (struct yenta_socket *) dev_id; | ||
437 | 440 | ||
438 | events = yenta_events(socket); | 441 | if (events) |
439 | if (events) { | ||
440 | pcmcia_parse_events(&socket->socket, events); | 442 | pcmcia_parse_events(&socket->socket, events); |
443 | |||
444 | if (cb_event || csc) | ||
441 | return IRQ_HANDLED; | 445 | return IRQ_HANDLED; |
442 | } | 446 | |
443 | return IRQ_NONE; | 447 | return IRQ_NONE; |
444 | } | 448 | } |
445 | 449 | ||
@@ -470,11 +474,22 @@ static void yenta_clear_maps(struct yenta_socket *socket) | |||
470 | } | 474 | } |
471 | } | 475 | } |
472 | 476 | ||
477 | /* redoes voltage interrogation if required */ | ||
478 | static void yenta_interrogate(struct yenta_socket *socket) | ||
479 | { | ||
480 | u32 state; | ||
481 | |||
482 | state = cb_readl(socket, CB_SOCKET_STATE); | ||
483 | if (!(state & (CB_5VCARD | CB_3VCARD | CB_XVCARD | CB_YVCARD)) || | ||
484 | (state & (CB_CDETECT1 | CB_CDETECT2 | CB_NOTACARD | CB_BADVCCREQ)) || | ||
485 | ((state & (CB_16BITCARD | CB_CBCARD)) == (CB_16BITCARD | CB_CBCARD))) | ||
486 | cb_writel(socket, CB_SOCKET_FORCE, CB_CVSTEST); | ||
487 | } | ||
488 | |||
473 | /* Called at resume and initialization events */ | 489 | /* Called at resume and initialization events */ |
474 | static int yenta_sock_init(struct pcmcia_socket *sock) | 490 | static int yenta_sock_init(struct pcmcia_socket *sock) |
475 | { | 491 | { |
476 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); | 492 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); |
477 | u32 state; | ||
478 | u16 bridge; | 493 | u16 bridge; |
479 | 494 | ||
480 | bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~CB_BRIDGE_INTR; | 495 | bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~CB_BRIDGE_INTR; |
@@ -486,10 +501,7 @@ static int yenta_sock_init(struct pcmcia_socket *sock) | |||
486 | exca_writeb(socket, I365_GENCTL, 0x00); | 501 | exca_writeb(socket, I365_GENCTL, 0x00); |
487 | 502 | ||
488 | /* Redo card voltage interrogation */ | 503 | /* Redo card voltage interrogation */ |
489 | state = cb_readl(socket, CB_SOCKET_STATE); | 504 | yenta_interrogate(socket); |
490 | if (!(state & (CB_CDETECT1 | CB_CDETECT2 | CB_5VCARD | | ||
491 | CB_3VCARD | CB_XVCARD | CB_YVCARD))) | ||
492 | cb_writel(socket, CB_SOCKET_FORCE, CB_CVSTEST); | ||
493 | 505 | ||
494 | yenta_clear_maps(socket); | 506 | yenta_clear_maps(socket); |
495 | 507 | ||
@@ -856,7 +868,10 @@ static void yenta_get_socket_capabilities(struct yenta_socket *socket, u32 isa_i | |||
856 | socket->socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS; | 868 | socket->socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS; |
857 | socket->socket.map_size = 0x1000; | 869 | socket->socket.map_size = 0x1000; |
858 | socket->socket.pci_irq = socket->cb_irq; | 870 | socket->socket.pci_irq = socket->cb_irq; |
859 | socket->socket.irq_mask = yenta_probe_irq(socket, isa_irq_mask); | 871 | if (isa_probe) |
872 | socket->socket.irq_mask = yenta_probe_irq(socket, isa_irq_mask); | ||
873 | else | ||
874 | socket->socket.irq_mask = 0; | ||
860 | socket->socket.cb_dev = socket->dev; | 875 | socket->socket.cb_dev = socket->dev; |
861 | 876 | ||
862 | printk(KERN_INFO "Yenta: ISA IRQ mask 0x%04x, PCI irq %d\n", | 877 | printk(KERN_INFO "Yenta: ISA IRQ mask 0x%04x, PCI irq %d\n", |
@@ -996,6 +1011,7 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i | |||
996 | } | 1011 | } |
997 | 1012 | ||
998 | /* Figure out what the dang thing can do for the PCMCIA layer... */ | 1013 | /* Figure out what the dang thing can do for the PCMCIA layer... */ |
1014 | yenta_interrogate(socket); | ||
999 | yenta_get_socket_capabilities(socket, isa_interrupts); | 1015 | yenta_get_socket_capabilities(socket, isa_interrupts); |
1000 | printk(KERN_INFO "Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE)); | 1016 | printk(KERN_INFO "Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE)); |
1001 | 1017 | ||
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 6d3413a56708..67b867f31fe4 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h | |||
@@ -77,6 +77,11 @@ extern socket_state_t dead_socket; | |||
77 | /* Use this just for bridge windows */ | 77 | /* Use this just for bridge windows */ |
78 | #define MAP_IOSPACE 0x20 | 78 | #define MAP_IOSPACE 0x20 |
79 | 79 | ||
80 | /* power hook operations */ | ||
81 | #define HOOK_POWER_PRE 0x01 | ||
82 | #define HOOK_POWER_POST 0x02 | ||
83 | |||
84 | |||
80 | typedef struct pccard_io_map { | 85 | typedef struct pccard_io_map { |
81 | u_char map; | 86 | u_char map; |
82 | u_char flags; | 87 | u_char flags; |
@@ -222,6 +227,9 @@ struct pcmcia_socket { | |||
222 | /* Zoom video behaviour is so chip specific its not worth adding | 227 | /* Zoom video behaviour is so chip specific its not worth adding |
223 | this to _ops */ | 228 | this to _ops */ |
224 | void (*zoom_video)(struct pcmcia_socket *, int); | 229 | void (*zoom_video)(struct pcmcia_socket *, int); |
230 | |||
231 | /* so is power hook */ | ||
232 | int (*power_hook)(struct pcmcia_socket *sock, int operation); | ||
225 | 233 | ||
226 | /* state thread */ | 234 | /* state thread */ |
227 | struct semaphore skt_sem; /* protects socket h/w state */ | 235 | struct semaphore skt_sem; /* protects socket h/w state */ |