Compare commits
6 Commits
4841b2863c
...
7158af4b73
| Author | SHA1 | Date |
|---|---|---|
|
|
7158af4b73 | |
|
|
d66977868f | |
|
|
9dd9a74b9e | |
|
|
760b9d8e34 | |
|
|
c888a206d9 | |
|
|
b69aaf12ab |
159
intrepid.c
159
intrepid.c
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue