root/drivers/input/serio/serport.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. serport_serio_write
  2. serport_serio_open
  3. serport_serio_close
  4. serport_ldisc_open
  5. serport_ldisc_close
  6. serport_ldisc_receive
  7. serport_ldisc_read
  8. serport_set_type
  9. serport_ldisc_ioctl
  10. serport_ldisc_compat_ioctl
  11. serport_ldisc_hangup
  12. serport_ldisc_write_wakeup
  13. serport_init
  14. serport_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Input device TTY line discipline
   4  *
   5  * Copyright (c) 1999-2002 Vojtech Pavlik
   6  *
   7  * This is a module that converts a tty line into a much simpler
   8  * 'serial io port' abstraction that the input device drivers use.
   9  */
  10 
  11 
  12 #include <linux/uaccess.h>
  13 #include <linux/kernel.h>
  14 #include <linux/sched.h>
  15 #include <linux/slab.h>
  16 #include <linux/module.h>
  17 #include <linux/init.h>
  18 #include <linux/serio.h>
  19 #include <linux/tty.h>
  20 #include <linux/compat.h>
  21 
  22 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
  23 MODULE_DESCRIPTION("Input device TTY line discipline");
  24 MODULE_LICENSE("GPL");
  25 MODULE_ALIAS_LDISC(N_MOUSE);
  26 
  27 #define SERPORT_BUSY    1
  28 #define SERPORT_ACTIVE  2
  29 #define SERPORT_DEAD    3
  30 
  31 struct serport {
  32         struct tty_struct *tty;
  33         wait_queue_head_t wait;
  34         struct serio *serio;
  35         struct serio_device_id id;
  36         spinlock_t lock;
  37         unsigned long flags;
  38 };
  39 
  40 /*
  41  * Callback functions from the serio code.
  42  */
  43 
  44 static int serport_serio_write(struct serio *serio, unsigned char data)
  45 {
  46         struct serport *serport = serio->port_data;
  47         return -(serport->tty->ops->write(serport->tty, &data, 1) != 1);
  48 }
  49 
  50 static int serport_serio_open(struct serio *serio)
  51 {
  52         struct serport *serport = serio->port_data;
  53         unsigned long flags;
  54 
  55         spin_lock_irqsave(&serport->lock, flags);
  56         set_bit(SERPORT_ACTIVE, &serport->flags);
  57         spin_unlock_irqrestore(&serport->lock, flags);
  58 
  59         return 0;
  60 }
  61 
  62 
  63 static void serport_serio_close(struct serio *serio)
  64 {
  65         struct serport *serport = serio->port_data;
  66         unsigned long flags;
  67 
  68         spin_lock_irqsave(&serport->lock, flags);
  69         clear_bit(SERPORT_ACTIVE, &serport->flags);
  70         spin_unlock_irqrestore(&serport->lock, flags);
  71 }
  72 
  73 /*
  74  * serport_ldisc_open() is the routine that is called upon setting our line
  75  * discipline on a tty. It prepares the serio struct.
  76  */
  77 
  78 static int serport_ldisc_open(struct tty_struct *tty)
  79 {
  80         struct serport *serport;
  81 
  82         if (!capable(CAP_SYS_ADMIN))
  83                 return -EPERM;
  84 
  85         serport = kzalloc(sizeof(struct serport), GFP_KERNEL);
  86         if (!serport)
  87                 return -ENOMEM;
  88 
  89         serport->tty = tty;
  90         spin_lock_init(&serport->lock);
  91         init_waitqueue_head(&serport->wait);
  92 
  93         tty->disc_data = serport;
  94         tty->receive_room = 256;
  95         set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
  96 
  97         return 0;
  98 }
  99 
 100 /*
 101  * serport_ldisc_close() is the opposite of serport_ldisc_open()
 102  */
 103 
 104 static void serport_ldisc_close(struct tty_struct *tty)
 105 {
 106         struct serport *serport = (struct serport *) tty->disc_data;
 107 
 108         kfree(serport);
 109 }
 110 
 111 /*
 112  * serport_ldisc_receive() is called by the low level tty driver when characters
 113  * are ready for us. We forward the characters and flags, one by one to the
 114  * 'interrupt' routine.
 115  */
 116 
 117 static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
 118 {
 119         struct serport *serport = (struct serport*) tty->disc_data;
 120         unsigned long flags;
 121         unsigned int ch_flags = 0;
 122         int i;
 123 
 124         spin_lock_irqsave(&serport->lock, flags);
 125 
 126         if (!test_bit(SERPORT_ACTIVE, &serport->flags))
 127                 goto out;
 128 
 129         for (i = 0; i < count; i++) {
 130                 if (fp) {
 131                         switch (fp[i]) {
 132                         case TTY_FRAME:
 133                                 ch_flags = SERIO_FRAME;
 134                                 break;
 135 
 136                         case TTY_PARITY:
 137                                 ch_flags = SERIO_PARITY;
 138                                 break;
 139 
 140                         default:
 141                                 ch_flags = 0;
 142                                 break;
 143                         }
 144                 }
 145 
 146                 serio_interrupt(serport->serio, cp[i], ch_flags);
 147         }
 148 
 149 out:
 150         spin_unlock_irqrestore(&serport->lock, flags);
 151 }
 152 
 153 /*
 154  * serport_ldisc_read() just waits indefinitely if everything goes well.
 155  * However, when the serio driver closes the serio port, it finishes,
 156  * returning 0 characters.
 157  */
 158 
 159 static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char __user * buf, size_t nr)
 160 {
 161         struct serport *serport = (struct serport*) tty->disc_data;
 162         struct serio *serio;
 163 
 164         if (test_and_set_bit(SERPORT_BUSY, &serport->flags))
 165                 return -EBUSY;
 166 
 167         serport->serio = serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
 168         if (!serio)
 169                 return -ENOMEM;
 170 
 171         strlcpy(serio->name, "Serial port", sizeof(serio->name));
 172         snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty));
 173         serio->id = serport->id;
 174         serio->id.type = SERIO_RS232;
 175         serio->write = serport_serio_write;
 176         serio->open = serport_serio_open;
 177         serio->close = serport_serio_close;
 178         serio->port_data = serport;
 179         serio->dev.parent = tty->dev;
 180 
 181         serio_register_port(serport->serio);
 182         printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty));
 183 
 184         wait_event_interruptible(serport->wait, test_bit(SERPORT_DEAD, &serport->flags));
 185         serio_unregister_port(serport->serio);
 186         serport->serio = NULL;
 187 
 188         clear_bit(SERPORT_DEAD, &serport->flags);
 189         clear_bit(SERPORT_BUSY, &serport->flags);
 190 
 191         return 0;
 192 }
 193 
 194 static void serport_set_type(struct tty_struct *tty, unsigned long type)
 195 {
 196         struct serport *serport = tty->disc_data;
 197 
 198         serport->id.proto = type & 0x000000ff;
 199         serport->id.id    = (type & 0x0000ff00) >> 8;
 200         serport->id.extra = (type & 0x00ff0000) >> 16;
 201 }
 202 
 203 /*
 204  * serport_ldisc_ioctl() allows to set the port protocol, and device ID
 205  */
 206 
 207 static int serport_ldisc_ioctl(struct tty_struct *tty, struct file *file,
 208                                unsigned int cmd, unsigned long arg)
 209 {
 210         if (cmd == SPIOCSTYPE) {
 211                 unsigned long type;
 212 
 213                 if (get_user(type, (unsigned long __user *) arg))
 214                         return -EFAULT;
 215 
 216                 serport_set_type(tty, type);
 217                 return 0;
 218         }
 219 
 220         return -EINVAL;
 221 }
 222 
 223 #ifdef CONFIG_COMPAT
 224 #define COMPAT_SPIOCSTYPE       _IOW('q', 0x01, compat_ulong_t)
 225 static int serport_ldisc_compat_ioctl(struct tty_struct *tty,
 226                                        struct file *file,
 227                                        unsigned int cmd, unsigned long arg)
 228 {
 229         if (cmd == COMPAT_SPIOCSTYPE) {
 230                 void __user *uarg = compat_ptr(arg);
 231                 compat_ulong_t compat_type;
 232 
 233                 if (get_user(compat_type, (compat_ulong_t __user *)uarg))
 234                         return -EFAULT;
 235 
 236                 serport_set_type(tty, compat_type);
 237                 return 0;
 238         }
 239 
 240         return -EINVAL;
 241 }
 242 #endif
 243 
 244 static int serport_ldisc_hangup(struct tty_struct *tty)
 245 {
 246         struct serport *serport = (struct serport *) tty->disc_data;
 247         unsigned long flags;
 248 
 249         spin_lock_irqsave(&serport->lock, flags);
 250         set_bit(SERPORT_DEAD, &serport->flags);
 251         spin_unlock_irqrestore(&serport->lock, flags);
 252 
 253         wake_up_interruptible(&serport->wait);
 254         return 0;
 255 }
 256 
 257 static void serport_ldisc_write_wakeup(struct tty_struct * tty)
 258 {
 259         struct serport *serport = (struct serport *) tty->disc_data;
 260         unsigned long flags;
 261 
 262         spin_lock_irqsave(&serport->lock, flags);
 263         if (test_bit(SERPORT_ACTIVE, &serport->flags))
 264                 serio_drv_write_wakeup(serport->serio);
 265         spin_unlock_irqrestore(&serport->lock, flags);
 266 }
 267 
 268 /*
 269  * The line discipline structure.
 270  */
 271 
 272 static struct tty_ldisc_ops serport_ldisc = {
 273         .owner =        THIS_MODULE,
 274         .name =         "input",
 275         .open =         serport_ldisc_open,
 276         .close =        serport_ldisc_close,
 277         .read =         serport_ldisc_read,
 278         .ioctl =        serport_ldisc_ioctl,
 279 #ifdef CONFIG_COMPAT
 280         .compat_ioctl = serport_ldisc_compat_ioctl,
 281 #endif
 282         .receive_buf =  serport_ldisc_receive,
 283         .hangup =       serport_ldisc_hangup,
 284         .write_wakeup = serport_ldisc_write_wakeup
 285 };
 286 
 287 /*
 288  * The functions for insering/removing us as a module.
 289  */
 290 
 291 static int __init serport_init(void)
 292 {
 293         int retval;
 294         retval = tty_register_ldisc(N_MOUSE, &serport_ldisc);
 295         if (retval)
 296                 printk(KERN_ERR "serport.c: Error registering line discipline.\n");
 297 
 298         return  retval;
 299 }
 300 
 301 static void __exit serport_exit(void)
 302 {
 303         tty_unregister_ldisc(N_MOUSE);
 304 }
 305 
 306 module_init(serport_init);
 307 module_exit(serport_exit);

/* [<][>][^][v][top][bottom][index][help] */