linux/drivers/staging/speakup/devsynth.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/errno.h>
   3#include <linux/miscdevice.h>   /* for misc_register, and SYNTH_MINOR */
   4#include <linux/types.h>
   5#include <linux/uaccess.h>
   6
   7#include "speakup.h"
   8#include "spk_priv.h"
   9
  10#ifndef SYNTH_MINOR
  11#define SYNTH_MINOR 25
  12#endif
  13
  14static int misc_registered;
  15static int dev_opened;
  16
  17static ssize_t speakup_file_write(struct file *fp, const char __user *buffer,
  18                                  size_t nbytes, loff_t *ppos)
  19{
  20        size_t count = nbytes;
  21        const char __user *ptr = buffer;
  22        size_t bytes;
  23        unsigned long flags;
  24        u_char buf[256];
  25
  26        if (!synth)
  27                return -ENODEV;
  28        while (count > 0) {
  29                bytes = min(count, sizeof(buf));
  30                if (copy_from_user(buf, ptr, bytes))
  31                        return -EFAULT;
  32                count -= bytes;
  33                ptr += bytes;
  34                spin_lock_irqsave(&speakup_info.spinlock, flags);
  35                synth_write(buf, bytes);
  36                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
  37        }
  38        return (ssize_t)nbytes;
  39}
  40
  41static ssize_t speakup_file_read(struct file *fp, char __user *buf,
  42                                 size_t nbytes, loff_t *ppos)
  43{
  44        return 0;
  45}
  46
  47static int speakup_file_open(struct inode *ip, struct file *fp)
  48{
  49        if (!synth)
  50                return -ENODEV;
  51        if (xchg(&dev_opened, 1))
  52                return -EBUSY;
  53        return 0;
  54}
  55
  56static int speakup_file_release(struct inode *ip, struct file *fp)
  57{
  58        dev_opened = 0;
  59        return 0;
  60}
  61
  62static const struct file_operations synth_fops = {
  63        .read = speakup_file_read,
  64        .write = speakup_file_write,
  65        .open = speakup_file_open,
  66        .release = speakup_file_release,
  67};
  68
  69static struct miscdevice synth_device = {
  70        .minor = SYNTH_MINOR,
  71        .name = "synth",
  72        .fops = &synth_fops,
  73};
  74
  75void speakup_register_devsynth(void)
  76{
  77        if (misc_registered != 0)
  78                return;
  79/* zero it so if register fails, deregister will not ref invalid ptrs */
  80        if (misc_register(&synth_device)) {
  81                pr_warn("Couldn't initialize miscdevice /dev/synth.\n");
  82        } else {
  83                pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n",
  84                        MISC_MAJOR, SYNTH_MINOR);
  85                misc_registered = 1;
  86        }
  87}
  88
  89void speakup_unregister_devsynth(void)
  90{
  91        if (!misc_registered)
  92                return;
  93        pr_info("speakup: unregistering synth device /dev/synth\n");
  94        misc_deregister(&synth_device);
  95        misc_registered = 0;
  96}
  97