Compare commits

..

6 Commits

Author SHA1 Message Date
Christian Gabriel 7158af4b73 3.1.0
Signed-off-by: Christian Gabriel <ch_gabriel@web.de>
2024-07-23 15:22:00 -04:00
Christian Gabriel d66977868f fix: Set CAN state to ERROR_ACTIVE, init supported
Signed-off-by: Christian Gabriel <ch_gabriel@web.de>
2024-07-23 15:22:00 -04:00
Christian Gabriel 9dd9a74b9e Add support for bitrate setting
Allow userspace daemon to report currently set bitrates via ioctl.
Also allow setting bitrates via kernel interfaces and report the
new bitrates to userspace daemon

Signed-off-by: Christian Gabriel <ch_gabriel@web.de>
2024-07-23 15:22:00 -04:00
Christian Gabriel 760b9d8e34 Add compile-time size checks to neomessage sizes
All versions of the struct need to be the same size. Ensure they are.

Signed-off-by: Christian Gabriel <ch_gabriel@web.de>
2024-07-23 15:22:00 -04:00
Christian Gabriel c888a206d9 Save client version
This allows to use old daemons with new versions of the driver
which do not support newer features yet

Signed-off-by: Christian Gabriel <ch_gabriel@web.de>
2024-07-23 15:21:43 -04:00
Christian Gabriel b69aaf12ab Add can_priv to intrepid_netdevice
For CAN network devices, the kernel expects struct can_priv as first
member of netdev_priv.

Signed-off-by: Christian Gabriel <ch_gabriel@web.de>
2024-07-23 15:21:43 -04:00
1 changed files with 156 additions and 3 deletions

View File

@ -57,8 +57,8 @@
#define KO_DESC "Netdevice driver for Intrepid CAN/Ethernet devices"
#define KO_MAJOR 3
#define KO_MINOR 0
#define KO_PATCH 4
#define KO_MINOR 1
#define KO_PATCH 0
#define KO_VERSION str(KO_MAJOR) "." str(KO_MINOR) "." str(KO_PATCH)
#define KO_VERSION_INT (KO_MAJOR << 16) | (KO_MINOR << 8) | KO_PATCH
@ -86,6 +86,7 @@ MODULE_VERSION(KO_VERSION);
#define SIOCGMAXIFACES 0x3007
#define SIOCGVERSION 0x3008
#define SIOCGCLIENTVEROK 0x3009
#define SIOCSBAUDRATE 0x300A
/* This is true until we have Ethernet support
* It is used to stop the netif queues before we have to return NETDEV_TX_BUSY
@ -108,15 +109,18 @@ struct intrepid_pending_tx_info {
};
struct intrepid_netdevice {
struct can_priv can;
struct net_device *dev;
spinlock_t lock;
int is_stopped;
unsigned char *from_user;
uint8_t tx_idx;
int bitrate_changed;
};
static int is_open;
static int major_number;
static int client_version;
static unsigned char *shared_mem;
static struct class *intrepid_dev_class;
static struct device *intrepid_dev;
@ -417,6 +421,68 @@ static int intrepid_remove_can_if(int index)
return 0;
}
static int intrepid_set_bittiming(struct net_device *netdev)
{
struct intrepid_netdevice *dev = netdev_priv(netdev);
struct can_bittiming *bt = &dev->can.bittiming;
dev_dbg(&netdev->dev, "bitrate %d sample_point %d tq %d sjw %d phase1 %d phase2 %d prop %d brp %d",
bt->bitrate, bt->sample_point, bt->tq, bt->sjw, bt->phase_seg1, bt->phase_seg2, bt->prop_seg, bt->brp);
dev->bitrate_changed = 1;
wake_up_interruptible(&tx_wait);
return 0;
}
static int intrepid_set_data_bittiming(struct net_device *netdev)
{
struct intrepid_netdevice *dev = netdev_priv(netdev);
struct can_bittiming *bt = &dev->can.data_bittiming;
dev_dbg(&netdev->dev, "bitrate %d sample_point %d tq %d sjw %d phase1 %d phase2 %d prop %d brp %d",
bt->bitrate, bt->sample_point, bt->tq, bt->sjw, bt->phase_seg1, bt->phase_seg2, bt->prop_seg, bt->brp);
dev->bitrate_changed = 1;
wake_up_interruptible(&tx_wait);
return 0;
}
static int intrepid_bitrates[] = {
20000,
33000,
50000,
62000,
83000,
100000,
125000,
250000,
500000,
666000,
800000,
1000000
};
static int intrepid_data_bitrates[] = {
20000,
33000,
50000,
62000,
83000,
100000,
125000,
250000,
500000,
666000,
800000,
1000000,
2000000,
4000000,
5000000,
6667000,
8000000,
10000000
};
static int intrepid_add_can_if(struct intrepid_netdevice **result, const char *requestedName)
{
// The `requestedName` parameter is always NULL if KERNEL_SUPPORTS_ALIASES is false
@ -472,6 +538,17 @@ static int intrepid_add_can_if(struct intrepid_netdevice **result, const char *r
ics->from_user = GET_RX_BOX(i); /* incoming rx messages */
ics->tx_idx = 0;
if (VER_MIN_FROM_INT(client_version) > 1) {
ics->can.bitrate_const = intrepid_bitrates;
ics->can.bitrate_const_cnt = ARRAY_SIZE(intrepid_bitrates);
ics->can.data_bitrate_const = intrepid_data_bitrates;
ics->can.data_bitrate_const_cnt = ARRAY_SIZE(intrepid_data_bitrates);
ics->can.do_set_bittiming = intrepid_set_bittiming;
ics->can.do_set_data_bittiming = intrepid_set_data_bittiming;
}
ics->can.state = CAN_STATE_ERROR_ACTIVE;
ics->can.ctrlmode_supported = CAN_CTRLMODE_FD;
spin_lock_init(&ics->lock);
ret = register_candev(dev);
@ -945,6 +1022,22 @@ static long intrepid_dev_ioctl(struct file *fp, unsigned int cmd, unsigned long
case SIOCSREMOVECANIF:
ret = intrepid_remove_can_if (arg);
break;
case SIOCSBAUDRATE: {
struct baudrate_info {
int handle;
int64_t baudrates[2];
} info;
ret = copy_from_user(&info, (void __user*)arg, sizeof(info));
if (ret)
break;
struct net_device *device = intrepid_get_dev_by_index(info.handle);
if (device == NULL)
break;
struct intrepid_netdevice *ics = netdev_priv(device);
ics->can.bittiming.bitrate = info.baudrates[0];
ics->can.data_bittiming.bitrate = info.baudrates[1];
break;
}
case SIOCSADDETHIF: {
struct intrepid_netdevice *result = NULL;
#if KERNEL_SUPPORTS_ALIASES
@ -976,7 +1069,8 @@ static long intrepid_dev_ioctl(struct file *fp, unsigned int cmd, unsigned long
ret = KO_VERSION_INT;
break;
case SIOCGCLIENTVEROK:
if (VER_MAJ_FROM_INT(arg) == 3 && VER_MIN_FROM_INT(arg) == 1 && VER_PATCH_FROM_INT(arg) >= 0)
client_version = arg;
if (VER_MAJ_FROM_INT(arg) == 3 && VER_MIN_FROM_INT(arg) >= 1 && VER_PATCH_FROM_INT(arg) >= 0)
ret = 0; /* ok to start */
else
ret = 1;
@ -1053,6 +1147,33 @@ static int intrepid_dev_release(struct inode *ip, struct file *fp)
return 0;
}
/* Re-use the pending_tx_info struct to send changed bitrates to userland
* Set the box index to -(dev_id) and encode the rest of the data in the count
* and bytes fields.
* count is the bitrate value
* bytes is the data bitrate value. */
static int check_bitrate_change(struct intrepid_pending_tx_info *info)
{
int i;
struct intrepid_netdevice *ics;
for (i = 0; i < MAX_NET_DEVICES; i++) {
if (net_devices[i] == NULL || net_devices[i]->type != ARPHRD_CAN)
continue;
ics = netdev_priv(net_devices[i]);
if (ics->bitrate_changed) {
info->tx_box_index = -(i + 1);
info->count = ics->can.bittiming.bitrate;
info->bytes = ics->can.data_bittiming.bitrate;
ics->bitrate_changed = 0;
return 1;
}
}
return 0;
}
/* usermode uses read() to get the current size of the tx buffer. we use a ping pong buffer
* so the user doesn't have to worry about the data changing out from under them while
* still avoiding a full copy to user. the ping pong flips on every call to this func */
@ -1064,6 +1185,15 @@ static ssize_t intrepid_dev_read(struct file *fp, char *buffer, size_t len, loff
if (len < sizeof(info))
return -EFAULT;
/* check if we have to send a bitrate change */
if (VER_MIN_FROM_INT(client_version) > 1) {
if (check_bitrate_change(&info)) {
if (copy_to_user(buffer, &info, sizeof(info)))
return -EFAULT;
return sizeof(info);
}
}
spin_lock_bh(&tx_box_lock);
/* fill out the info for the user */
@ -1098,6 +1228,18 @@ static unsigned int intrepid_dev_poll(struct file *fp, poll_table *wait)
if (tx_box_count[current_tx_box] > 0)
return POLLIN | POLLRDNORM;
if (VER_MIN_FROM_INT(client_version) > 1) {
int i;
for (i = 0; i < MAX_NET_DEVICES; i++) {
if (net_devices[i] == NULL || net_devices[i]->type != ARPHRD_CAN)
continue;
struct intrepid_netdevice *ics = netdev_priv(net_devices[i]);
if (ics->bitrate_changed)
return POLLIN | POLLRDNORM;
}
}
return 0;
}
@ -1115,6 +1257,17 @@ static __init int intrepid_init(void)
int ret;
pr_info("intrepid: %s %s\n", KO_DESC, KO_VERSION);
BUILD_BUG_ON_MSG(sizeof(neomessage_t) != (56 + sizeof(void*) + sizeof(size_t)),
"neomessage_t size is incorrect!");
BUILD_BUG_ON_MSG(sizeof(neomessage_frame_t) != sizeof(neomessage_t),
"All types of neomessage_t must be the same size! (Base frame is not)");
BUILD_BUG_ON_MSG(sizeof(neomessage_can_t) != sizeof(neomessage_t),
"All types of neomessage_t must be the same size! (CAN is not)");
BUILD_BUG_ON_MSG(sizeof(neomessage_can_error_t) != sizeof(neomessage_t),
"All types of neomessage_t must be the same size! (CAN error is not)");
BUILD_BUG_ON_MSG(sizeof(neomessage_eth_t) != sizeof(neomessage_t),
"All types of neomessage_t must be the same size! (Ethernet is not)");
is_open = 0;
/* this is the shared memory used to transfer between us and the user daemon */