forked from mirrors/linux
		
	serdev: Add serdev_device_write subroutine
Add serdev_device_write() a blocking call allowing to transfer arbitraty amount of data (potentially exceeding amount that serdev_device_write_buf can process in a single call) To support that, also add serdev_device_write_wakeup(). Drivers wanting to use full extent of serdev_device_write functionality are expected to provide serdev_device_write_wakeup() as a sole handler of .write_wakeup event or call it as a part of driver's custom .write_wakeup code. Because serdev_device_write() subroutine is a superset of serdev_device_write_buf() the patch re-impelements latter is terms of the former. For drivers wanting to just use serdev_device_write_buf() .write_wakeup handler is optional. Cc: cphealy@gmail.com Cc: Guenter Roeck <linux@roeck-us.net> Cc: linux-serial@vger.kernel.org Cc: linux-kernel@vger.kernel.org Reviewed-by: Rob Herring <robh@kernel.org> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
		
							parent
							
								
									e1dc9b0805
								
							
						
					
					
						commit
						6fe729c4bd
					
				
					 2 changed files with 46 additions and 7 deletions
				
			
		|  | @ -116,17 +116,41 @@ void serdev_device_close(struct serdev_device *serdev) | |||
| } | ||||
| EXPORT_SYMBOL_GPL(serdev_device_close); | ||||
| 
 | ||||
| int serdev_device_write_buf(struct serdev_device *serdev, | ||||
| 			    const unsigned char *buf, size_t count) | ||||
| void serdev_device_write_wakeup(struct serdev_device *serdev) | ||||
| { | ||||
| 	complete(&serdev->write_comp); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(serdev_device_write_wakeup); | ||||
| 
 | ||||
| int serdev_device_write(struct serdev_device *serdev, | ||||
| 			const unsigned char *buf, size_t count, | ||||
| 			unsigned long timeout) | ||||
| { | ||||
| 	struct serdev_controller *ctrl = serdev->ctrl; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!ctrl || !ctrl->ops->write_buf) | ||||
| 	if (!ctrl || !ctrl->ops->write_buf || | ||||
| 	    (timeout && !serdev->ops->write_wakeup)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	return ctrl->ops->write_buf(ctrl, buf, count); | ||||
| 	mutex_lock(&serdev->write_lock); | ||||
| 	do { | ||||
| 		reinit_completion(&serdev->write_comp); | ||||
| 
 | ||||
| 		ret = ctrl->ops->write_buf(ctrl, buf, count); | ||||
| 		if (ret < 0) | ||||
| 			break; | ||||
| 
 | ||||
| 		buf += ret; | ||||
| 		count -= ret; | ||||
| 
 | ||||
| 	} while (count && | ||||
| 		 (timeout = wait_for_completion_timeout(&serdev->write_comp, | ||||
| 							timeout))); | ||||
| 	mutex_unlock(&serdev->write_lock); | ||||
| 	return ret < 0 ? ret : (count ? -ETIMEDOUT : 0); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(serdev_device_write_buf); | ||||
| EXPORT_SYMBOL_GPL(serdev_device_write); | ||||
| 
 | ||||
| void serdev_device_write_flush(struct serdev_device *serdev) | ||||
| { | ||||
|  | @ -232,6 +256,8 @@ struct serdev_device *serdev_device_alloc(struct serdev_controller *ctrl) | |||
| 	serdev->dev.parent = &ctrl->dev; | ||||
| 	serdev->dev.bus = &serdev_bus_type; | ||||
| 	serdev->dev.type = &serdev_device_type; | ||||
| 	init_completion(&serdev->write_comp); | ||||
| 	mutex_init(&serdev->write_lock); | ||||
| 	return serdev; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(serdev_device_alloc); | ||||
|  |  | |||
|  | @ -39,12 +39,16 @@ struct serdev_device_ops { | |||
|  * @nr:		Device number on serdev bus. | ||||
|  * @ctrl:	serdev controller managing this device. | ||||
|  * @ops:	Device operations. | ||||
|  * @write_comp	Completion used by serdev_device_write() internally | ||||
|  * @write_lock	Lock to serialize access when writing data | ||||
|  */ | ||||
| struct serdev_device { | ||||
| 	struct device dev; | ||||
| 	int nr; | ||||
| 	struct serdev_controller *ctrl; | ||||
| 	const struct serdev_device_ops *ops; | ||||
| 	struct completion write_comp; | ||||
| 	struct mutex write_lock; | ||||
| }; | ||||
| 
 | ||||
| static inline struct serdev_device *to_serdev_device(struct device *d) | ||||
|  | @ -186,7 +190,8 @@ int serdev_device_open(struct serdev_device *); | |||
| void serdev_device_close(struct serdev_device *); | ||||
| unsigned int serdev_device_set_baudrate(struct serdev_device *, unsigned int); | ||||
| void serdev_device_set_flow_control(struct serdev_device *, bool); | ||||
| int serdev_device_write_buf(struct serdev_device *, const unsigned char *, size_t); | ||||
| void serdev_device_write_wakeup(struct serdev_device *); | ||||
| int serdev_device_write(struct serdev_device *, const unsigned char *, size_t, unsigned long); | ||||
| void serdev_device_write_flush(struct serdev_device *); | ||||
| int serdev_device_write_room(struct serdev_device *); | ||||
| 
 | ||||
|  | @ -223,7 +228,8 @@ static inline unsigned int serdev_device_set_baudrate(struct serdev_device *sdev | |||
| 	return 0; | ||||
| } | ||||
| static inline void serdev_device_set_flow_control(struct serdev_device *sdev, bool enable) {} | ||||
| static inline int serdev_device_write_buf(struct serdev_device *sdev, const unsigned char *buf, size_t count) | ||||
| static inline int serdev_device_write(struct serdev_device *sdev, const unsigned char *buf, | ||||
| 				      size_t count, unsigned long timeout) | ||||
| { | ||||
| 	return -ENODEV; | ||||
| } | ||||
|  | @ -259,4 +265,11 @@ static inline struct device *serdev_tty_port_register(struct tty_port *port, | |||
| static inline void serdev_tty_port_unregister(struct tty_port *port) {} | ||||
| #endif /* CONFIG_SERIAL_DEV_CTRL_TTYPORT */ | ||||
| 
 | ||||
| static inline int serdev_device_write_buf(struct serdev_device *serdev, | ||||
| 					  const unsigned char *data, | ||||
| 					  size_t count) | ||||
| { | ||||
| 	return serdev_device_write(serdev, data, count, 0); | ||||
| } | ||||
| 
 | ||||
| #endif /*_LINUX_SERDEV_H */ | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Andrey Smirnov
						Andrey Smirnov