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