// SPDX-License-Identifier: GPL-2.0-or-later /* * linux/drivers/char/ppdev.c * * This is the code behind /dev/parport* -- it allows a user-space * application to use the parport subsystem. * * Copyright (C) 1998-2000, 2002 Tim Waugh <[email protected]> * * A /dev/parportx device node represents an arbitrary device * on port 'x'. The following operations are possible: * * open do nothing, set up default IEEE 1284 protocol to be COMPAT * close release port and unregister device (if necessary) * ioctl * EXCL register device exclusively (may fail) * CLAIM (register device first time) parport_claim_or_block * RELEASE parport_release * SETMODE set the IEEE 1284 protocol to use for read/write * SETPHASE set the IEEE 1284 phase of a particular mode. Not to be * confused with ioctl(fd, SETPHASER, &stun). ;-) * DATADIR data_forward / data_reverse * WDATA write_data * RDATA read_data * WCONTROL write_control * RCONTROL read_control * FCONTROL frob_control * RSTATUS read_status * NEGOT parport_negotiate * YIELD parport_yield_blocking * WCTLONIRQ on interrupt, set control lines * CLRIRQ clear (and return) interrupt count * SETTIME sets device timeout (struct timeval) * GETTIME gets device timeout (struct timeval) * GETMODES gets hardware supported modes (unsigned int) * GETMODE gets the current IEEE1284 mode * GETPHASE gets the current IEEE1284 phase * GETFLAGS gets current (user-visible) flags * SETFLAGS sets current (user-visible) flags * read/write read or write in current IEEE 1284 protocol * select wait for interrupt (in readfds) * * Changes: * Added SETTIME/GETTIME ioctl, Fred Barnes, 1999. * * Arnaldo Carvalho de Melo <[email protected]> 2000/08/25 * - On error, copy_from_user and copy_to_user do not return -EFAULT, * They return the positive number of bytes *not* copied due to address * space errors. * * Added GETMODES/GETMODE/GETPHASE ioctls, Fred Barnes <[email protected]>, 03/01/2001. * Added GETFLAGS/SETFLAGS ioctls, Fred Barnes, 04/2001 */ #include <linux/module.h> #include <linux/init.h> #include <linux/sched/signal.h> #include <linux/device.h> #include <linux/ioctl.h> #include <linux/parport.h> #include <linux/ctype.h> #include <linux/poll.h> #include <linux/slab.h> #include <linux/major.h> #include <linux/ppdev.h> #include <linux/mutex.h> #include <linux/uaccess.h> #include <linux/compat.h> #define PP_VERSION … #define CHRDEV … struct pp_struct { … }; /* should we use PARDEVICE_MAX here? */ static struct device *devices[PARPORT_MAX]; static DEFINE_IDA(ida_index); /* pp_struct.flags bitfields */ #define PP_CLAIMED … #define PP_EXCL … /* Other constants */ #define PP_INTERRUPT_TIMEOUT … #define PP_BUFFER_SIZE … #define PARDEVICE_MAX … static DEFINE_MUTEX(pp_do_mutex); /* define fixed sized ioctl cmd for y2038 migration */ #define PPGETTIME32 … #define PPSETTIME32 … #define PPGETTIME64 … #define PPSETTIME64 … static inline void pp_enable_irq(struct pp_struct *pp) { … } static ssize_t pp_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { … } static ssize_t pp_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { … } static void pp_irq(void *private) { … } static int register_device(int minor, struct pp_struct *pp) { … } static enum ieee1284_phase init_phase(int mode) { … } static int pp_set_timeout(struct pardevice *pdev, long tv_sec, int tv_usec) { … } static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { … } static long pp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { … } static int pp_open(struct inode *inode, struct file *file) { … } static int pp_release(struct inode *inode, struct file *file) { … } /* No kernel lock held - fine */ static __poll_t pp_poll(struct file *file, poll_table *wait) { … } static const struct class ppdev_class = …; static const struct file_operations pp_fops = …; static void pp_attach(struct parport *port) { … } static void pp_detach(struct parport *port) { … } static int pp_probe(struct pardevice *par_dev) { … } static struct parport_driver pp_driver = …; static int __init ppdev_init(void) { … } static void __exit ppdev_cleanup(void) { … } module_init(…) …; module_exit(ppdev_cleanup); MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …; MODULE_ALIAS_CHARDEV_MAJOR(…);