drivers: can: fix multiple issues

* Registration of interrupt context callbacks from user mode
  is forbidden.

  - Remove can_attach_isr() as a system call
  - Enforce that can_send() has a NULL callback parameter

* k_msgq are kernel objects that do not live in user memory.
  Fix the checks for it in can_attach_msgq().

* CAN API documentation was with the API struct typedefs and
  not the actual APIs. Moved.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2019-03-08 10:14:57 -08:00 committed by Anas Nashif
commit 26085d9570
2 changed files with 85 additions and 104 deletions

View file

@ -23,6 +23,8 @@ Z_SYSCALL_HANDLER(can_send, dev, msg, timeout, callback_isr) {
sizeof(struct zcan_frame)));
Z_OOPS(Z_SYSCALL_MEMORY_READ(((struct zcan_frame *)msg)->data,
sizeof((struct zcan_frame *)msg)->data));
Z_OOPS(Z_SYSCALL_VERIFY_MSG(callback_isr == 0,
"callbacks may not be set from user mode"));
return _impl_can_send((struct device *)dev,
(const struct zcan_frame *)msg,
@ -35,29 +37,13 @@ Z_SYSCALL_HANDLER(can_attach_msgq, dev, msgq, filter) {
Z_OOPS(Z_SYSCALL_MEMORY_READ((struct zcan_filter *)filter,
sizeof(struct zcan_filter)));
Z_OOPS(Z_SYSCALL_MEMORY_WRITE((struct k_msgq *)msgq,
sizeof(struct k_msgq)));
Z_OOPS(Z_SYSCALL_MEMORY_WRITE(((struct k_msgq *)msgq)->buffer_start,
((struct k_msgq *)msgq)->buffer_end -
((struct k_msgq *)msgq)->buffer_start));
Z_OOPS(Z_SYSCALL_OBJ(msgq, K_OBJ_MSGQ));
return _impl_can_attach_msgq((struct device *)dev,
(struct k_msgq *)msgq,
(const struct zcan_filter *) filter);
}
Z_SYSCALL_HANDLER(can_attach_isr, dev, isr, filter) {
Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, attach_isr));
Z_OOPS(Z_SYSCALL_MEMORY_READ((struct zcan_filter *)filter,
sizeof(struct zcan_filter)));
return _impl_can_attach_isr((struct device *)dev,
(can_rx_callback_t)isr,
(const struct zcan_filter *) filter);
}
Z_SYSCALL_HANDLER(can_detach, dev, filter_id) {
Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, detach));

View file

@ -216,19 +216,29 @@ typedef void (*can_tx_callback_t)(u32_t error_flags);
*/
typedef void (*can_rx_callback_t)(struct zcan_frame *msg);
/**
* @brief Configure operation of a host controller.
*
* @param dev Pointer to the device structure for the driver instance.
* @param mode Operation mode
* @param bitrate bus-speed in Baud/s
*
* @retval 0 If successful.
* @retval -EIO General input / output error, failed to configure device.
*/
typedef int (*can_configure_t)(struct device *dev, enum can_mode mode,
u32_t bitrate);
typedef int (*can_send_t)(struct device *dev, const struct zcan_frame *msg,
s32_t timeout, can_tx_callback_t callback_isr);
typedef int (*can_attach_msgq_t)(struct device *dev, struct k_msgq *msg_q,
const struct zcan_filter *filter);
typedef int (*can_attach_isr_t)(struct device *dev, can_rx_callback_t isr,
const struct zcan_filter *filter);
typedef void (*can_detach_t)(struct device *dev, int filter_id);
struct can_driver_api {
can_configure_t configure;
can_send_t send;
can_attach_isr_t attach_isr;
can_attach_msgq_t attach_msgq;
can_detach_t detach;
};
/**
* @brief Perform data transfer to CAN bus.
*
@ -239,80 +249,13 @@ typedef int (*can_configure_t)(struct device *dev, enum can_mode mode,
* @param msg Message to transfer.
* @param timeout Waiting for empty tx mailbox timeout in ms or K_FOREVER.
* @param callback_isr Is called when message was sent or a transmission error
* occurred. If null, this function is blocking until
* message is sent.
* occurred. If NULL, this function is blocking until
* message is sent. This must be NULL if called from user
* mode.
*
* @retval 0 If successful.
* @retval CAN_TX_* on failure.
*/
typedef int (*can_send_t)(struct device *dev, const struct zcan_frame *msg,
s32_t timeout, can_tx_callback_t callback_isr);
/**
* @brief Attach a message queue to a single or group of identifiers.
*
* This routine attaches a message queue to identifiers specified by
* a filter. Whenever the filter matches, the message is pushed to the queue
* If a message passes more than one filter the priority of the match
* is hardware dependent.
* A message queue can be attached to more than one filter.
* The message queue must me initialized before.
* *
* @param dev Pointer to the device structure for the driver instance.
* @param msgq Pointer to the already initialized message queue.
* @param filter Pointer to a zcan_filter structure defining the id
* filtering.
*
* @retval filter id on success.
* @retval CAN_NO_FREE_FILTER if there is no filter left.
*/
typedef int (*can_attach_msgq_t)(struct device *dev, struct k_msgq *msg_q,
const struct zcan_filter *filter);
/**
* @brief Attach an isr callback function to a single or group of identifiers.
*
* This routine attaches an isr callback to identifiers specified by
* a filter. Whenever the filter matches, the callback function is called
* with isr context.
* If a message passes more than one filter the priority of the match
* is hardware dependent.
* A callback function can be attached to more than one filter.
* *
* @param dev Pointer to the device structure for the driver instance.
* @param isr Callback function pointer.
* @param filter Pointer to a zcan_filter structure defining the id
* filtering.
*
* @retval filter id on success.
* @retval CAN_NO_FREE_FILTER if there is no filter left.
*/
typedef int (*can_attach_isr_t)(struct device *dev, can_rx_callback_t isr,
const struct zcan_filter *filter);
/**
* @brief Detach an isr or message queue from the identifier filtering.
*
* This routine detaches an isr callback or message queue from the identifier
* filtering.
* *
* @param dev Pointer to the device structure for the driver instance.
* @param filter_id filter id returned by can_attach_isr or can_attach_msgq.
*
* @retval none
*/
typedef void (*can_detach_t)(struct device *dev, int filter_id);
struct can_driver_api {
can_configure_t configure;
can_send_t send;
can_attach_isr_t attach_isr;
can_attach_msgq_t attach_msgq;
can_detach_t detach;
};
__syscall int can_send(struct device *dev, const struct zcan_frame *msg,
s32_t timeout, can_tx_callback_t callback_isr);
@ -369,7 +312,25 @@ static inline int can_write(struct device *dev, const u8_t *data, u8_t length,
return can_send(dev, &msg, timeout, NULL);
}
/**
* @brief Attach a message queue to a single or group of identifiers.
*
* This routine attaches a message queue to identifiers specified by
* a filter. Whenever the filter matches, the message is pushed to the queue
* If a message passes more than one filter the priority of the match
* is hardware dependent.
* A message queue can be attached to more than one filter.
* The message queue must me initialized before, and the caller must have
* appropriate permissions on it.
*
* @param dev Pointer to the device structure for the driver instance.
* @param msg_q Pointer to the already initialized message queue.
* @param filter Pointer to a zcan_filter structure defining the id
* filtering.
*
* @retval filter id on success.
* @retval CAN_NO_FREE_FILTER if there is no filter left.
*/
__syscall int can_attach_msgq(struct device *dev, struct k_msgq *msg_q,
const struct zcan_filter *filter);
@ -382,10 +343,25 @@ static inline int _impl_can_attach_msgq(struct device *dev,
return api->attach_msgq(dev, msg_q, filter);
}
__syscall int can_attach_isr(struct device *dev, can_rx_callback_t isr,
const struct zcan_filter *filter);
static inline int _impl_can_attach_isr(struct device *dev,
/**
* @brief Attach an isr callback function to a single or group of identifiers.
*
* This routine attaches an isr callback to identifiers specified by
* a filter. Whenever the filter matches, the callback function is called
* with isr context.
* If a message passes more than one filter the priority of the match
* is hardware dependent.
* A callback function can be attached to more than one filter.
* *
* @param dev Pointer to the device structure for the driver instance.
* @param isr Callback function pointer.
* @param filter Pointer to a zcan_filter structure defining the id
* filtering.
*
* @retval filter id on success.
* @retval CAN_NO_FREE_FILTER if there is no filter left.
*/
static inline int can_attach_isr(struct device *dev,
can_rx_callback_t isr,
const struct zcan_filter *filter)
{
@ -394,7 +370,17 @@ static inline int _impl_can_attach_isr(struct device *dev,
return api->attach_isr(dev, isr, filter);
}
/**
* @brief Detach an isr or message queue from the identifier filtering.
*
* This routine detaches an isr callback or message queue from the identifier
* filtering.
* *
* @param dev Pointer to the device structure for the driver instance.
* @param filter_id filter id returned by can_attach_isr or can_attach_msgq.
*
* @retval none
*/
__syscall void can_detach(struct device *dev, int filter_id);
static inline void _impl_can_detach(struct device *dev, int filter_id)
@ -404,7 +390,16 @@ static inline void _impl_can_detach(struct device *dev, int filter_id)
return api->detach(dev, filter_id);
}
/**
* @brief Configure operation of a host controller.
*
* @param dev Pointer to the device structure for the driver instance.
* @param mode Operation mode
* @param bitrate bus-speed in Baud/s
*
* @retval 0 If successful.
* @retval -EIO General input / output error, failed to configure device.
*/
__syscall int can_configure(struct device *dev, enum can_mode mode,
u32_t bitrate);