aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia/rsrc_nonstatic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pcmcia/rsrc_nonstatic.c')
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c170
1 files changed, 114 insertions, 56 deletions
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 5876bab7c14c..c42455d20eb6 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -372,6 +372,9 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
372 base, base+num-1); 372 base, base+num-1);
373 bad = fail = 0; 373 bad = fail = 0;
374 step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); 374 step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
375 /* don't allow too large steps */
376 if (step > 0x800000)
377 step = 0x800000;
375 /* cis_readable wants to map 2x map_size */ 378 /* cis_readable wants to map 2x map_size */
376 if (step < 2 * s->map_size) 379 if (step < 2 * s->map_size)
377 step = 2 * s->map_size; 380 step = 2 * s->map_size;
@@ -465,8 +468,7 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
465 468
466 for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { 469 for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
467 mm = *m; 470 mm = *m;
468 if (do_mem_probe(mm.base, mm.num, s)) 471 do_mem_probe(mm.base, mm.num, s);
469 break;
470 } 472 }
471} 473}
472 474
@@ -601,7 +603,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
601 603
602======================================================================*/ 604======================================================================*/
603 605
604struct resource *nonstatic_find_io_region(unsigned long base, int num, 606static struct resource *nonstatic_find_io_region(unsigned long base, int num,
605 unsigned long align, struct pcmcia_socket *s) 607 unsigned long align, struct pcmcia_socket *s)
606{ 608{
607 struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id); 609 struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id);
@@ -635,8 +637,8 @@ struct resource *nonstatic_find_io_region(unsigned long base, int num,
635 return res; 637 return res;
636} 638}
637 639
638struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long align, 640static struct resource * nonstatic_find_mem_region(u_long base, u_long num,
639 int low, struct pcmcia_socket *s) 641 u_long align, int low, struct pcmcia_socket *s)
640{ 642{
641 struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id); 643 struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id);
642 struct socket_data *s_data = s->resource_data; 644 struct socket_data *s_data = s->resource_data;
@@ -683,27 +685,23 @@ struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long alig
683} 685}
684 686
685 687
686static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj) 688static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
687{ 689{
688 u_long base, num;
689 struct socket_data *data = s->resource_data; 690 struct socket_data *data = s->resource_data;
690 int ret; 691 unsigned long size = end - start + 1;
691 692 int ret = 0;
692 base = adj->resource.memory.Base;
693 num = adj->resource.memory.Size;
694 if ((num == 0) || (base+num-1 < base))
695 return CS_BAD_SIZE;
696 693
697 ret = CS_SUCCESS; 694 if (end <= start)
695 return -EINVAL;
698 696
699 down(&rsrc_sem); 697 down(&rsrc_sem);
700 switch (adj->Action) { 698 switch (action) {
701 case ADD_MANAGED_RESOURCE: 699 case ADD_MANAGED_RESOURCE:
702 ret = add_interval(&data->mem_db, base, num); 700 ret = add_interval(&data->mem_db, start, size);
703 break; 701 break;
704 case REMOVE_MANAGED_RESOURCE: 702 case REMOVE_MANAGED_RESOURCE:
705 ret = sub_interval(&data->mem_db, base, num); 703 ret = sub_interval(&data->mem_db, start, size);
706 if (ret == CS_SUCCESS) { 704 if (!ret) {
707 struct pcmcia_socket *socket; 705 struct pcmcia_socket *socket;
708 down_read(&pcmcia_socket_list_rwsem); 706 down_read(&pcmcia_socket_list_rwsem);
709 list_for_each_entry(socket, &pcmcia_socket_list, socket_list) 707 list_for_each_entry(socket, &pcmcia_socket_list, socket_list)
@@ -712,7 +710,7 @@ static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj)
712 } 710 }
713 break; 711 break;
714 default: 712 default:
715 ret = CS_UNSUPPORTED_FUNCTION; 713 ret = -EINVAL;
716 } 714 }
717 up(&rsrc_sem); 715 up(&rsrc_sem);
718 716
@@ -720,36 +718,35 @@ static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj)
720} 718}
721 719
722 720
723static int adjust_io(struct pcmcia_socket *s, adjust_t *adj) 721static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
724{ 722{
725 struct socket_data *data = s->resource_data; 723 struct socket_data *data = s->resource_data;
726 kio_addr_t base, num; 724 unsigned long size = end - start + 1;
727 int ret = CS_SUCCESS; 725 int ret = 0;
728 726
729 base = adj->resource.io.BasePort; 727 if (end <= start)
730 num = adj->resource.io.NumPorts; 728 return -EINVAL;
731 if ((base < 0) || (base > 0xffff)) 729
732 return CS_BAD_BASE; 730 if (end > IO_SPACE_LIMIT)
733 if ((num <= 0) || (base+num > 0x10000) || (base+num <= base)) 731 return -EINVAL;
734 return CS_BAD_SIZE;
735 732
736 down(&rsrc_sem); 733 down(&rsrc_sem);
737 switch (adj->Action) { 734 switch (action) {
738 case ADD_MANAGED_RESOURCE: 735 case ADD_MANAGED_RESOURCE:
739 if (add_interval(&data->io_db, base, num) != 0) { 736 if (add_interval(&data->io_db, start, size) != 0) {
740 ret = CS_IN_USE; 737 ret = -EBUSY;
741 break; 738 break;
742 } 739 }
743#ifdef CONFIG_PCMCIA_PROBE 740#ifdef CONFIG_PCMCIA_PROBE
744 if (probe_io) 741 if (probe_io)
745 do_io_probe(s, base, num); 742 do_io_probe(s, start, size);
746#endif 743#endif
747 break; 744 break;
748 case REMOVE_MANAGED_RESOURCE: 745 case REMOVE_MANAGED_RESOURCE:
749 sub_interval(&data->io_db, base, num); 746 sub_interval(&data->io_db, start, size);
750 break; 747 break;
751 default: 748 default:
752 ret = CS_UNSUPPORTED_FUNCTION; 749 ret = -EINVAL;
753 break; 750 break;
754 } 751 }
755 up(&rsrc_sem); 752 up(&rsrc_sem);
@@ -760,15 +757,82 @@ static int adjust_io(struct pcmcia_socket *s, adjust_t *adj)
760 757
761static int nonstatic_adjust_resource_info(struct pcmcia_socket *s, adjust_t *adj) 758static int nonstatic_adjust_resource_info(struct pcmcia_socket *s, adjust_t *adj)
762{ 759{
760 unsigned long end;
761
763 switch (adj->Resource) { 762 switch (adj->Resource) {
764 case RES_MEMORY_RANGE: 763 case RES_MEMORY_RANGE:
765 return adjust_memory(s, adj); 764 end = adj->resource.memory.Base + adj->resource.memory.Size - 1;
765 return adjust_memory(s, adj->Action, adj->resource.memory.Base, end);
766 case RES_IO_RANGE: 766 case RES_IO_RANGE:
767 return adjust_io(s, adj); 767 end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1;
768 return adjust_io(s, adj->Action, adj->resource.io.BasePort, end);
768 } 769 }
769 return CS_UNSUPPORTED_FUNCTION; 770 return CS_UNSUPPORTED_FUNCTION;
770} 771}
771 772
773#ifdef CONFIG_PCI
774static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
775{
776 struct resource *res;
777 int i, done = 0;
778
779 if (!s->cb_dev || !s->cb_dev->bus)
780 return -ENODEV;
781
782#if defined(CONFIG_X86) || defined(CONFIG_X86_64)
783 /* If this is the root bus, the risk of hitting
784 * some strange system devices which aren't protected
785 * by either ACPI resource tables or properly requested
786 * resources is too big. Therefore, don't do auto-adding
787 * of resources at the moment.
788 */
789 if (s->cb_dev->bus->number == 0)
790 return -EINVAL;
791#endif
792
793 for (i=0; i < PCI_BUS_NUM_RESOURCES; i++) {
794 res = s->cb_dev->bus->resource[i];
795 if (!res)
796 continue;
797
798 if (res->flags & IORESOURCE_IO) {
799 if (res == &ioport_resource)
800 continue;
801 printk(KERN_INFO "pcmcia: parent PCI bridge I/O window: 0x%lx - 0x%lx\n",
802 res->start, res->end);
803 if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
804 done |= IORESOURCE_IO;
805
806 }
807
808 if (res->flags & IORESOURCE_MEM) {
809 if (res == &iomem_resource)
810 continue;
811 printk(KERN_INFO "pcmcia: parent PCI bridge Memory window: 0x%lx - 0x%lx\n",
812 res->start, res->end);
813 if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
814 done |= IORESOURCE_MEM;
815 }
816 }
817
818 /* if we got at least one of IO, and one of MEM, we can be glad and
819 * activate the PCMCIA subsystem */
820 if (done & (IORESOURCE_MEM | IORESOURCE_IO))
821 s->resource_setup_done = 1;
822
823 return 0;
824}
825
826#else
827
828static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s)
829{
830 return -ENODEV;
831}
832
833#endif
834
835
772static int nonstatic_init(struct pcmcia_socket *s) 836static int nonstatic_init(struct pcmcia_socket *s)
773{ 837{
774 struct socket_data *data; 838 struct socket_data *data;
@@ -783,6 +847,8 @@ static int nonstatic_init(struct pcmcia_socket *s)
783 847
784 s->resource_data = (void *) data; 848 s->resource_data = (void *) data;
785 849
850 nonstatic_autoadd_resources(s);
851
786 return 0; 852 return 0;
787} 853}
788 854
@@ -845,17 +911,16 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size
845{ 911{
846 struct pcmcia_socket *s = class_get_devdata(class_dev); 912 struct pcmcia_socket *s = class_get_devdata(class_dev);
847 unsigned long start_addr, end_addr; 913 unsigned long start_addr, end_addr;
848 unsigned int add = 1; 914 unsigned int add = ADD_MANAGED_RESOURCE;
849 adjust_t adj;
850 ssize_t ret = 0; 915 ssize_t ret = 0;
851 916
852 ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr); 917 ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
853 if (ret != 2) { 918 if (ret != 2) {
854 ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr); 919 ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
855 add = 0; 920 add = REMOVE_MANAGED_RESOURCE;
856 if (ret != 2) { 921 if (ret != 2) {
857 ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr); 922 ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
858 add = 1; 923 add = ADD_MANAGED_RESOURCE;
859 if (ret != 2) 924 if (ret != 2)
860 return -EINVAL; 925 return -EINVAL;
861 } 926 }
@@ -863,12 +928,9 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size
863 if (end_addr <= start_addr) 928 if (end_addr <= start_addr)
864 return -EINVAL; 929 return -EINVAL;
865 930
866 adj.Action = add ? ADD_MANAGED_RESOURCE : REMOVE_MANAGED_RESOURCE; 931 ret = adjust_io(s, add, start_addr, end_addr);
867 adj.Resource = RES_IO_RANGE; 932 if (!ret)
868 adj.resource.io.BasePort = start_addr; 933 s->resource_setup_new = 1;
869 adj.resource.io.NumPorts = end_addr - start_addr + 1;
870
871 ret = adjust_io(s, &adj);
872 934
873 return ret ? ret : count; 935 return ret ? ret : count;
874} 936}
@@ -901,17 +963,16 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz
901{ 963{
902 struct pcmcia_socket *s = class_get_devdata(class_dev); 964 struct pcmcia_socket *s = class_get_devdata(class_dev);
903 unsigned long start_addr, end_addr; 965 unsigned long start_addr, end_addr;
904 unsigned int add = 1; 966 unsigned int add = ADD_MANAGED_RESOURCE;
905 adjust_t adj;
906 ssize_t ret = 0; 967 ssize_t ret = 0;
907 968
908 ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr); 969 ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
909 if (ret != 2) { 970 if (ret != 2) {
910 ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr); 971 ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
911 add = 0; 972 add = REMOVE_MANAGED_RESOURCE;
912 if (ret != 2) { 973 if (ret != 2) {
913 ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr); 974 ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
914 add = 1; 975 add = ADD_MANAGED_RESOURCE;
915 if (ret != 2) 976 if (ret != 2)
916 return -EINVAL; 977 return -EINVAL;
917 } 978 }
@@ -919,12 +980,9 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz
919 if (end_addr <= start_addr) 980 if (end_addr <= start_addr)
920 return -EINVAL; 981 return -EINVAL;
921 982
922 adj.Action = add ? ADD_MANAGED_RESOURCE : REMOVE_MANAGED_RESOURCE; 983 ret = adjust_memory(s, add, start_addr, end_addr);
923 adj.Resource = RES_MEMORY_RANGE; 984 if (!ret)
924 adj.resource.memory.Base = start_addr; 985 s->resource_setup_new = 1;
925 adj.resource.memory.Size = end_addr - start_addr + 1;
926
927 ret = adjust_memory(s, &adj);
928 986
929 return ret ? ret : count; 987 return ret ? ret : count;
930} 988}