/*
* pcmcia_ioctl.c -- ioctl interface for cardmgr and cardctl
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* The initial developer of the original code is David A. Hinds
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
*
* (C) 1999 David A. Hinds
* (C) 2003 - 2004 Dominik Brodowski
*/
/*
* This file will go away soon.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/proc_fs.h>
#include <linux/poll.h>
#include <linux/pci.h>
#include <linux/seq_file.h>
#include <linux/smp_lock.h>
#include <linux/workqueue.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>
#include <pcmcia/ss.h>
#include "cs_internal.h"
static int major_dev = -1;
/* Device user information */
#define MAX_EVENTS 32
#define USER_MAGIC 0x7ea4
#define CHECK_USER(u) \
(((u) == NULL) || ((u)->user_magic != USER_MAGIC))
typedef struct user_info_t {
u_int user_magic;
int event_head, event_tail;
event_t event[MAX_EVENTS];
struct user_info_t *next;
struct pcmcia_socket *socket;
} user_info_t;
static struct pcmcia_device *get_pcmcia_device(struct pcmcia_socket *s,
unsigned int function)
{
struct pcmcia_device *p_dev = NULL;
unsigned long flags;
spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
if (p_dev->func == function) {
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
return pcmcia_get_dev(p_dev);
}
}
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
return NULL;
}
/* backwards-compatible accessing of driver --- by name! */
static struct pcmcia_driver *get_pcmcia_driver(dev_info_t *dev_info)
{
struct device_driver *drv;
struct pcmcia_driver *p_drv;
drv = driver_find((char *) dev_info, &pcmcia_bus_type);
if (!drv)
return NULL;
p_drv = container_of(drv, struct pcmcia_driver, drv);
return (p_drv);
}
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_pccard = NULL;
static int proc_read_drivers_callback(struct device_driver *driver, void *_m)
{
struct seq_file *m = _m;
struct pcmcia_driver *p_drv = container_of(driver,
struct pcmcia_driver, drv);
seq_printf(m, "%-24.24s 1 %d\n", p_drv->drv.name,
#ifdef CONFIG_MODULE_UNLOAD
(p_drv->owner) ? module_refcount(p_drv->owner) : 1
#else
1
#endif
);
return 0;
}
static int pccard_drivers_proc_show(struct seq_file *m, void *v)
{
return bus_for_each_drv(&pcmcia_bus_type, NULL,
m, proc_read_drivers_callback);
}
static int pccard_drivers_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, pccard_drivers_proc_show, NULL);
}
static const struct file_operations pccard_drivers_proc_fops = {
.owner = THIS_MODULE,
.open = pccard_drivers_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
#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 -EINVAL;
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 0;
}
#endif
static int pcmcia_adjust_resource_info(adjust_t *adj)
{
struct pcmcia_socket *s;
int ret = -ENOSYS;
unsigned long flags;
down_read(&pcmcia_socket_list_rwsem