aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia/ds.c
diff options
context:
space:
mode:
authorDominik Brodowski <linux@dominikbrodowski.net>2005-06-27 19:28:06 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-27 21:03:06 -0400
commit1ad275e3e7d253d44f03868e85977c908e334fed (patch)
tree82f0a1fc070f32c015be14596c50c681d90d4c1a /drivers/pcmcia/ds.c
parent3ee13937525f6044d769b1a84d5db5669ac1959e (diff)
[PATCH] pcmcia: device and driver matching
The actual matching of pcmcia drivers and pcmcia devices. The original version of this was written by David Woodhouse. Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/pcmcia/ds.c')
-rw-r--r--drivers/pcmcia/ds.c123
1 files changed, 122 insertions, 1 deletions
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 35d479b0df64..5701b93b2ddb 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -101,6 +101,9 @@ struct pcmcia_bus_socket {
101 u8 device_count; /* the number of devices, used 101 u8 device_count; /* the number of devices, used
102 * only internally and subject 102 * only internally and subject
103 * to incorrectness and change */ 103 * to incorrectness and change */
104
105 u8 device_add_pending;
106 struct work_struct device_add;
104}; 107};
105static spinlock_t pcmcia_dev_list_lock; 108static spinlock_t pcmcia_dev_list_lock;
106 109
@@ -512,6 +515,10 @@ static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s, uns
512 515
513 down(&device_add_lock); 516 down(&device_add_lock);
514 517
518 /* max of 2 devices per card */
519 if (s->device_count == 2)
520 goto err_put;
521
515 p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL); 522 p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
516 if (!p_dev) 523 if (!p_dev)
517 goto err_put; 524 goto err_put;
@@ -537,6 +544,8 @@ static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s, uns
537 list_add_tail(&p_dev->socket_device_list, &s->devices_list); 544 list_add_tail(&p_dev->socket_device_list, &s->devices_list);
538 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); 545 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
539 546
547 pcmcia_device_query(p_dev);
548
540 if (device_register(&p_dev->dev)) { 549 if (device_register(&p_dev->dev)) {
541 spin_lock_irqsave(&pcmcia_dev_list_lock, flags); 550 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
542 list_del(&p_dev->socket_device_list); 551 list_del(&p_dev->socket_device_list);
@@ -591,14 +600,123 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
591} 600}
592 601
593 602
603static void pcmcia_delayed_add_pseudo_device(void *data)
604{
605 struct pcmcia_bus_socket *s = data;
606 pcmcia_device_add(s, 0);
607 s->device_add_pending = 0;
608}
609
610static inline void pcmcia_add_pseudo_device(struct pcmcia_bus_socket *s)
611{
612 if (!s->device_add_pending) {
613 schedule_work(&s->device_add);
614 s->device_add_pending = 1;
615 }
616 return;
617}
618
619
620static inline int pcmcia_devmatch(struct pcmcia_device *dev,
621 struct pcmcia_device_id *did)
622{
623 if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) {
624 if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id))
625 return 0;
626 }
627
628 if (did->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID) {
629 if ((!dev->has_card_id) || (dev->card_id != did->card_id))
630 return 0;
631 }
632
633 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION) {
634 if (dev->func != did->function)
635 return 0;
636 }
637
638 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1) {
639 if (!dev->prod_id[0])
640 return 0;
641 if (strcmp(did->prod_id[0], dev->prod_id[0]))
642 return 0;
643 }
644
645 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2) {
646 if (!dev->prod_id[1])
647 return 0;
648 if (strcmp(did->prod_id[1], dev->prod_id[1]))
649 return 0;
650 }
651
652 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3) {
653 if (!dev->prod_id[2])
654 return 0;
655 if (strcmp(did->prod_id[2], dev->prod_id[2]))
656 return 0;
657 }
658
659 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4) {
660 if (!dev->prod_id[3])
661 return 0;
662 if (strcmp(did->prod_id[3], dev->prod_id[3]))
663 return 0;
664 }
665
666 if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
667 /* handle pseudo multifunction devices:
668 * there are at most two pseudo multifunction devices.
669 * if we're matching against the first, schedule a
670 * call which will then check whether there are two
671 * pseudo devices, and if not, add the second one.
672 */
673 if (dev->device_no == 0)
674 pcmcia_add_pseudo_device(dev->socket->pcmcia);
675
676 if (dev->device_no != did->device_no)
677 return 0;
678 }
679
680 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {
681 if ((!dev->has_func_id) || (dev->func_id != did->func_id))
682 return 0;
683
684 /* if this is a pseudo-multi-function device,
685 * we need explicit matches */
686 if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO)
687 return 0;
688 if (dev->device_no)
689 return 0;
690
691 /* also, FUNC_ID matching needs to be activated by userspace
692 * after it has re-checked that there is no possible module
693 * with a prod_id/manf_id/card_id match.
694 */
695 if (!dev->allow_func_id_match)
696 return 0;
697 }
698
699 dev->dev.driver_data = (void *) did;
700
701 return 1;
702}
703
704
594static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { 705static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
595 struct pcmcia_device * p_dev = to_pcmcia_dev(dev); 706 struct pcmcia_device * p_dev = to_pcmcia_dev(dev);
596 struct pcmcia_driver * p_drv = to_pcmcia_drv(drv); 707 struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
708 struct pcmcia_device_id *did = p_drv->id_table;
597 709
598 /* matching by cardmgr */ 710 /* matching by cardmgr */
599 if (p_dev->cardmgr == p_drv) 711 if (p_dev->cardmgr == p_drv)
600 return 1; 712 return 1;
601 713
714 while (did && did->match_flags) {
715 if (pcmcia_devmatch(p_dev, did))
716 return 1;
717 did++;
718 }
719
602 return 0; 720 return 0;
603} 721}
604 722
@@ -922,7 +1040,9 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
922rescan: 1040rescan:
923 p_dev->cardmgr = p_drv; 1041 p_dev->cardmgr = p_drv;
924 1042
925 pcmcia_device_query(p_dev); 1043 /* if a driver is already running, we can abort */
1044 if (p_dev->dev.driver)
1045 goto err_put_module;
926 1046
927 /* 1047 /*
928 * Prevent this racing with a card insertion. 1048 * Prevent this racing with a card insertion.
@@ -1595,6 +1715,7 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev)
1595 1715
1596 init_waitqueue_head(&s->queue); 1716 init_waitqueue_head(&s->queue);
1597 INIT_LIST_HEAD(&s->devices_list); 1717 INIT_LIST_HEAD(&s->devices_list);
1718 INIT_WORK(&s->device_add, pcmcia_delayed_add_pseudo_device, s);
1598 1719
1599 /* Set up hotline to Card Services */ 1720 /* Set up hotline to Card Services */
1600 s->callback.owner = THIS_MODULE; 1721 s->callback.owner = THIS_MODULE;