-struct resource *find_mem_region(u_long base, u_long num, u_long align,
- int low, char *name, struct pcmcia_socket *s)
-{
- struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id);
- struct pcmcia_align_data data;
- unsigned long min, max;
- int ret, i;
-
- low = low || !(s->features & SS_CAP_PAGE_REGS);
-
- data.mask = align - 1;
- data.offset = base & data.mask;
- data.map = &mem_db;
-
- for (i = 0; i < 2; i++) {
- if (low) {
- max = 0x100000UL;
- min = base < max ? base : 0;
- } else {
- max = ~0UL;
- min = 0x100000UL + base;
- }
-
- down(&rsrc_sem);
-#ifdef CONFIG_PCI
- if (s->cb_dev) {
- ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num,
- 1, min, 0,
- pcmcia_align, &data);
- } else
-#endif
- ret = allocate_resource(&iomem_resource, res, num, min,
- max, 1, pcmcia_align, &data);
- up(&rsrc_sem);
- if (ret == 0 || low)
- break;
- low = 1;
- }
-
- if (ret != 0) {
- kfree(res);
- res = NULL;
- }
- return res;
-}
-
-/*======================================================================
-
- This checks to see if an interrupt is available, with support
- for interrupt sharing. We don't support reserving interrupts
- yet. If the interrupt is available, we allocate it.
-
-======================================================================*/
-
-#ifdef CONFIG_PCMCIA_PROBE
-
-static irqreturn_t fake_irq(int i, void *d, struct pt_regs *r) { return IRQ_NONE; }
-static inline int check_irq(int irq)
-{
- if (request_irq(irq, fake_irq, 0, "bogus", NULL) != 0)
- return -1;
- free_irq(irq, NULL);
- return 0;
-}
-
-int try_irq(u_int Attributes, int irq, int specific)
-{
- irq_info_t *info = &irq_table[irq];
- int ret = 0;
-
- down(&rsrc_sem);
- if (info->Attributes & RES_ALLOCATED) {
- switch (Attributes & IRQ_TYPE) {
- case IRQ_TYPE_EXCLUSIVE:
- ret = CS_IN_USE;
- break;
- case IRQ_TYPE_TIME:
- if ((info->Attributes & RES_IRQ_TYPE)
- != RES_IRQ_TYPE_TIME) {
- ret = CS_IN_USE;
- break;
- }
- if (Attributes & IRQ_FIRST_SHARED) {
- ret = CS_BAD_ATTRIBUTE;
- break;
- }
- info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
- info->time_share++;
- break;
- case IRQ_TYPE_DYNAMIC_SHARING:
- if ((info->Attributes & RES_IRQ_TYPE)
- != RES_IRQ_TYPE_DYNAMIC) {
- ret = CS_IN_USE;
- break;
- }
- if (Attributes & IRQ_FIRST_SHARED) {
- ret = CS_BAD_ATTRIBUTE;
- break;
- }
- info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
- info->dyn_share++;
- break;
- }
- } else {
- if ((info->Attributes & RES_RESERVED) && !specific) {
- ret = CS_IN_USE;
- goto out;
- }
- if (check_irq(irq) != 0) {
- ret = CS_IN_USE;
- goto out;
- }
- switch (Attributes & IRQ_TYPE) {
- case IRQ_TYPE_EXCLUSIVE:
- info->Attributes |= RES_ALLOCATED;
- break;
- case IRQ_TYPE_TIME:
- if (!(Attributes & IRQ_FIRST_SHARED)) {
- ret = CS_BAD_ATTRIBUTE;
- break;
- }
- info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
- info->time_share = 1;
- break;
- case IRQ_TYPE_DYNAMIC_SHARING:
- if (!(Attributes & IRQ_FIRST_SHARED)) {
- ret = CS_BAD_ATTRIBUTE;
- break;
- }
- info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
- info->dyn_share = 1;
- break;
- }
- }
- out:
- up(&rsrc_sem);
- return ret;
-}
-
-#endif
-
-/*====================================================================*/
-
-#ifdef CONFIG_PCMCIA_PROBE
-
-void undo_irq(u_int Attributes, int irq)
-{
- irq_info_t *info;
-
- info = &irq_table[irq];
- down(&rsrc_sem);
- switch (Attributes & IRQ_TYPE) {
- case IRQ_TYPE_EXCLUSIVE:
- info->Attributes &= RES_RESERVED;
- break;
- case IRQ_TYPE_TIME:
- info->time_share--;
- if (info->time_share == 0)
- info->Attributes &= RES_RESERVED;
- break;
- case IRQ_TYPE_DYNAMIC_SHARING:
- info->dyn_share--;
- if (info->dyn_share == 0)
- info->Attributes &= RES_RESERVED;
- break;
- }
- up(&rsrc_sem);
-}
-
-#endif
-
-/*======================================================================
-
- The various adjust_* calls form the external interface to the
- resource database.
-
-======================================================================*/
-
-static int adjust_memory(adjust_t *adj)
-{
- u_long base, num;
- int ret;
-
- base = adj->resource.memory.Base;
- num = adj->resource.memory.Size;
- if ((num == 0) || (base+num-1 < base))
- return CS_BAD_SIZE;
-
- ret = CS_SUCCESS;
-
- down(&rsrc_sem);
- switch (adj->Action) {
- case ADD_MANAGED_RESOURCE:
- ret = add_interval(&mem_db, base, num);
- break;
- case REMOVE_MANAGED_RESOURCE:
- ret = sub_interval(&mem_db, base, num);
- if (ret == CS_SUCCESS) {
- struct pcmcia_socket *socket;
- down_read(&pcmcia_socket_list_rwsem);
- list_for_each_entry(socket, &pcmcia_socket_list, socket_list)
- release_cis_mem(socket);
- up_read(&pcmcia_socket_list_rwsem);
- }
- break;
- default:
- ret = CS_UNSUPPORTED_FUNCTION;
- }
- up(&rsrc_sem);
-
- return ret;
-}
-
-/*====================================================================*/
-
-static int adjust_io(adjust_t *adj)
-{
- int base, num, ret = CS_SUCCESS;
-
- base = adj->resource.io.BasePort;
- num = adj->resource.io.NumPorts;
- if ((base < 0) || (base > 0xffff))
- return CS_BAD_BASE;
- if ((num <= 0) || (base+num > 0x10000) || (base+num <= base))
- return CS_BAD_SIZE;
-
- down(&rsrc_sem);
- switch (adj->Action) {
- case ADD_MANAGED_RESOURCE:
- if (add_interval(&io_db, base, num) != 0) {
- ret = CS_IN_USE;
- break;
- }
-#ifdef CONFIG_PCMCIA_PROBE
- if (probe_io)
- do_io_probe(base, num);
-#endif
- break;
- case REMOVE_MANAGED_RESOURCE:
- sub_interval(&io_db, base, num);
- break;
- default:
- ret = CS_UNSUPPORTED_FUNCTION;
- break;
- }
- up(&rsrc_sem);
-
- return ret;
-}
-
-/*====================================================================*/
-
-static int adjust_irq(adjust_t *adj)
-{
- int ret = CS_SUCCESS;
-#ifdef CONFIG_PCMCIA_PROBE
- int irq;
- irq_info_t *info;
-
- irq = adj->resource.irq.IRQ;
- if ((irq < 0) || (irq > 15))
- return CS_BAD_IRQ;
- info = &irq_table[irq];
-
- down(&rsrc_sem);
- switch (adj->Action) {
- case ADD_MANAGED_RESOURCE:
- if (info->Attributes & RES_REMOVED)
- info->Attributes &= ~(RES_REMOVED|RES_ALLOCATED);
- else
- if (adj->Attributes & RES_ALLOCATED) {
- ret = CS_IN_USE;
- break;
- }
- if (adj->Attributes & RES_RESERVED)
- info->Attributes |= RES_RESERVED;
- else
- info->Attributes &= ~RES_RESERVED;
- break;
- case REMOVE_MANAGED_RESOURCE:
- if (info->Attributes & RES_REMOVED) {
- ret = 0;
- break;
- }
- if (info->Attributes & RES_ALLOCATED) {
- ret = CS_IN_USE;
- break;
- }
- info->Attributes |= RES_ALLOCATED|RES_REMOVED;
- info->Attributes &= ~RES_RESERVED;
- break;
- default:
- ret = CS_UNSUPPORTED_FUNCTION;
- break;
- }
- up(&rsrc_sem);
-#endif
- return ret;
-}
-
-/*====================================================================*/
-
-int pcmcia_adjust_resource_info(client_handle_t handle, adjust_t *adj)
-{
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
-
- switch (adj->Resource) {
- case RES_MEMORY_RANGE:
- return adjust_memory(adj);
- break;
- case RES_IO_RANGE:
- return adjust_io(adj);
- break;
- case RES_IRQ:
- return adjust_irq(adj);
- break;
- }
- return CS_UNSUPPORTED_FUNCTION;
-}
-
-/*====================================================================*/