mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	Here is the big set of char/misc and a number of other driver subsystem
 updates for 6.9-rc1.  Included in here are:
   - IIO driver updates, loads of new ones and evolution of existing ones
   - coresight driver updates
   - const cleanups for many driver subsystems
   - speakup driver additions
   - platform remove callback void cleanups
   - mei driver updates
   - mhi driver updates
   - cdx driver updates for MSI interrupt handling
   - nvmem driver updates
   - other smaller driver updates and cleanups, full details in the
     shortlog
 
 All of these have been in linux-next for a long time with no reported
 issue, other than a build warning with some older versions of gcc for a
 speakup driver, fix for that will come in a few days when I catch up
 with my pending patch queues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZfwuLg8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ynKVACgjvR1cD8NYk9PcGWc9ZaXAZ6zSnwAn260kMoe
 lLFtwszo7m0N6ZULBWBd
 =y3yz
 -----END PGP SIGNATURE-----
Merge tag 'char-misc-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc and other driver subsystem updates from Greg KH:
 "Here is the big set of char/misc and a number of other driver
  subsystem updates for 6.9-rc1. Included in here are:
   - IIO driver updates, loads of new ones and evolution of existing ones
   - coresight driver updates
   - const cleanups for many driver subsystems
   - speakup driver additions
   - platform remove callback void cleanups
   - mei driver updates
   - mhi driver updates
   - cdx driver updates for MSI interrupt handling
   - nvmem driver updates
   - other smaller driver updates and cleanups, full details in the
    shortlog
  All of these have been in linux-next for a long time with no reported
  issue, other than a build warning for the speakup driver"
The build warning hits clang and is a gcc (and C23) extension, and is
fixed up in the merge.
Link: https://lore.kernel.org/all/20240321134831.GA2762840@dev-arch.thelio-3990X/
* tag 'char-misc-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (279 commits)
  binder: remove redundant variable page_addr
  uio_dmem_genirq: UIO_MEM_DMA_COHERENT conversion
  uio_pruss: UIO_MEM_DMA_COHERENT conversion
  cnic,bnx2,bnx2x: use UIO_MEM_DMA_COHERENT
  uio: introduce UIO_MEM_DMA_COHERENT type
  cdx: add MSI support for CDX bus
  pps: use cflags-y instead of EXTRA_CFLAGS
  speakup: Add /dev/synthu device
  speakup: Fix 8bit characters from direct synth
  parport: sunbpp: Convert to platform remove callback returning void
  parport: amiga: Convert to platform remove callback returning void
  char: xillybus: Convert to platform remove callback returning void
  vmw_balloon: change maintainership
  MAINTAINERS: change the maintainer for hpilo driver
  char: xilinx_hwicap: Fix NULL vs IS_ERR() bug
  hpet: remove hpets::hp_clocksource
  platform: goldfish: move the separate 'default' propery for CONFIG_GOLDFISH
  char: xilinx_hwicap: drop casting to void in dev_set_drvdata
  greybus: move is_gb_* functions out of greybus.h
  greybus: Remove usage of the deprecated ida_simple_xx() API
  ...
		
	
			
		
			
				
	
	
		
			211 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0
 | 
						|
#include <linux/errno.h>
 | 
						|
#include <linux/miscdevice.h>	/* for misc_register, and MISC_DYNAMIC_MINOR */
 | 
						|
#include <linux/types.h>
 | 
						|
#include <linux/uaccess.h>
 | 
						|
 | 
						|
#include "speakup.h"
 | 
						|
#include "spk_priv.h"
 | 
						|
 | 
						|
static int synth_registered, synthu_registered;
 | 
						|
static int dev_opened;
 | 
						|
 | 
						|
/* Latin1 version */
 | 
						|
static ssize_t speakup_file_write(struct file *fp, const char __user *buffer,
 | 
						|
				  size_t nbytes, loff_t *ppos)
 | 
						|
{
 | 
						|
	size_t count = nbytes;
 | 
						|
	const char __user *ptr = buffer;
 | 
						|
	size_t bytes;
 | 
						|
	unsigned long flags;
 | 
						|
	u_char buf[256];
 | 
						|
 | 
						|
	if (!synth)
 | 
						|
		return -ENODEV;
 | 
						|
	while (count > 0) {
 | 
						|
		bytes = min(count, sizeof(buf));
 | 
						|
		if (copy_from_user(buf, ptr, bytes))
 | 
						|
			return -EFAULT;
 | 
						|
		count -= bytes;
 | 
						|
		ptr += bytes;
 | 
						|
		spin_lock_irqsave(&speakup_info.spinlock, flags);
 | 
						|
		synth_write(buf, bytes);
 | 
						|
		spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 | 
						|
	}
 | 
						|
	return (ssize_t)nbytes;
 | 
						|
}
 | 
						|
 | 
						|
/* UTF-8 version */
 | 
						|
static ssize_t speakup_file_writeu(struct file *fp, const char __user *buffer,
 | 
						|
				   size_t nbytes, loff_t *ppos)
 | 
						|
{
 | 
						|
	size_t count = nbytes, want;
 | 
						|
	const char __user *ptr = buffer;
 | 
						|
	size_t bytes;
 | 
						|
	unsigned long flags;
 | 
						|
	unsigned char buf[256];
 | 
						|
	u16 ubuf[256];
 | 
						|
	size_t in, in2, out;
 | 
						|
 | 
						|
	if (!synth)
 | 
						|
		return -ENODEV;
 | 
						|
 | 
						|
	want = 1;
 | 
						|
	while (count >= want) {
 | 
						|
		/* Copy some UTF-8 piece from userland */
 | 
						|
		bytes = min(count, sizeof(buf));
 | 
						|
		if (copy_from_user(buf, ptr, bytes))
 | 
						|
			return -EFAULT;
 | 
						|
 | 
						|
		/* Convert to u16 */
 | 
						|
		for (in = 0, out = 0; in < bytes; in++) {
 | 
						|
			unsigned char c = buf[in];
 | 
						|
			int nbytes = 8 - fls(c ^ 0xff);
 | 
						|
			u32 value;
 | 
						|
 | 
						|
			switch (nbytes) {
 | 
						|
			case 8: /* 0xff */
 | 
						|
			case 7: /* 0xfe */
 | 
						|
			case 1: /* 0x80 */
 | 
						|
				/* Invalid, drop */
 | 
						|
				goto drop;
 | 
						|
 | 
						|
			case 0:
 | 
						|
				/* ASCII, copy */
 | 
						|
				ubuf[out++] = c;
 | 
						|
				continue;
 | 
						|
 | 
						|
			default:
 | 
						|
				/* 2..6-byte UTF-8 */
 | 
						|
 | 
						|
				if (bytes - in < nbytes) {
 | 
						|
					/* We don't have it all yet, stop here
 | 
						|
					 * and wait for the rest
 | 
						|
					 */
 | 
						|
					bytes = in;
 | 
						|
					want = nbytes;
 | 
						|
					continue;
 | 
						|
				}
 | 
						|
 | 
						|
				/* First byte */
 | 
						|
				value = c & ((1u << (7 - nbytes)) - 1);
 | 
						|
 | 
						|
				/* Other bytes */
 | 
						|
				for (in2 = 2; in2 <= nbytes; in2++) {
 | 
						|
					c = buf[in + 1];
 | 
						|
					if ((c & 0xc0) != 0x80)	{
 | 
						|
						/* Invalid, drop the head */
 | 
						|
						want = 1;
 | 
						|
						goto drop;
 | 
						|
					}
 | 
						|
					value = (value << 6) | (c & 0x3f);
 | 
						|
					in++;
 | 
						|
				}
 | 
						|
 | 
						|
				if (value < 0x10000)
 | 
						|
					ubuf[out++] = value;
 | 
						|
				want = 1;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
drop:
 | 
						|
			/* empty statement */;
 | 
						|
		}
 | 
						|
 | 
						|
		count -= bytes;
 | 
						|
		ptr += bytes;
 | 
						|
 | 
						|
		/* And speak this up */
 | 
						|
		if (out) {
 | 
						|
			spin_lock_irqsave(&speakup_info.spinlock, flags);
 | 
						|
			for (in = 0; in < out; in++)
 | 
						|
				synth_buffer_add(ubuf[in]);
 | 
						|
			synth_start();
 | 
						|
			spin_unlock_irqrestore(&speakup_info.spinlock, flags);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return (ssize_t)(nbytes - count);
 | 
						|
}
 | 
						|
 | 
						|
static ssize_t speakup_file_read(struct file *fp, char __user *buf,
 | 
						|
				 size_t nbytes, loff_t *ppos)
 | 
						|
{
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int speakup_file_open(struct inode *ip, struct file *fp)
 | 
						|
{
 | 
						|
	if (!synth)
 | 
						|
		return -ENODEV;
 | 
						|
	if (xchg(&dev_opened, 1))
 | 
						|
		return -EBUSY;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int speakup_file_release(struct inode *ip, struct file *fp)
 | 
						|
{
 | 
						|
	dev_opened = 0;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static const struct file_operations synth_fops = {
 | 
						|
	.read = speakup_file_read,
 | 
						|
	.write = speakup_file_write,
 | 
						|
	.open = speakup_file_open,
 | 
						|
	.release = speakup_file_release,
 | 
						|
};
 | 
						|
 | 
						|
static const struct file_operations synthu_fops = {
 | 
						|
	.read = speakup_file_read,
 | 
						|
	.write = speakup_file_writeu,
 | 
						|
	.open = speakup_file_open,
 | 
						|
	.release = speakup_file_release,
 | 
						|
};
 | 
						|
 | 
						|
static struct miscdevice synth_device = {
 | 
						|
	.minor = MISC_DYNAMIC_MINOR,
 | 
						|
	.name = "synth",
 | 
						|
	.fops = &synth_fops,
 | 
						|
};
 | 
						|
 | 
						|
static struct miscdevice synthu_device = {
 | 
						|
	.minor = MISC_DYNAMIC_MINOR,
 | 
						|
	.name = "synthu",
 | 
						|
	.fops = &synthu_fops,
 | 
						|
};
 | 
						|
 | 
						|
void speakup_register_devsynth(void)
 | 
						|
{
 | 
						|
	if (!synth_registered) {
 | 
						|
		if (misc_register(&synth_device)) {
 | 
						|
			pr_warn("Couldn't initialize miscdevice /dev/synth.\n");
 | 
						|
		} else {
 | 
						|
			pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n",
 | 
						|
				MISC_MAJOR, synth_device.minor);
 | 
						|
			synth_registered = 1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (!synthu_registered) {
 | 
						|
		if (misc_register(&synthu_device)) {
 | 
						|
			pr_warn("Couldn't initialize miscdevice /dev/synthu.\n");
 | 
						|
		} else {
 | 
						|
			pr_info("initialized device: /dev/synthu, node (MAJOR %d, MINOR %d)\n",
 | 
						|
				MISC_MAJOR, synthu_device.minor);
 | 
						|
			synthu_registered = 1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void speakup_unregister_devsynth(void)
 | 
						|
{
 | 
						|
	if (synth_registered) {
 | 
						|
		pr_info("speakup: unregistering synth device /dev/synth\n");
 | 
						|
		misc_deregister(&synth_device);
 | 
						|
		synth_registered = 0;
 | 
						|
	}
 | 
						|
	if (synthu_registered) {
 | 
						|
		pr_info("speakup: unregistering synth device /dev/synthu\n");
 | 
						|
		misc_deregister(&synthu_device);
 | 
						|
		synthu_registered = 0;
 | 
						|
	}
 | 
						|
}
 |