char: pcmcia: remove all the drivers

These char PCMCIA drivers are buggy[1] and receive only minimal care. It
was concluded[2], that we should try to remove most pcmcia drivers
completely. Let's start with these char broken one.

Note that I also removed a UAPI header: include/uapi/linux/cm4000_cs.h.
I found only coccinelle tests mentioning some ioctl constants from that
file. But they are not actually used. Anyway, should someone complain,
we may reintroduce the header (or its parts).

[1] https://lore.kernel.org/all/f41c2765-80e0-48bc-b1e4-8cfd3230fd4a@www.fastmail.com/
[2] https://lore.kernel.org/all/c5b39544-a4fb-4796-a046-0b9be9853787@app.fastmail.com/

Signed-off-by: Jiri Slaby (SUSE) <jirislaby@kernel.org>
Cc: "Hyunwoo Kim" <imv4bel@gmail.com>
Cc: Harald Welte <laforge@gnumonks.org>
Cc: Lubomir Rintel <lkundrak@v3.sk>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Dominik Brodowski <linux@dominikbrodowski.net>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Link: https://lore.kernel.org/r/20230222092302.6348-2-jirislaby@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Jiri Slaby 2023-02-22 10:23:02 +01:00 committed by Greg Kroah-Hartman
parent 3996954fa0
commit 9b12f050c7
19 changed files with 0 additions and 7466 deletions

View File

@ -72,7 +72,6 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c``
BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``

View File

@ -78,7 +78,6 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c``
BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``

View File

@ -77,7 +77,6 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c``
BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``

View File

@ -61,7 +61,6 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c``
BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``

View File

@ -64,7 +64,6 @@ PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/
APM_BIOS_MAGIC 0x4101 apm_user ``arch/x86/kernel/apm_32.c``
FASYNC_MAGIC 0x4601 fasync_struct ``include/linux/fs.h``
SLIP_MAGIC 0x5302 slip ``drivers/net/slip.h``
MGSLPC_MAGIC 0x5402 mgslpc_info ``drivers/char/pcmcia/synclink_cs.c``
BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c``
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state ``include/linux/hdlcdrv.h``
KV_MAGIC 0x5f4b565f kernel_vars_s ``arch/mips/include/asm/sn/klkernvars.h``

View File

@ -222,7 +222,6 @@ Code Seq# Include File Comments
'b' 00-FF conflict! bit3 vme host bridge
<mailto:natalia@nikhefk.nikhef.nl>
'b' 00-0F linux/dma-buf.h conflict!
'c' all linux/cm4000_cs.h conflict!
'c' 00-7F linux/comstats.h conflict!
'c' 00-7F linux/coda.h conflict!
'c' 00-1F linux/chio.h conflict!

View File

@ -15322,18 +15322,6 @@ S: Maintained
F: Documentation/filesystems/omfs.rst
F: fs/omfs/
OMNIKEY CARDMAN 4000 DRIVER
M: Harald Welte <laforge@gnumonks.org>
S: Maintained
F: drivers/char/pcmcia/cm4000_cs.c
F: include/linux/cm4000_cs.h
F: include/uapi/linux/cm4000_cs.h
OMNIKEY CARDMAN 4040 DRIVER
M: Harald Welte <laforge@gnumonks.org>
S: Maintained
F: drivers/char/pcmcia/cm4040_cs.*
OMNIVISION OG01A1B SENSOR DRIVER
M: Shawn Tu <shawnx.tu@intel.com>
L: linux-media@vger.kernel.org
@ -18609,11 +18597,6 @@ F: include/linux/wait.h
F: include/uapi/linux/sched.h
F: kernel/sched/
SCR24X CHIP CARD INTERFACE DRIVER
M: Lubomir Rintel <lkundrak@v3.sk>
S: Supported
F: drivers/char/pcmcia/scr24x_cs.c
SCSI RDMA PROTOCOL (SRP) INITIATOR
M: Bart Van Assche <bvanassche@acm.org>
L: linux-rdma@vger.kernel.org

View File

@ -614,8 +614,6 @@ CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_VIRTIO=m
CONFIG_NVRAM=y
CONFIG_DTLK=m
CONFIG_CARDMAN_4000=m
CONFIG_CARDMAN_4040=m
CONFIG_IPWIRELESS=m
CONFIG_I2C_CHARDEV=m
CONFIG_I2C_HYDRA=m

View File

@ -247,8 +247,6 @@ config SONYPI
To compile this driver as a module, choose M here: the
module will be called sonypi.
source "drivers/char/pcmcia/Kconfig"
config MWAVE
tristate "ACP Modem (Mwave) support"
depends on X86 && TTY

View File

@ -35,7 +35,6 @@ obj-$(CONFIG_TELCLOCK) += tlclk.o
obj-$(CONFIG_MWAVE) += mwave/
obj-y += agp/
obj-$(CONFIG_PCMCIA) += pcmcia/
obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
obj-$(CONFIG_TCG_TPM) += tpm/

View File

@ -1,59 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# PCMCIA character device configuration
#
menu "PCMCIA character devices"
depends on PCMCIA!=n
config SYNCLINK_CS
tristate "SyncLink PC Card support"
depends on PCMCIA && TTY
help
Enable support for the SyncLink PC Card serial adapter, running
asynchronous and HDLC communications up to 512Kbps. The port is
selectable for RS-232, V.35, RS-449, RS-530, and X.21
This driver may be built as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called synclink_cs. If you want to do that, say M
here.
config CARDMAN_4000
tristate "Omnikey Cardman 4000 support"
depends on PCMCIA
select BITREVERSE
help
Enable support for the Omnikey Cardman 4000 PCMCIA Smartcard
reader.
This kernel driver requires additional userspace support, either
by the vendor-provided PC/SC ifd_handler (http://www.omnikey.com/),
or via the cm4000 backend of OpenCT (http://www.opensc-project.org/opensc).
config CARDMAN_4040
tristate "Omnikey CardMan 4040 support"
depends on PCMCIA
help
Enable support for the Omnikey CardMan 4040 PCMCIA Smartcard
reader.
This card is basically a USB CCID device connected to a FIFO
in I/O space. To use the kernel driver, you will need either the
PC/SC ifdhandler provided from the Omnikey homepage
(http://www.omnikey.com/), or a current development version of OpenCT
(http://www.opensc-project.org/opensc).
config SCR24X
tristate "SCR24x Chip Card Interface support"
depends on PCMCIA
help
Enable support for the SCR24x PCMCIA Chip Card Interface.
To compile this driver as a module, choose M here.
The module will be called scr24x_cs..
If unsure say N.
endmenu

View File

@ -1,11 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# drivers/char/pcmcia/Makefile
#
# Makefile for the Linux PCMCIA char device drivers.
#
obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o
obj-$(CONFIG_CARDMAN_4000) += cm4000_cs.o
obj-$(CONFIG_CARDMAN_4040) += cm4040_cs.o
obj-$(CONFIG_SCR24X) += scr24x_cs.o

File diff suppressed because it is too large Load Diff

View File

@ -1,684 +0,0 @@
/*
* A driver for the Omnikey PCMCIA smartcard reader CardMan 4040
*
* (c) 2000-2004 Omnikey AG (http://www.omnikey.com/)
*
* (C) 2005-2006 Harald Welte <laforge@gnumonks.org>
* - add support for poll()
* - driver cleanup
* - add waitqueues
* - adhere to linux kernel coding style and policies
* - support 2.6.13 "new style" pcmcia interface
* - add class interface for udev device creation
*
* The device basically is a USB CCID compliant device that has been
* attached to an I/O-Mapped FIFO.
*
* All rights reserved, Dual BSD/GPL Licensed.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/ds.h>
#include "cm4040_cs.h"
#define reader_to_dev(x) (&x->p_dev->dev)
/* n (debug level) is ignored */
/* additional debug output may be enabled by re-compiling with
* CM4040_DEBUG set */
/* #define CM4040_DEBUG */
#define DEBUGP(n, rdr, x, args...) do { \
dev_dbg(reader_to_dev(rdr), "%s:" x, \
__func__ , ## args); \
} while (0)
static DEFINE_MUTEX(cm4040_mutex);
#define CCID_DRIVER_BULK_DEFAULT_TIMEOUT (150*HZ)
#define CCID_DRIVER_ASYNC_POWERUP_TIMEOUT (35*HZ)
#define CCID_DRIVER_MINIMUM_TIMEOUT (3*HZ)
#define READ_WRITE_BUFFER_SIZE 512
#define POLL_LOOP_COUNT 1000
/* how often to poll for fifo status change */
#define POLL_PERIOD msecs_to_jiffies(10)
static void reader_release(struct pcmcia_device *link);
static int major;
static struct class *cmx_class;
#define BS_READABLE 0x01
#define BS_WRITABLE 0x02
struct reader_dev {
struct pcmcia_device *p_dev;
wait_queue_head_t devq;
wait_queue_head_t poll_wait;
wait_queue_head_t read_wait;
wait_queue_head_t write_wait;
unsigned long buffer_status;
unsigned long timeout;
unsigned char s_buf[READ_WRITE_BUFFER_SIZE];
unsigned char r_buf[READ_WRITE_BUFFER_SIZE];
struct timer_list poll_timer;
};
static struct pcmcia_device *dev_table[CM_MAX_DEV];
#ifndef CM4040_DEBUG
#define xoutb outb
#define xinb inb
#else
static inline void xoutb(unsigned char val, unsigned short port)
{
pr_debug("outb(val=%.2x,port=%.4x)\n", val, port);
outb(val, port);
}
static inline unsigned char xinb(unsigned short port)
{
unsigned char val;
val = inb(port);
pr_debug("%.2x=inb(%.4x)\n", val, port);
return val;
}
#endif
/* poll the device fifo status register. not to be confused with
* the poll syscall. */
static void cm4040_do_poll(struct timer_list *t)
{
struct reader_dev *dev = from_timer(dev, t, poll_timer);
unsigned int obs = xinb(dev->p_dev->resource[0]->start
+ REG_OFFSET_BUFFER_STATUS);
if ((obs & BSR_BULK_IN_FULL)) {
set_bit(BS_READABLE, &dev->buffer_status);
DEBUGP(4, dev, "waking up read_wait\n");
wake_up_interruptible(&dev->read_wait);
} else
clear_bit(BS_READABLE, &dev->buffer_status);
if (!(obs & BSR_BULK_OUT_FULL)) {
set_bit(BS_WRITABLE, &dev->buffer_status);
DEBUGP(4, dev, "waking up write_wait\n");
wake_up_interruptible(&dev->write_wait);
} else
clear_bit(BS_WRITABLE, &dev->buffer_status);
if (dev->buffer_status)
wake_up_interruptible(&dev->poll_wait);
mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD);
}
static void cm4040_stop_poll(struct reader_dev *dev)
{
del_timer_sync(&dev->poll_timer);
}
static int wait_for_bulk_out_ready(struct reader_dev *dev)
{
int i, rc;
int iobase = dev->p_dev->resource[0]->start;
for (i = 0; i < POLL_LOOP_COUNT; i++) {
if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS)
& BSR_BULK_OUT_FULL) == 0) {
DEBUGP(4, dev, "BulkOut empty (i=%d)\n", i);
return 1;
}
}
DEBUGP(4, dev, "wait_event_interruptible_timeout(timeout=%ld\n",
dev->timeout);
rc = wait_event_interruptible_timeout(dev->write_wait,
test_and_clear_bit(BS_WRITABLE,
&dev->buffer_status),
dev->timeout);
if (rc > 0)
DEBUGP(4, dev, "woke up: BulkOut empty\n");
else if (rc == 0)
DEBUGP(4, dev, "woke up: BulkOut full, returning 0 :(\n");
else if (rc < 0)
DEBUGP(4, dev, "woke up: signal arrived\n");
return rc;
}
/* Write to Sync Control Register */
static int write_sync_reg(unsigned char val, struct reader_dev *dev)
{
int iobase = dev->p_dev->resource[0]->start;
int rc;
rc = wait_for_bulk_out_ready(dev);
if (rc <= 0)
return rc;
xoutb(val, iobase + REG_OFFSET_SYNC_CONTROL);
rc = wait_for_bulk_out_ready(dev);
if (rc <= 0)
return rc;
return 1;
}
static int wait_for_bulk_in_ready(struct reader_dev *dev)
{
int i, rc;
int iobase = dev->p_dev->resource[0]->start;
for (i = 0; i < POLL_LOOP_COUNT; i++) {
if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS)
& BSR_BULK_IN_FULL) == BSR_BULK_IN_FULL) {
DEBUGP(3, dev, "BulkIn full (i=%d)\n", i);
return 1;
}
}
DEBUGP(4, dev, "wait_event_interruptible_timeout(timeout=%ld\n",
dev->timeout);
rc = wait_event_interruptible_timeout(dev->read_wait,
test_and_clear_bit(BS_READABLE,
&dev->buffer_status),
dev->timeout);
if (rc > 0)
DEBUGP(4, dev, "woke up: BulkIn full\n");
else if (rc == 0)
DEBUGP(4, dev, "woke up: BulkIn not full, returning 0 :(\n");
else if (rc < 0)
DEBUGP(4, dev, "woke up: signal arrived\n");
return rc;
}
static ssize_t cm4040_read(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
struct reader_dev *dev = filp->private_data;
int iobase = dev->p_dev->resource[0]->start;
size_t bytes_to_read;
unsigned long i;
size_t min_bytes_to_read;
int rc;
DEBUGP(2, dev, "-> cm4040_read(%s,%d)\n", current->comm, current->pid);
if (count == 0)
return 0;
if (count < 10)
return -EFAULT;
if (filp->f_flags & O_NONBLOCK) {
DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n");
DEBUGP(2, dev, "<- cm4040_read (failure)\n");
return -EAGAIN;
}
if (!pcmcia_dev_present(dev->p_dev))
return -ENODEV;
for (i = 0; i < 5; i++) {
rc = wait_for_bulk_in_ready(dev);
if (rc <= 0) {
DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc);
DEBUGP(2, dev, "<- cm4040_read (failed)\n");
if (rc == -ERESTARTSYS)
return rc;
return -EIO;
}
dev->r_buf[i] = xinb(iobase + REG_OFFSET_BULK_IN);
#ifdef CM4040_DEBUG
pr_debug("%lu:%2x ", i, dev->r_buf[i]);
}
pr_debug("\n");
#else
}
#endif
bytes_to_read = 5 + le32_to_cpu(*(__le32 *)&dev->r_buf[1]);
DEBUGP(6, dev, "BytesToRead=%zu\n", bytes_to_read);
min_bytes_to_read = min(count, bytes_to_read + 5);
min_bytes_to_read = min_t(size_t, min_bytes_to_read, READ_WRITE_BUFFER_SIZE);
DEBUGP(6, dev, "Min=%zu\n", min_bytes_to_read);
for (i = 0; i < (min_bytes_to_read-5); i++) {
rc = wait_for_bulk_in_ready(dev);
if (rc <= 0) {
DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc);
DEBUGP(2, dev, "<- cm4040_read (failed)\n");
if (rc == -ERESTARTSYS)
return rc;
return -EIO;
}
dev->r_buf[i+5] = xinb(iobase + REG_OFFSET_BULK_IN);
#ifdef CM4040_DEBUG
pr_debug("%lu:%2x ", i, dev->r_buf[i]);
}
pr_debug("\n");
#else
}
#endif
*ppos = min_bytes_to_read;
if (copy_to_user(buf, dev->r_buf, min_bytes_to_read))
return -EFAULT;
rc = wait_for_bulk_in_ready(dev);
if (rc <= 0) {
DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc);
DEBUGP(2, dev, "<- cm4040_read (failed)\n");
if (rc == -ERESTARTSYS)
return rc;
return -EIO;
}
rc = write_sync_reg(SCR_READER_TO_HOST_DONE, dev);
if (rc <= 0) {
DEBUGP(5, dev, "write_sync_reg c=%.2x\n", rc);
DEBUGP(2, dev, "<- cm4040_read (failed)\n");
if (rc == -ERESTARTSYS)
return rc;
else
return -EIO;
}
xinb(iobase + REG_OFFSET_BULK_IN);
DEBUGP(2, dev, "<- cm4040_read (successfully)\n");
return min_bytes_to_read;
}
static ssize_t cm4040_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
struct reader_dev *dev = filp->private_data;
int iobase = dev->p_dev->resource[0]->start;
ssize_t rc;
int i;
unsigned int bytes_to_write;
DEBUGP(2, dev, "-> cm4040_write(%s,%d)\n", current->comm, current->pid);
if (count == 0) {
DEBUGP(2, dev, "<- cm4040_write empty read (successfully)\n");
return 0;
}
if ((count < 5) || (count > READ_WRITE_BUFFER_SIZE)) {
DEBUGP(2, dev, "<- cm4040_write buffersize=%zd < 5\n", count);
return -EIO;
}
if (filp->f_flags & O_NONBLOCK) {
DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n");
DEBUGP(4, dev, "<- cm4040_write (failure)\n");
return -EAGAIN;
}
if (!pcmcia_dev_present(dev->p_dev))
return -ENODEV;
bytes_to_write = count;
if (copy_from_user(dev->s_buf, buf, bytes_to_write))
return -EFAULT;
switch (dev->s_buf[0]) {
case CMD_PC_TO_RDR_XFRBLOCK:
case CMD_PC_TO_RDR_SECURE:
case CMD_PC_TO_RDR_TEST_SECURE:
case CMD_PC_TO_RDR_OK_SECURE:
dev->timeout = CCID_DRIVER_BULK_DEFAULT_TIMEOUT;
break;
case CMD_PC_TO_RDR_ICCPOWERON:
dev->timeout = CCID_DRIVER_ASYNC_POWERUP_TIMEOUT;
break;
case CMD_PC_TO_RDR_GETSLOTSTATUS:
case CMD_PC_TO_RDR_ICCPOWEROFF:
case CMD_PC_TO_RDR_GETPARAMETERS:
case CMD_PC_TO_RDR_RESETPARAMETERS:
case CMD_PC_TO_RDR_SETPARAMETERS:
case CMD_PC_TO_RDR_ESCAPE:
case CMD_PC_TO_RDR_ICCCLOCK:
default:
dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
break;
}
rc = write_sync_reg(SCR_HOST_TO_READER_START, dev);
if (rc <= 0) {
DEBUGP(5, dev, "write_sync_reg c=%.2zx\n", rc);
DEBUGP(2, dev, "<- cm4040_write (failed)\n");
if (rc == -ERESTARTSYS)
return rc;
else
return -EIO;
}
DEBUGP(4, dev, "start \n");
for (i = 0; i < bytes_to_write; i++) {
rc = wait_for_bulk_out_ready(dev);
if (rc <= 0) {
DEBUGP(5, dev, "wait_for_bulk_out_ready rc=%.2zx\n",
rc);
DEBUGP(2, dev, "<- cm4040_write (failed)\n");
if (rc == -ERESTARTSYS)
return rc;
else
return -EIO;
}
xoutb(dev->s_buf[i],iobase + REG_OFFSET_BULK_OUT);
}
DEBUGP(4, dev, "end\n");
rc = write_sync_reg(SCR_HOST_TO_READER_DONE, dev);
if (rc <= 0) {
DEBUGP(5, dev, "write_sync_reg c=%.2zx\n", rc);
DEBUGP(2, dev, "<- cm4040_write (failed)\n");
if (rc == -ERESTARTSYS)
return rc;
else
return -EIO;
}
DEBUGP(2, dev, "<- cm4040_write (successfully)\n");
return count;
}
static __poll_t cm4040_poll(struct file *filp, poll_table *wait)
{
struct reader_dev *dev = filp->private_data;
__poll_t mask = 0;
poll_wait(filp, &dev->poll_wait, wait);
if (test_and_clear_bit(BS_READABLE, &dev->buffer_status))
mask |= EPOLLIN | EPOLLRDNORM;
if (test_and_clear_bit(BS_WRITABLE, &dev->buffer_status))
mask |= EPOLLOUT | EPOLLWRNORM;
DEBUGP(2, dev, "<- cm4040_poll(%u)\n", mask);
return mask;
}
static int cm4040_open(struct inode *inode, struct file *filp)
{
struct reader_dev *dev;
struct pcmcia_device *link;
int minor = iminor(inode);
int ret;
if (minor >= CM_MAX_DEV)
return -ENODEV;
mutex_lock(&cm4040_mutex);
link = dev_table[minor];
if (link == NULL || !pcmcia_dev_present(link)) {
ret = -ENODEV;
goto out;
}
if (link->open) {
ret = -EBUSY;
goto out;
}
dev = link->priv;
filp->private_data = dev;
if (filp->f_flags & O_NONBLOCK) {
DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n");
ret = -EAGAIN;
goto out;
}
link->open = 1;
mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD);
DEBUGP(2, dev, "<- cm4040_open (successfully)\n");
ret = nonseekable_open(inode, filp);
out:
mutex_unlock(&cm4040_mutex);
return ret;
}
static int cm4040_close(struct inode *inode, struct file *filp)
{
struct reader_dev *dev = filp->private_data;
struct pcmcia_device *link;
int minor = iminor(inode);
DEBUGP(2, dev, "-> cm4040_close(maj/min=%d.%d)\n", imajor(inode),
iminor(inode));
if (minor >= CM_MAX_DEV)
return -ENODEV;
link = dev_table[minor];
if (link == NULL)
return -ENODEV;
cm4040_stop_poll(dev);
link->open = 0;
wake_up(&dev->devq);
DEBUGP(2, dev, "<- cm4040_close\n");
return 0;
}
static void cm4040_reader_release(struct pcmcia_device *link)
{
struct reader_dev *dev = link->priv;
DEBUGP(3, dev, "-> cm4040_reader_release\n");
while (link->open) {
DEBUGP(3, dev, MODULE_NAME ": delaying release "
"until process has terminated\n");
wait_event(dev->devq, (link->open == 0));
}
DEBUGP(3, dev, "<- cm4040_reader_release\n");
return;
}
static int cm4040_config_check(struct pcmcia_device *p_dev, void *priv_data)
{
return pcmcia_request_io(p_dev);
}
static int reader_config(struct pcmcia_device *link, int devno)
{
struct reader_dev *dev;
int fail_rc;
link->config_flags |= CONF_AUTO_SET_IO;
if (pcmcia_loop_config(link, cm4040_config_check, NULL))
goto cs_release;
fail_rc = pcmcia_enable_device(link);
if (fail_rc != 0) {
dev_info(&link->dev, "pcmcia_enable_device failed 0x%x\n",
fail_rc);
goto cs_release;
}
dev = link->priv;
DEBUGP(2, dev, "device " DEVICE_NAME "%d at %pR\n", devno,
link->resource[0]);
DEBUGP(2, dev, "<- reader_config (succ)\n");
return 0;
cs_release:
reader_release(link);
return -ENODEV;
}
static void reader_release(struct pcmcia_device *link)
{
cm4040_reader_release(link);
pcmcia_disable_device(link);
}
static int reader_probe(struct pcmcia_device *link)
{
struct reader_dev *dev;
int i, ret;
for (i = 0; i < CM_MAX_DEV; i++) {
if (dev_table[i] == NULL)
break;
}
if (i == CM_MAX_DEV)
return -ENODEV;
dev = kzalloc(sizeof(struct reader_dev), GFP_KERNEL);
if (dev == NULL)
return -ENOMEM;
dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
dev->buffer_status = 0;
link->priv = dev;
dev->p_dev = link;
dev_table[i] = link;
init_waitqueue_head(&dev->devq);
init_waitqueue_head(&dev->poll_wait);
init_waitqueue_head(&dev->read_wait);
init_waitqueue_head(&dev->write_wait);
timer_setup(&dev->poll_timer, cm4040_do_poll, 0);
ret = reader_config(link, i);
if (ret) {
dev_table[i] = NULL;
kfree(dev);
return ret;
}
device_create(cmx_class, NULL, MKDEV(major, i), NULL, "cmx%d", i);
return 0;
}
static void reader_detach(struct pcmcia_device *link)
{
struct reader_dev *dev = link->priv;
int devno;
/* find device */
for (devno = 0; devno < CM_MAX_DEV; devno++) {
if (dev_table[devno] == link)
break;
}
if (devno == CM_MAX_DEV)
return;
reader_release(link);
dev_table[devno] = NULL;
kfree(dev);
device_destroy(cmx_class, MKDEV(major, devno));
return;
}
static const struct file_operations reader_fops = {
.owner = THIS_MODULE,
.read = cm4040_read,
.write = cm4040_write,
.open = cm4040_open,
.release = cm4040_close,
.poll = cm4040_poll,
.llseek = no_llseek,
};
static const struct pcmcia_device_id cm4040_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0200),
PCMCIA_DEVICE_PROD_ID12("OMNIKEY", "CardMan 4040",
0xE32CDD8C, 0x8F23318B),
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, cm4040_ids);
static struct pcmcia_driver reader_driver = {
.owner = THIS_MODULE,
.name = "cm4040_cs",
.probe = reader_probe,
.remove = reader_detach,
.id_table = cm4040_ids,
};
static int __init cm4040_init(void)
{
int rc;
cmx_class = class_create(THIS_MODULE, "cardman_4040");
if (IS_ERR(cmx_class))
return PTR_ERR(cmx_class);
major = register_chrdev(0, DEVICE_NAME, &reader_fops);
if (major < 0) {
printk(KERN_WARNING MODULE_NAME
": could not get major number\n");
class_destroy(cmx_class);
return major;
}
rc = pcmcia_register_driver(&reader_driver);
if (rc < 0) {
unregister_chrdev(major, DEVICE_NAME);
class_destroy(cmx_class);
return rc;
}
return 0;
}
static void __exit cm4040_exit(void)
{
pcmcia_unregister_driver(&reader_driver);
unregister_chrdev(major, DEVICE_NAME);
class_destroy(cmx_class);
}
module_init(cm4040_init);
module_exit(cm4040_exit);
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -1,48 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _CM4040_H_
#define _CM4040_H_
#define CM_MAX_DEV 4
#define DEVICE_NAME "cmx"
#define MODULE_NAME "cm4040_cs"
#define REG_OFFSET_BULK_OUT 0
#define REG_OFFSET_BULK_IN 0
#define REG_OFFSET_BUFFER_STATUS 1
#define REG_OFFSET_SYNC_CONTROL 2
#define BSR_BULK_IN_FULL 0x02
#define BSR_BULK_OUT_FULL 0x01
#define SCR_HOST_TO_READER_START 0x80
#define SCR_ABORT 0x40
#define SCR_EN_NOTIFY 0x20
#define SCR_ACK_NOTIFY 0x10
#define SCR_READER_TO_HOST_DONE 0x08
#define SCR_HOST_TO_READER_DONE 0x04
#define SCR_PULSE_INTERRUPT 0x02
#define SCR_POWER_DOWN 0x01
#define CMD_PC_TO_RDR_ICCPOWERON 0x62
#define CMD_PC_TO_RDR_GETSLOTSTATUS 0x65
#define CMD_PC_TO_RDR_ICCPOWEROFF 0x63
#define CMD_PC_TO_RDR_SECURE 0x69
#define CMD_PC_TO_RDR_GETPARAMETERS 0x6C
#define CMD_PC_TO_RDR_RESETPARAMETERS 0x6D
#define CMD_PC_TO_RDR_SETPARAMETERS 0x61
#define CMD_PC_TO_RDR_XFRBLOCK 0x6F
#define CMD_PC_TO_RDR_ESCAPE 0x6B
#define CMD_PC_TO_RDR_ICCCLOCK 0x6E
#define CMD_PC_TO_RDR_TEST_SECURE 0x74
#define CMD_PC_TO_RDR_OK_SECURE 0x89
#define CMD_RDR_TO_PC_SLOTSTATUS 0x81
#define CMD_RDR_TO_PC_DATABLOCK 0x80
#define CMD_RDR_TO_PC_PARAMETERS 0x82
#define CMD_RDR_TO_PC_ESCAPE 0x83
#define CMD_RDR_TO_PC_OK_SECURE 0x89
#endif /* _CM4040_H_ */

View File

@ -1,359 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* SCR24x PCMCIA Smart Card Reader Driver
*
* Copyright (C) 2005-2006 TL Sudheendran
* Copyright (C) 2016 Lubomir Rintel
*
* Derived from "scr24x_v4.2.6_Release.tar.gz" driver by TL Sudheendran.
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#define CCID_HEADER_SIZE 10
#define CCID_LENGTH_OFFSET 1
#define CCID_MAX_LEN 271
#define SCR24X_DATA(n) (1 + n)
#define SCR24X_CMD_STATUS 7
#define CMD_START 0x40
#define CMD_WRITE_BYTE 0x41
#define CMD_READ_BYTE 0x42
#define STATUS_BUSY 0x80
struct scr24x_dev {
struct device *dev;
struct cdev c_dev;
unsigned char buf[CCID_MAX_LEN];
int devno;
struct mutex lock;
struct kref refcnt;
u8 __iomem *regs;
};
#define SCR24X_DEVS 8
static DECLARE_BITMAP(scr24x_minors, SCR24X_DEVS);
static struct class *scr24x_class;
static dev_t scr24x_devt;
static void scr24x_delete(struct kref *kref)
{
struct scr24x_dev *dev = container_of(kref, struct scr24x_dev,
refcnt);
kfree(dev);
}
static int scr24x_wait_ready(struct scr24x_dev *dev)
{
u_char status;
int timeout = 100;
do {
status = ioread8(dev->regs + SCR24X_CMD_STATUS);
if (!(status & STATUS_BUSY))
return 0;
msleep(20);
} while (--timeout);
return -EIO;
}
static int scr24x_open(struct inode *inode, struct file *filp)
{
struct scr24x_dev *dev = container_of(inode->i_cdev,
struct scr24x_dev, c_dev);
kref_get(&dev->refcnt);
filp->private_data = dev;
return stream_open(inode, filp);
}
static int scr24x_release(struct inode *inode, struct file *filp)
{
struct scr24x_dev *dev = filp->private_data;
/* We must not take the dev->lock here as scr24x_delete()
* might be called to remove the dev structure altogether.
* We don't need the lock anyway, since after the reference
* acquired in probe() is released in remove() the chrdev
* is already unregistered and noone can possibly acquire
* a reference via open() anymore. */
kref_put(&dev->refcnt, scr24x_delete);
return 0;
}
static int read_chunk(struct scr24x_dev *dev, size_t offset, size_t limit)
{
size_t i, y;
int ret;
for (i = offset; i < limit; i += 5) {
iowrite8(CMD_READ_BYTE, dev->regs + SCR24X_CMD_STATUS);
ret = scr24x_wait_ready(dev);
if (ret < 0)
return ret;
for (y = 0; y < 5 && i + y < limit; y++)
dev->buf[i + y] = ioread8(dev->regs + SCR24X_DATA(y));
}
return 0;
}
static ssize_t scr24x_read(struct file *filp, char __user *buf, size_t count,
loff_t *ppos)
{
struct scr24x_dev *dev = filp->private_data;
int ret;
int len;
if (count < CCID_HEADER_SIZE)
return -EINVAL;
if (mutex_lock_interruptible(&dev->lock))
return -ERESTARTSYS;
if (!dev->dev) {
ret = -ENODEV;
goto out;
}
ret = scr24x_wait_ready(dev);
if (ret < 0)
goto out;
len = CCID_HEADER_SIZE;
ret = read_chunk(dev, 0, len);
if (ret < 0)
goto out;
len += le32_to_cpu(*(__le32 *)(&dev->buf[CCID_LENGTH_OFFSET]));
if (len > sizeof(dev->buf)) {
ret = -EIO;
goto out;
}
ret = read_chunk(dev, CCID_HEADER_SIZE, len);
if (ret < 0)
goto out;
if (len < count)
count = len;
if (copy_to_user(buf, dev->buf, count)) {
ret = -EFAULT;
goto out;
}
ret = count;
out:
mutex_unlock(&dev->lock);
return ret;
}
static ssize_t scr24x_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
struct scr24x_dev *dev = filp->private_data;
size_t i, y;
int ret;
if (mutex_lock_interruptible(&dev->lock))
return -ERESTARTSYS;
if (!dev->dev) {
ret = -ENODEV;
goto out;
}
if (count > sizeof(dev->buf)) {
ret = -EINVAL;
goto out;
}
if (copy_from_user(dev->buf, buf, count)) {
ret = -EFAULT;
goto out;
}
ret = scr24x_wait_ready(dev);
if (ret < 0)
goto out;
iowrite8(CMD_START, dev->regs + SCR24X_CMD_STATUS);
ret = scr24x_wait_ready(dev);
if (ret < 0)
goto out;
for (i = 0; i < count; i += 5) {
for (y = 0; y < 5 && i + y < count; y++)
iowrite8(dev->buf[i + y], dev->regs + SCR24X_DATA(y));
iowrite8(CMD_WRITE_BYTE, dev->regs + SCR24X_CMD_STATUS);
ret = scr24x_wait_ready(dev);
if (ret < 0)
goto out;
}
ret = count;
out:
mutex_unlock(&dev->lock);
return ret;
}
static const struct file_operations scr24x_fops = {
.owner = THIS_MODULE,
.read = scr24x_read,
.write = scr24x_write,
.open = scr24x_open,
.release = scr24x_release,
.llseek = no_llseek,
};
static int scr24x_config_check(struct pcmcia_device *link, void *priv_data)
{
if (resource_size(link->resource[PCMCIA_IOPORT_0]) != 0x11)
return -ENODEV;
return pcmcia_request_io(link);
}
static int scr24x_probe(struct pcmcia_device *link)
{
struct scr24x_dev *dev;
int ret;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
dev->devno = find_first_zero_bit(scr24x_minors, SCR24X_DEVS);
if (dev->devno >= SCR24X_DEVS) {
ret = -EBUSY;
goto err;
}
mutex_init(&dev->lock);
kref_init(&dev->refcnt);
link->priv = dev;
link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
ret = pcmcia_loop_config(link, scr24x_config_check, NULL);
if (ret < 0)
goto err;
dev->dev = &link->dev;
dev->regs = devm_ioport_map(&link->dev,
link->resource[PCMCIA_IOPORT_0]->start,
resource_size(link->resource[PCMCIA_IOPORT_0]));
if (!dev->regs) {
ret = -EIO;
goto err;
}
cdev_init(&dev->c_dev, &scr24x_fops);
dev->c_dev.owner = THIS_MODULE;
ret = cdev_add(&dev->c_dev, MKDEV(MAJOR(scr24x_devt), dev->devno), 1);
if (ret < 0)
goto err;
ret = pcmcia_enable_device(link);
if (ret < 0) {
pcmcia_disable_device(link);
goto err;
}
device_create(scr24x_class, NULL, MKDEV(MAJOR(scr24x_devt), dev->devno),
NULL, "scr24x%d", dev->devno);
dev_info(&link->dev, "SCR24x Chip Card Interface\n");
return 0;
err:
if (dev->devno < SCR24X_DEVS)
clear_bit(dev->devno, scr24x_minors);
kfree (dev);
return ret;
}
static void scr24x_remove(struct pcmcia_device *link)
{
struct scr24x_dev *dev = (struct scr24x_dev *)link->priv;
device_destroy(scr24x_class, MKDEV(MAJOR(scr24x_devt), dev->devno));
mutex_lock(&dev->lock);
pcmcia_disable_device(link);
cdev_del(&dev->c_dev);
clear_bit(dev->devno, scr24x_minors);
dev->dev = NULL;
mutex_unlock(&dev->lock);
kref_put(&dev->refcnt, scr24x_delete);
}
static const struct pcmcia_device_id scr24x_ids[] = {
PCMCIA_DEVICE_PROD_ID12("HP", "PC Card Smart Card Reader",
0x53cb94f9, 0xbfdf89a5),
PCMCIA_DEVICE_PROD_ID1("SCR241 PCMCIA", 0x6271efa3),
PCMCIA_DEVICE_PROD_ID1("SCR243 PCMCIA", 0x2054e8de),
PCMCIA_DEVICE_PROD_ID1("SCR24x PCMCIA", 0x54a33665),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, scr24x_ids);
static struct pcmcia_driver scr24x_driver = {
.owner = THIS_MODULE,
.name = "scr24x_cs",
.probe = scr24x_probe,
.remove = scr24x_remove,
.id_table = scr24x_ids,
};
static int __init scr24x_init(void)
{
int ret;
scr24x_class = class_create(THIS_MODULE, "scr24x");
if (IS_ERR(scr24x_class))
return PTR_ERR(scr24x_class);
ret = alloc_chrdev_region(&scr24x_devt, 0, SCR24X_DEVS, "scr24x");
if (ret < 0) {
class_destroy(scr24x_class);
return ret;
}
ret = pcmcia_register_driver(&scr24x_driver);
if (ret < 0) {
unregister_chrdev_region(scr24x_devt, SCR24X_DEVS);
class_destroy(scr24x_class);
}
return ret;
}
static void __exit scr24x_exit(void)
{
pcmcia_unregister_driver(&scr24x_driver);
unregister_chrdev_region(scr24x_devt, SCR24X_DEVS);
class_destroy(scr24x_class);
}
module_init(scr24x_init);
module_exit(scr24x_exit);
MODULE_AUTHOR("Lubomir Rintel");
MODULE_DESCRIPTION("SCR24x PCMCIA Smart Card Reader Driver");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _CM4000_H_
#define _CM4000_H_
#include <uapi/linux/cm4000_cs.h>
#define DEVICE_NAME "cmm"
#define MODULE_NAME "cm4000_cs"
#endif /* _CM4000_H_ */

View File

@ -1,64 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _UAPI_CM4000_H_
#define _UAPI_CM4000_H_
#include <linux/types.h>
#include <linux/ioctl.h>
#define MAX_ATR 33
#define CM4000_MAX_DEV 4
/* those two structures are passed via ioctl() from/to userspace. They are
* used by existing userspace programs, so I kepth the awkward "bIFSD" naming
* not to break compilation of userspace apps. -HW */
typedef struct atreq {
__s32 atr_len;
unsigned char atr[64];
__s32 power_act;
unsigned char bIFSD;
unsigned char bIFSC;
} atreq_t;
/* what is particularly stupid in the original driver is the arch-dependent
* member sizes. This leads to CONFIG_COMPAT breakage, since 32bit userspace
* will lay out the structure members differently than the 64bit kernel.
*
* I've changed "ptsreq.protocol" from "unsigned long" to "__u32".
* On 32bit this will make no difference. With 64bit kernels, it will make
* 32bit apps work, too.
*/
typedef struct ptsreq {
__u32 protocol; /*T=0: 2^0, T=1: 2^1*/
unsigned char flags;
unsigned char pts1;
unsigned char pts2;
unsigned char pts3;
} ptsreq_t;
#define CM_IOC_MAGIC 'c'
#define CM_IOC_MAXNR 255
#define CM_IOCGSTATUS _IOR (CM_IOC_MAGIC, 0, unsigned char *)
#define CM_IOCGATR _IOWR(CM_IOC_MAGIC, 1, atreq_t *)
#define CM_IOCSPTS _IOW (CM_IOC_MAGIC, 2, ptsreq_t *)
#define CM_IOCSRDR _IO (CM_IOC_MAGIC, 3)
#define CM_IOCARDOFF _IO (CM_IOC_MAGIC, 4)
#define CM_IOSDBGLVL _IOW(CM_IOC_MAGIC, 250, int*)
/* card and device states */
#define CM_CARD_INSERTED 0x01
#define CM_CARD_POWERED 0x02
#define CM_ATR_PRESENT 0x04
#define CM_ATR_VALID 0x08
#define CM_STATE_VALID 0x0f
/* extra info only from CM4000 */
#define CM_NO_READER 0x10
#define CM_BAD_CARD 0x20
#endif /* _UAPI_CM4000_H_ */