Add an ioctl function to the I/O interface
This new ioctl function allows to perform I/O stream specific requests through a generic interface. This provides an easy way to extend the I/O interface with some driver specific features, without having to modify the public api.
This commit is contained in:
parent
be0e32b43b
commit
0359a57fdc
@ -42,6 +42,7 @@ typedef struct dc_custom_cbs_t {
|
||||
dc_status_t (*poll) (void *userdata, int timeout);
|
||||
dc_status_t (*read) (void *userdata, void *data, size_t size, size_t *actual);
|
||||
dc_status_t (*write) (void *userdata, const void *data, size_t size, size_t *actual);
|
||||
dc_status_t (*ioctl) (void *userdata, unsigned int request, void *data, size_t size);
|
||||
dc_status_t (*flush) (void *userdata);
|
||||
dc_status_t (*purge) (void *userdata, dc_direction_t direction);
|
||||
dc_status_t (*sleep) (void *userdata, unsigned int milliseconds);
|
||||
|
||||
73
include/libdivecomputer/ioctl.h
Normal file
73
include/libdivecomputer/ioctl.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2019 Jef Driesen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef DC_IOCTL_H
|
||||
#define DC_IOCTL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Ioctl direction bits.
|
||||
*
|
||||
* Note: WRITE means the application is writing and the driver is
|
||||
* reading. READ means the application is reading and the driver is
|
||||
* writing.
|
||||
*/
|
||||
#define DC_IOCTL_DIR_NONE 0u
|
||||
#define DC_IOCTL_DIR_READ 1u
|
||||
#define DC_IOCTL_DIR_WRITE 2u
|
||||
|
||||
/*
|
||||
* Ioctl variable size bits.
|
||||
*/
|
||||
#define DC_IOCTL_SIZE_VARIABLE 0
|
||||
|
||||
/*
|
||||
* Helper macro to encode ioctl numbers.
|
||||
*/
|
||||
#define DC_IOCTL_BASE(dir,type,nr,size) \
|
||||
(((dir) << 30) | \
|
||||
((size) << 16) | \
|
||||
((type) << 8) | \
|
||||
((nr) << 0))
|
||||
|
||||
/*
|
||||
* Macros to encode ioctl numbers.
|
||||
*/
|
||||
#define DC_IOCTL_IO(type,nr) DC_IOCTL_BASE(DC_IOCTL_DIR_NONE, (type), (nr), 0)
|
||||
#define DC_IOCTL_IOR(type,nr,size) DC_IOCTL_BASE(DC_IOCTL_DIR_READ, (type), (nr), (size))
|
||||
#define DC_IOCTL_IOW(type,nr,size) DC_IOCTL_BASE(DC_IOCTL_DIR_WRITE, (type), (nr), (size))
|
||||
#define DC_IOCTL_IORW(type,nr,size) DC_IOCTL_BASE(DC_IOCTL_DIR_READ | DC_IOCTL_DIR_WRITE, (type), (nr), (size))
|
||||
|
||||
/*
|
||||
* Macros to decode ioctl numbers.
|
||||
*/
|
||||
#define DC_IOCTL_DIR(request) (((request) >> 30) & 0x0003)
|
||||
#define DC_IOCTL_SIZE(request) (((request) >> 16) & 0x3FFF)
|
||||
#define DC_IOCTL_TYPE(request) (((request) >> 8) & 0x00FF)
|
||||
#define DC_IOCTL_NR(request) (((request) >> 0) & 0x00FF)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* DC_IOCTL_H */
|
||||
@ -269,6 +269,19 @@ dc_iostream_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actu
|
||||
dc_status_t
|
||||
dc_iostream_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual);
|
||||
|
||||
/**
|
||||
* Perform an I/O stream specific request.
|
||||
*
|
||||
* @param[in] iostream A valid I/O stream.
|
||||
* @param[in] request The request to perform.
|
||||
* @param[in,out] data The request specific data.
|
||||
* @param[in] size The size of the request specific data.
|
||||
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
|
||||
* on failure.
|
||||
*/
|
||||
dc_status_t
|
||||
dc_iostream_ioctl (dc_iostream_t *iostream, unsigned int request, void *data, size_t size);
|
||||
|
||||
/**
|
||||
* Flush the internal output buffer and wait until the data has been
|
||||
* transmitted.
|
||||
|
||||
@ -109,6 +109,7 @@ static const dc_iostream_vtable_t dc_bluetooth_vtable = {
|
||||
dc_socket_poll, /* poll */
|
||||
dc_socket_read, /* read */
|
||||
dc_socket_write, /* write */
|
||||
dc_socket_ioctl, /* ioctl */
|
||||
NULL, /* flush */
|
||||
NULL, /* purge */
|
||||
dc_socket_sleep, /* sleep */
|
||||
|
||||
13
src/custom.c
13
src/custom.c
@ -38,6 +38,7 @@ static dc_status_t dc_custom_configure (dc_iostream_t *abstract, unsigned int ba
|
||||
static dc_status_t dc_custom_poll (dc_iostream_t *abstract, int timeout);
|
||||
static dc_status_t dc_custom_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual);
|
||||
static dc_status_t dc_custom_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual);
|
||||
static dc_status_t dc_custom_ioctl (dc_iostream_t *abstract, unsigned int request, void *data, size_t size);
|
||||
static dc_status_t dc_custom_flush (dc_iostream_t *abstract);
|
||||
static dc_status_t dc_custom_purge (dc_iostream_t *abstract, dc_direction_t direction);
|
||||
static dc_status_t dc_custom_sleep (dc_iostream_t *abstract, unsigned int milliseconds);
|
||||
@ -64,6 +65,7 @@ static const dc_iostream_vtable_t dc_custom_vtable = {
|
||||
dc_custom_poll, /* poll */
|
||||
dc_custom_read, /* read */
|
||||
dc_custom_write, /* write */
|
||||
dc_custom_ioctl, /* ioctl */
|
||||
dc_custom_flush, /* flush */
|
||||
dc_custom_purge, /* purge */
|
||||
dc_custom_sleep, /* sleep */
|
||||
@ -216,6 +218,17 @@ dc_custom_write (dc_iostream_t *abstract, const void *data, size_t size, size_t
|
||||
return custom->callbacks.write (custom->userdata, data, size, actual);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_custom_ioctl (dc_iostream_t *abstract, unsigned int request, void *data, size_t size)
|
||||
{
|
||||
dc_custom_t *custom = (dc_custom_t *) abstract;
|
||||
|
||||
if (custom->callbacks.ioctl == NULL)
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
return custom->callbacks.ioctl (custom->userdata, request, data, size);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_custom_flush (dc_iostream_t *abstract)
|
||||
{
|
||||
|
||||
@ -63,6 +63,8 @@ struct dc_iostream_vtable_t {
|
||||
|
||||
dc_status_t (*write) (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual);
|
||||
|
||||
dc_status_t (*ioctl) (dc_iostream_t *iostream, unsigned int request, void *data, size_t size);
|
||||
|
||||
dc_status_t (*flush) (dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t (*purge) (dc_iostream_t *iostream, dc_direction_t direction);
|
||||
|
||||
@ -23,6 +23,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <libdivecomputer/ioctl.h>
|
||||
|
||||
#include "iostream-private.h"
|
||||
#include "context-private.h"
|
||||
#include "platform.h"
|
||||
@ -236,6 +238,40 @@ out:
|
||||
return status;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_iostream_ioctl (dc_iostream_t *iostream, unsigned int request, void *data, size_t size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
|
||||
if (iostream == NULL || iostream->vtable->ioctl == NULL)
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
// The size should match the size encoded in the ioctl request,
|
||||
// unless it's a variable size request.
|
||||
if (size != DC_IOCTL_SIZE(request) &&
|
||||
!(DC_IOCTL_DIR(request) != DC_IOCTL_DIR_NONE && DC_IOCTL_SIZE(request) == 0)) {
|
||||
ERROR (iostream->context, "Invalid size for ioctl request 0x%08x (" DC_PRINTF_SIZE ").", request, size);
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
INFO (iostream->context, "Ioctl: request=0x%08x (dir=%u, type=%u, nr=%u, size=%u)",
|
||||
request,
|
||||
DC_IOCTL_DIR(request), DC_IOCTL_TYPE(request),
|
||||
DC_IOCTL_NR(request), DC_IOCTL_SIZE(request));
|
||||
|
||||
if (DC_IOCTL_DIR(request) & DC_IOCTL_DIR_WRITE) {
|
||||
HEXDUMP (iostream->context, DC_LOGLEVEL_INFO, "Ioctl write", (unsigned char *) data, size);
|
||||
}
|
||||
|
||||
status = iostream->vtable->ioctl (iostream, request, data, size);
|
||||
|
||||
if (DC_IOCTL_DIR(request) & DC_IOCTL_DIR_READ) {
|
||||
HEXDUMP (iostream->context, DC_LOGLEVEL_INFO, "Ioctl read", (unsigned char *) data, size);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_iostream_flush (dc_iostream_t *iostream)
|
||||
{
|
||||
|
||||
@ -101,6 +101,7 @@ static const dc_iostream_vtable_t dc_irda_vtable = {
|
||||
dc_socket_poll, /* poll */
|
||||
dc_socket_read, /* read */
|
||||
dc_socket_write, /* write */
|
||||
dc_socket_ioctl, /* ioctl */
|
||||
NULL, /* flush */
|
||||
NULL, /* purge */
|
||||
dc_socket_sleep, /* sleep */
|
||||
|
||||
@ -46,6 +46,7 @@ dc_iostream_configure
|
||||
dc_iostream_poll
|
||||
dc_iostream_read
|
||||
dc_iostream_write
|
||||
dc_iostream_ioctl
|
||||
dc_iostream_flush
|
||||
dc_iostream_purge
|
||||
dc_iostream_sleep
|
||||
|
||||
@ -77,6 +77,7 @@ static dc_status_t dc_serial_configure (dc_iostream_t *iostream, unsigned int ba
|
||||
static dc_status_t dc_serial_poll (dc_iostream_t *iostream, int timeout);
|
||||
static dc_status_t dc_serial_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual);
|
||||
static dc_status_t dc_serial_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual);
|
||||
static dc_status_t dc_serial_ioctl (dc_iostream_t *iostream, unsigned int request, void *data, size_t size);
|
||||
static dc_status_t dc_serial_flush (dc_iostream_t *iostream);
|
||||
static dc_status_t dc_serial_purge (dc_iostream_t *iostream, dc_direction_t direction);
|
||||
static dc_status_t dc_serial_sleep (dc_iostream_t *iostream, unsigned int milliseconds);
|
||||
@ -127,6 +128,7 @@ static const dc_iostream_vtable_t dc_serial_vtable = {
|
||||
dc_serial_poll, /* poll */
|
||||
dc_serial_read, /* read */
|
||||
dc_serial_write, /* write */
|
||||
dc_serial_ioctl, /* ioctl */
|
||||
dc_serial_flush, /* flush */
|
||||
dc_serial_purge, /* purge */
|
||||
dc_serial_sleep, /* sleep */
|
||||
@ -849,6 +851,12 @@ out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_serial_ioctl (dc_iostream_t *abstract, unsigned int request, void *data, size_t size)
|
||||
{
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_serial_purge (dc_iostream_t *abstract, dc_direction_t direction)
|
||||
{
|
||||
|
||||
@ -46,6 +46,7 @@ static dc_status_t dc_serial_configure (dc_iostream_t *iostream, unsigned int ba
|
||||
static dc_status_t dc_serial_poll (dc_iostream_t *iostream, int timeout);
|
||||
static dc_status_t dc_serial_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual);
|
||||
static dc_status_t dc_serial_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual);
|
||||
static dc_status_t dc_serial_ioctl (dc_iostream_t *iostream, unsigned int request, void *data, size_t size);
|
||||
static dc_status_t dc_serial_flush (dc_iostream_t *iostream);
|
||||
static dc_status_t dc_serial_purge (dc_iostream_t *iostream, dc_direction_t direction);
|
||||
static dc_status_t dc_serial_sleep (dc_iostream_t *iostream, unsigned int milliseconds);
|
||||
@ -102,6 +103,7 @@ static const dc_iostream_vtable_t dc_serial_vtable = {
|
||||
dc_serial_poll, /* poll */
|
||||
dc_serial_read, /* read */
|
||||
dc_serial_write, /* write */
|
||||
dc_serial_ioctl, /* ioctl */
|
||||
dc_serial_flush, /* flush */
|
||||
dc_serial_purge, /* purge */
|
||||
dc_serial_sleep, /* sleep */
|
||||
@ -682,6 +684,12 @@ out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_serial_ioctl (dc_iostream_t *abstract, unsigned int request, void *data, size_t size)
|
||||
{
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_serial_purge (dc_iostream_t *abstract, dc_direction_t direction)
|
||||
{
|
||||
|
||||
@ -330,6 +330,12 @@ out:
|
||||
return status;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_socket_ioctl (dc_iostream_t *abstract, unsigned int request, void *data, size_t size)
|
||||
{
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_socket_sleep (dc_iostream_t *abstract, unsigned int timeout)
|
||||
{
|
||||
|
||||
@ -117,6 +117,9 @@ dc_socket_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual
|
||||
dc_status_t
|
||||
dc_socket_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual);
|
||||
|
||||
dc_status_t
|
||||
dc_socket_ioctl (dc_iostream_t *iostream, unsigned int request, void *data, size_t size);
|
||||
|
||||
dc_status_t
|
||||
dc_socket_sleep (dc_iostream_t *abstract, unsigned int timeout);
|
||||
|
||||
|
||||
@ -97,6 +97,7 @@ static dc_status_t dc_usbhid_set_timeout (dc_iostream_t *iostream, int timeout);
|
||||
static dc_status_t dc_usbhid_poll (dc_iostream_t *iostream, int timeout);
|
||||
static dc_status_t dc_usbhid_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual);
|
||||
static dc_status_t dc_usbhid_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual);
|
||||
static dc_status_t dc_usbhid_ioctl (dc_iostream_t *iostream, unsigned int request, void *data, size_t size);
|
||||
static dc_status_t dc_usbhid_close (dc_iostream_t *iostream);
|
||||
|
||||
typedef struct dc_usbhid_iterator_t {
|
||||
@ -148,6 +149,7 @@ static const dc_iostream_vtable_t dc_usbhid_vtable = {
|
||||
dc_usbhid_poll, /* poll */
|
||||
dc_usbhid_read, /* read */
|
||||
dc_usbhid_write, /* write */
|
||||
dc_usbhid_ioctl, /* ioctl */
|
||||
NULL, /* flush */
|
||||
NULL, /* purge */
|
||||
NULL, /* sleep */
|
||||
@ -781,4 +783,10 @@ out:
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_usbhid_ioctl (dc_iostream_t *abstract, unsigned int request, void *data, size_t size)
|
||||
{
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user