scr24x_cs.c (7771B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * SCR24x PCMCIA Smart Card Reader Driver 4 * 5 * Copyright (C) 2005-2006 TL Sudheendran 6 * Copyright (C) 2016 Lubomir Rintel 7 * 8 * Derived from "scr24x_v4.2.6_Release.tar.gz" driver by TL Sudheendran. 9 */ 10 11#include <linux/device.h> 12#include <linux/module.h> 13#include <linux/delay.h> 14#include <linux/cdev.h> 15#include <linux/slab.h> 16#include <linux/fs.h> 17#include <linux/io.h> 18#include <linux/uaccess.h> 19 20#include <pcmcia/cistpl.h> 21#include <pcmcia/ds.h> 22 23#define CCID_HEADER_SIZE 10 24#define CCID_LENGTH_OFFSET 1 25#define CCID_MAX_LEN 271 26 27#define SCR24X_DATA(n) (1 + n) 28#define SCR24X_CMD_STATUS 7 29#define CMD_START 0x40 30#define CMD_WRITE_BYTE 0x41 31#define CMD_READ_BYTE 0x42 32#define STATUS_BUSY 0x80 33 34struct scr24x_dev { 35 struct device *dev; 36 struct cdev c_dev; 37 unsigned char buf[CCID_MAX_LEN]; 38 int devno; 39 struct mutex lock; 40 struct kref refcnt; 41 u8 __iomem *regs; 42}; 43 44#define SCR24X_DEVS 8 45static DECLARE_BITMAP(scr24x_minors, SCR24X_DEVS); 46 47static struct class *scr24x_class; 48static dev_t scr24x_devt; 49 50static void scr24x_delete(struct kref *kref) 51{ 52 struct scr24x_dev *dev = container_of(kref, struct scr24x_dev, 53 refcnt); 54 55 kfree(dev); 56} 57 58static int scr24x_wait_ready(struct scr24x_dev *dev) 59{ 60 u_char status; 61 int timeout = 100; 62 63 do { 64 status = ioread8(dev->regs + SCR24X_CMD_STATUS); 65 if (!(status & STATUS_BUSY)) 66 return 0; 67 68 msleep(20); 69 } while (--timeout); 70 71 return -EIO; 72} 73 74static int scr24x_open(struct inode *inode, struct file *filp) 75{ 76 struct scr24x_dev *dev = container_of(inode->i_cdev, 77 struct scr24x_dev, c_dev); 78 79 kref_get(&dev->refcnt); 80 filp->private_data = dev; 81 82 return stream_open(inode, filp); 83} 84 85static int scr24x_release(struct inode *inode, struct file *filp) 86{ 87 struct scr24x_dev *dev = filp->private_data; 88 89 /* We must not take the dev->lock here as scr24x_delete() 90 * might be called to remove the dev structure altogether. 91 * We don't need the lock anyway, since after the reference 92 * acquired in probe() is released in remove() the chrdev 93 * is already unregistered and noone can possibly acquire 94 * a reference via open() anymore. */ 95 kref_put(&dev->refcnt, scr24x_delete); 96 return 0; 97} 98 99static int read_chunk(struct scr24x_dev *dev, size_t offset, size_t limit) 100{ 101 size_t i, y; 102 int ret; 103 104 for (i = offset; i < limit; i += 5) { 105 iowrite8(CMD_READ_BYTE, dev->regs + SCR24X_CMD_STATUS); 106 ret = scr24x_wait_ready(dev); 107 if (ret < 0) 108 return ret; 109 110 for (y = 0; y < 5 && i + y < limit; y++) 111 dev->buf[i + y] = ioread8(dev->regs + SCR24X_DATA(y)); 112 } 113 114 return 0; 115} 116 117static ssize_t scr24x_read(struct file *filp, char __user *buf, size_t count, 118 loff_t *ppos) 119{ 120 struct scr24x_dev *dev = filp->private_data; 121 int ret; 122 int len; 123 124 if (count < CCID_HEADER_SIZE) 125 return -EINVAL; 126 127 if (mutex_lock_interruptible(&dev->lock)) 128 return -ERESTARTSYS; 129 130 if (!dev->dev) { 131 ret = -ENODEV; 132 goto out; 133 } 134 135 ret = scr24x_wait_ready(dev); 136 if (ret < 0) 137 goto out; 138 len = CCID_HEADER_SIZE; 139 ret = read_chunk(dev, 0, len); 140 if (ret < 0) 141 goto out; 142 143 len += le32_to_cpu(*(__le32 *)(&dev->buf[CCID_LENGTH_OFFSET])); 144 if (len > sizeof(dev->buf)) { 145 ret = -EIO; 146 goto out; 147 } 148 ret = read_chunk(dev, CCID_HEADER_SIZE, len); 149 if (ret < 0) 150 goto out; 151 152 if (len < count) 153 count = len; 154 155 if (copy_to_user(buf, dev->buf, count)) { 156 ret = -EFAULT; 157 goto out; 158 } 159 160 ret = count; 161out: 162 mutex_unlock(&dev->lock); 163 return ret; 164} 165 166static ssize_t scr24x_write(struct file *filp, const char __user *buf, 167 size_t count, loff_t *ppos) 168{ 169 struct scr24x_dev *dev = filp->private_data; 170 size_t i, y; 171 int ret; 172 173 if (mutex_lock_interruptible(&dev->lock)) 174 return -ERESTARTSYS; 175 176 if (!dev->dev) { 177 ret = -ENODEV; 178 goto out; 179 } 180 181 if (count > sizeof(dev->buf)) { 182 ret = -EINVAL; 183 goto out; 184 } 185 186 if (copy_from_user(dev->buf, buf, count)) { 187 ret = -EFAULT; 188 goto out; 189 } 190 191 ret = scr24x_wait_ready(dev); 192 if (ret < 0) 193 goto out; 194 195 iowrite8(CMD_START, dev->regs + SCR24X_CMD_STATUS); 196 ret = scr24x_wait_ready(dev); 197 if (ret < 0) 198 goto out; 199 200 for (i = 0; i < count; i += 5) { 201 for (y = 0; y < 5 && i + y < count; y++) 202 iowrite8(dev->buf[i + y], dev->regs + SCR24X_DATA(y)); 203 204 iowrite8(CMD_WRITE_BYTE, dev->regs + SCR24X_CMD_STATUS); 205 ret = scr24x_wait_ready(dev); 206 if (ret < 0) 207 goto out; 208 } 209 210 ret = count; 211out: 212 mutex_unlock(&dev->lock); 213 return ret; 214} 215 216static const struct file_operations scr24x_fops = { 217 .owner = THIS_MODULE, 218 .read = scr24x_read, 219 .write = scr24x_write, 220 .open = scr24x_open, 221 .release = scr24x_release, 222 .llseek = no_llseek, 223}; 224 225static int scr24x_config_check(struct pcmcia_device *link, void *priv_data) 226{ 227 if (resource_size(link->resource[PCMCIA_IOPORT_0]) != 0x11) 228 return -ENODEV; 229 return pcmcia_request_io(link); 230} 231 232static int scr24x_probe(struct pcmcia_device *link) 233{ 234 struct scr24x_dev *dev; 235 int ret; 236 237 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 238 if (!dev) 239 return -ENOMEM; 240 241 dev->devno = find_first_zero_bit(scr24x_minors, SCR24X_DEVS); 242 if (dev->devno >= SCR24X_DEVS) { 243 ret = -EBUSY; 244 goto err; 245 } 246 247 mutex_init(&dev->lock); 248 kref_init(&dev->refcnt); 249 250 link->priv = dev; 251 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; 252 253 ret = pcmcia_loop_config(link, scr24x_config_check, NULL); 254 if (ret < 0) 255 goto err; 256 257 dev->dev = &link->dev; 258 dev->regs = devm_ioport_map(&link->dev, 259 link->resource[PCMCIA_IOPORT_0]->start, 260 resource_size(link->resource[PCMCIA_IOPORT_0])); 261 if (!dev->regs) { 262 ret = -EIO; 263 goto err; 264 } 265 266 cdev_init(&dev->c_dev, &scr24x_fops); 267 dev->c_dev.owner = THIS_MODULE; 268 ret = cdev_add(&dev->c_dev, MKDEV(MAJOR(scr24x_devt), dev->devno), 1); 269 if (ret < 0) 270 goto err; 271 272 ret = pcmcia_enable_device(link); 273 if (ret < 0) { 274 pcmcia_disable_device(link); 275 goto err; 276 } 277 278 device_create(scr24x_class, NULL, MKDEV(MAJOR(scr24x_devt), dev->devno), 279 NULL, "scr24x%d", dev->devno); 280 281 dev_info(&link->dev, "SCR24x Chip Card Interface\n"); 282 return 0; 283 284err: 285 if (dev->devno < SCR24X_DEVS) 286 clear_bit(dev->devno, scr24x_minors); 287 kfree (dev); 288 return ret; 289} 290 291static void scr24x_remove(struct pcmcia_device *link) 292{ 293 struct scr24x_dev *dev = (struct scr24x_dev *)link->priv; 294 295 device_destroy(scr24x_class, MKDEV(MAJOR(scr24x_devt), dev->devno)); 296 mutex_lock(&dev->lock); 297 pcmcia_disable_device(link); 298 cdev_del(&dev->c_dev); 299 clear_bit(dev->devno, scr24x_minors); 300 dev->dev = NULL; 301 mutex_unlock(&dev->lock); 302 303 kref_put(&dev->refcnt, scr24x_delete); 304} 305 306static const struct pcmcia_device_id scr24x_ids[] = { 307 PCMCIA_DEVICE_PROD_ID12("HP", "PC Card Smart Card Reader", 308 0x53cb94f9, 0xbfdf89a5), 309 PCMCIA_DEVICE_PROD_ID1("SCR241 PCMCIA", 0x6271efa3), 310 PCMCIA_DEVICE_PROD_ID1("SCR243 PCMCIA", 0x2054e8de), 311 PCMCIA_DEVICE_PROD_ID1("SCR24x PCMCIA", 0x54a33665), 312 PCMCIA_DEVICE_NULL 313}; 314MODULE_DEVICE_TABLE(pcmcia, scr24x_ids); 315 316static struct pcmcia_driver scr24x_driver = { 317 .owner = THIS_MODULE, 318 .name = "scr24x_cs", 319 .probe = scr24x_probe, 320 .remove = scr24x_remove, 321 .id_table = scr24x_ids, 322}; 323 324static int __init scr24x_init(void) 325{ 326 int ret; 327 328 scr24x_class = class_create(THIS_MODULE, "scr24x"); 329 if (IS_ERR(scr24x_class)) 330 return PTR_ERR(scr24x_class); 331 332 ret = alloc_chrdev_region(&scr24x_devt, 0, SCR24X_DEVS, "scr24x"); 333 if (ret < 0) { 334 class_destroy(scr24x_class); 335 return ret; 336 } 337 338 ret = pcmcia_register_driver(&scr24x_driver); 339 if (ret < 0) { 340 unregister_chrdev_region(scr24x_devt, SCR24X_DEVS); 341 class_destroy(scr24x_class); 342 } 343 344 return ret; 345} 346 347static void __exit scr24x_exit(void) 348{ 349 pcmcia_unregister_driver(&scr24x_driver); 350 unregister_chrdev_region(scr24x_devt, SCR24X_DEVS); 351 class_destroy(scr24x_class); 352} 353 354module_init(scr24x_init); 355module_exit(scr24x_exit); 356 357MODULE_AUTHOR("Lubomir Rintel"); 358MODULE_DESCRIPTION("SCR24x PCMCIA Smart Card Reader Driver"); 359MODULE_LICENSE("GPL");