diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2008-06-19 19:02:52 +0200 |
---|---|---|
committer | Dominik Brodowski <linux@dominikbrodowski.net> | 2008-06-24 15:33:42 +0200 |
commit | c502380170ee93fd1f4028cc1f32efc87fde7376 (patch) | |
tree | 3743249953d40aa0f08cc9ae4f7774c8907b3326 /drivers/pcmcia/pcmcia_ioctl.c | |
parent | 635416ef393e8cec5a89fc6c1de710ee9596a51e (diff) |
pcmcia: carve out ioctl adjust function to pcmcia_ioctl
Let pcmcia_ioctl interact with rsrc_nonstatic using functions which
rsrc_nonstatic.c has to use anyway.
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers/pcmcia/pcmcia_ioctl.c')
-rw-r--r-- | drivers/pcmcia/pcmcia_ioctl.c | 90 |
1 files changed, 88 insertions, 2 deletions
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 5f186abca10..758ece8dc36 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -138,6 +138,94 @@ static int proc_read_drivers(char *buf, char **start, off_t pos, } #endif + +#ifdef CONFIG_PCMCIA_PROBE + +static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) +{ + int irq; + u32 mask; + + irq = adj->resource.irq.IRQ; + if ((irq < 0) || (irq > 15)) + return CS_BAD_IRQ; + + if (adj->Action != REMOVE_MANAGED_RESOURCE) + return 0; + + mask = 1 << irq; + + if (!(s->irq_mask & mask)) + return 0; + + s->irq_mask &= ~mask; + + return 0; +} + +#else + +static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) { + return CS_SUCCESS; +} + +#endif + +static int pcmcia_adjust_resource_info(adjust_t *adj) +{ + struct pcmcia_socket *s; + int ret = CS_UNSUPPORTED_FUNCTION; + unsigned long flags; + + down_read(&pcmcia_socket_list_rwsem); + list_for_each_entry(s, &pcmcia_socket_list, socket_list) { + + if (adj->Resource == RES_IRQ) + ret = adjust_irq(s, adj); + + else if (s->resource_ops->add_io) { + unsigned long begin, end; + + /* you can't use the old interface if the new + * one was used before */ + spin_lock_irqsave(&s->lock, flags); + if ((s->resource_setup_new) && + !(s->resource_setup_old)) { + spin_unlock_irqrestore(&s->lock, flags); + continue; + } else if (!(s->resource_setup_old)) + s->resource_setup_old = 1; + spin_unlock_irqrestore(&s->lock, flags); + + switch (adj->Resource) { + case RES_MEMORY_RANGE: + begin = adj->resource.memory.Base; + end = adj->resource.memory.Base + adj->resource.memory.Size - 1; + if (s->resource_ops->add_mem) + ret =s->resource_ops->add_mem(s, adj->Action, begin, end); + case RES_IO_RANGE: + begin = adj->resource.io.BasePort; + end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1; + if (s->resource_ops->add_io) + ret = s->resource_ops->add_io(s, adj->Action, begin, end); + } + if (!ret) { + /* as there's no way we know this is the + * last call to adjust_resource_info, we + * always need to assume this is the latest + * one... */ + spin_lock_irqsave(&s->lock, flags); + s->resource_setup_done = 1; + spin_unlock_irqrestore(&s->lock, flags); + } + } + } + up_read(&pcmcia_socket_list_rwsem); + + return (ret); +} + + /*====================================================================== These manage a ring buffer of events pending for one user process @@ -546,8 +634,6 @@ static u_int ds_poll(struct file *file, poll_table *wait) /*====================================================================*/ -extern int pcmcia_adjust_resource_info(adjust_t *adj); - static int ds_ioctl(struct inode * inode, struct file * file, u_int cmd, u_long arg) { |