devsynth.c 2.1 KB

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