Path: blob/master/drivers/accessibility/speakup/devsynth.c
26282 views
// SPDX-License-Identifier: GPL-2.01#include <linux/errno.h>2#include <linux/miscdevice.h> /* for misc_register, and MISC_DYNAMIC_MINOR */3#include <linux/types.h>4#include <linux/uaccess.h>56#include "speakup.h"7#include "spk_priv.h"89static int synth_registered, synthu_registered;10static int dev_opened;1112/* Latin1 version */13static ssize_t speakup_file_write(struct file *fp, const char __user *buffer,14size_t nbytes, loff_t *ppos)15{16size_t count = nbytes;17const char __user *ptr = buffer;18size_t bytes;19unsigned long flags;20u_char buf[256];2122if (!synth)23return -ENODEV;24while (count > 0) {25bytes = min(count, sizeof(buf));26if (copy_from_user(buf, ptr, bytes))27return -EFAULT;28count -= bytes;29ptr += bytes;30spin_lock_irqsave(&speakup_info.spinlock, flags);31synth_write(buf, bytes);32spin_unlock_irqrestore(&speakup_info.spinlock, flags);33}34return (ssize_t)nbytes;35}3637/* UTF-8 version */38static ssize_t speakup_file_writeu(struct file *fp, const char __user *buffer,39size_t nbytes, loff_t *ppos)40{41size_t count = nbytes, consumed, want;42const char __user *ptr = buffer;43size_t bytes;44unsigned long flags;45unsigned char buf[256];46u16 ubuf[256];47size_t in, out;4849if (!synth)50return -ENODEV;5152want = 1;53while (count >= want) {54/* Copy some UTF-8 piece from userland */55bytes = min(count, sizeof(buf));56if (copy_from_user(buf, ptr, bytes))57return -EFAULT;5859/* Convert to u16 */60for (in = 0, out = 0; in < bytes; in += consumed) {61s32 value;6263value = synth_utf8_get(buf + in, bytes - in, &consumed, &want);64if (value == -1) {65/* Invalid or incomplete */6667if (want > bytes - in)68/* We don't have it all yet, stop here69* and wait for the rest70*/71bytes = in;7273continue;74}7576if (value < 0x10000)77ubuf[out++] = value;78}7980count -= bytes;81ptr += bytes;8283/* And speak this up */84if (out) {85spin_lock_irqsave(&speakup_info.spinlock, flags);86for (in = 0; in < out; in++)87synth_buffer_add(ubuf[in]);88synth_start();89spin_unlock_irqrestore(&speakup_info.spinlock, flags);90}91}9293return (ssize_t)(nbytes - count);94}9596static ssize_t speakup_file_read(struct file *fp, char __user *buf,97size_t nbytes, loff_t *ppos)98{99return 0;100}101102static int speakup_file_open(struct inode *ip, struct file *fp)103{104if (!synth)105return -ENODEV;106if (xchg(&dev_opened, 1))107return -EBUSY;108return 0;109}110111static int speakup_file_release(struct inode *ip, struct file *fp)112{113dev_opened = 0;114return 0;115}116117static const struct file_operations synth_fops = {118.read = speakup_file_read,119.write = speakup_file_write,120.open = speakup_file_open,121.release = speakup_file_release,122};123124static const struct file_operations synthu_fops = {125.read = speakup_file_read,126.write = speakup_file_writeu,127.open = speakup_file_open,128.release = speakup_file_release,129};130131static struct miscdevice synth_device = {132.minor = MISC_DYNAMIC_MINOR,133.name = "synth",134.fops = &synth_fops,135};136137static struct miscdevice synthu_device = {138.minor = MISC_DYNAMIC_MINOR,139.name = "synthu",140.fops = &synthu_fops,141};142143void speakup_register_devsynth(void)144{145if (!synth_registered) {146if (misc_register(&synth_device)) {147pr_warn("Couldn't initialize miscdevice /dev/synth.\n");148} else {149pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n",150MISC_MAJOR, synth_device.minor);151synth_registered = 1;152}153}154if (!synthu_registered) {155if (misc_register(&synthu_device)) {156pr_warn("Couldn't initialize miscdevice /dev/synthu.\n");157} else {158pr_info("initialized device: /dev/synthu, node (MAJOR %d, MINOR %d)\n",159MISC_MAJOR, synthu_device.minor);160synthu_registered = 1;161}162}163}164165void speakup_unregister_devsynth(void)166{167if (synth_registered) {168pr_info("speakup: unregistering synth device /dev/synth\n");169misc_deregister(&synth_device);170synth_registered = 0;171}172if (synthu_registered) {173pr_info("speakup: unregistering synth device /dev/synthu\n");174misc_deregister(&synthu_device);175synthu_registered = 0;176}177}178179180