/* * initialize a time_ref object with usb adapter own settings
*/ void peak_usb_init_time_ref(struct peak_time_ref *time_ref, conststruct peak_usb_adapter *adapter)
{ if (time_ref) {
memset(time_ref, 0, sizeof(struct peak_time_ref));
time_ref->adapter = adapter;
}
}
/* * sometimes, another now may be more recent than current one...
*/ void peak_usb_update_ts_now(struct peak_time_ref *time_ref, u32 ts_now)
{
time_ref->ts_dev_2 = ts_now;
/* should wait at least two passes before computing */ if (ktime_to_ns(time_ref->tv_host) > 0) {
u32 delta_ts = time_ref->ts_dev_2 - time_ref->ts_dev_1;
/* * compute time according to current ts and time_ref data
*/ void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *time)
{ /* protect from getting time before setting now */ if (ktime_to_ns(time_ref->tv_host)) {
u64 delta_us;
s64 delta_ts = 0;
/* General case: dev_ts_1 < dev_ts_2 < ts, with: * * - dev_ts_1 = previous sync timestamp * - dev_ts_2 = last sync timestamp * - ts = event timestamp * - ts_period = known sync period (theoretical) * ~ dev_ts2 - dev_ts1 * *but*: * * - time counters wrap (see adapter->ts_used_bits) * - sometimes, dev_ts_1 < ts < dev_ts2 * * "normal" case (sync time counters increase): * must take into account case when ts wraps (tsw) * * < ts_period > < > * | | | * ---+--------+----+-------0-+--+--> * ts_dev_1 | ts_dev_2 | * ts tsw
*/ if (time_ref->ts_dev_1 < time_ref->ts_dev_2) { /* case when event time (tsw) wraps */ if (ts < time_ref->ts_dev_1)
delta_ts = BIT_ULL(time_ref->adapter->ts_used_bits);
/* Otherwise, sync time counter (ts_dev_2) has wrapped: * handle case when event time (tsn) hasn't. * * < ts_period > < > * | | | * ---+--------+--0-+---------+--+--> * ts_dev_1 | ts_dev_2 | * tsn ts
*/
} elseif (time_ref->ts_dev_1 < ts) {
delta_ts = -BIT_ULL(time_ref->adapter->ts_used_bits);
}
/* add delay between last sync and event timestamps */
delta_ts += (signedint)(ts - time_ref->ts_dev_2);
/* add time from beginning to last sync */
delta_ts += time_ref->ts_total;
/* convert ticks number into microseconds */
delta_us = delta_ts * time_ref->adapter->us_per_ts_scale;
delta_us >>= time_ref->adapter->us_per_ts_shift;
/* protect from any incoming empty msgs */ if ((urb->actual_length > 0) && (dev->adapter->dev_decode_buf)) { /* handle these kinds of msgs only if _start callback called */ if (dev->state & PCAN_USB_STATE_STARTED) {
err = dev->adapter->dev_decode_buf(dev, urb); if (err)
pcan_dump_mem("received usb message",
urb->transfer_buffer,
urb->transfer_buffer_length);
}
}
/* slow down tx path */ if (atomic_read(&dev->active_tx_urbs) >= PCAN_USB_MAX_TX_URBS)
netif_stop_queue(netdev);
}
return NETDEV_TX_OK;
}
/* * start the CAN interface. * Rx and Tx urbs are allocated here. Rx urbs are submitted here.
*/ staticint peak_usb_start(struct peak_usb_device *dev)
{ struct net_device *netdev = dev->netdev; int err, i;
for (i = 0; i < PCAN_USB_MAX_RX_URBS; i++) { struct urb *urb;
u8 *buf;
/* create a URB, and a buffer for it, to receive usb messages */
urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) {
err = -ENOMEM; break;
}
/* drop reference, USB core will take care of freeing it */
usb_free_urb(urb);
}
/* did we submit any URBs? Warn if we was not able to submit all urbs */ if (i < PCAN_USB_MAX_RX_URBS) { if (i == 0) {
netdev_err(netdev, "couldn't setup any rx URB\n"); return err;
}
netdev_warn(netdev, "rx performance may be slow\n");
}
/* pre-alloc tx buffers and corresponding urbs */ for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) { struct peak_tx_urb_context *context; struct urb *urb;
u8 *buf;
/* create a URB and a buffer for it, to transmit usb messages */
urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) {
err = -ENOMEM; break;
}
/* ask last usb_free_urb() to also kfree() transfer_buffer */
urb->transfer_flags |= URB_FREE_BUFFER;
}
/* warn if we were not able to allocate enough tx contexts */ if (i < PCAN_USB_MAX_TX_URBS) { if (i == 0) {
netdev_err(netdev, "couldn't setup any tx URB\n"); goto err_tx;
}
netdev_warn(netdev, "tx performance may be slow\n");
}
if (dev->adapter->dev_start) {
err = dev->adapter->dev_start(dev); if (err) goto err_adapter;
}
dev->state |= PCAN_USB_STATE_STARTED;
/* can set bus on now */ if (dev->adapter->dev_set_bus) {
err = dev->adapter->dev_set_bus(dev, 1); if (err) goto err_adapter;
}
dev->can.state = CAN_STATE_ERROR_ACTIVE;
return 0;
err_adapter: if (err == -ENODEV)
netif_device_detach(dev->netdev);
for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) {
usb_free_urb(dev->tx_contexts[i].urb);
dev->tx_contexts[i].urb = NULL;
}
err_tx:
usb_kill_anchored_urbs(&dev->rx_submitted);
return err;
}
/* * called by netdev to open the corresponding CAN interface.
*/ staticint peak_usb_ndo_open(struct net_device *netdev)
{ struct peak_usb_device *dev = netdev_priv(netdev); int err;
/* common open */
err = open_candev(netdev); if (err) return err;
/* * unlink in-flight Rx and Tx urbs and free their memory.
*/ staticvoid peak_usb_unlink_all_urbs(struct peak_usb_device *dev)
{ int i;
/* free all Rx (submitted) urbs */
usb_kill_anchored_urbs(&dev->rx_submitted);
/* free unsubmitted Tx urbs first */ for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) { struct urb *urb = dev->tx_contexts[i].urb;
if (!urb ||
dev->tx_contexts[i].echo_index != PCAN_USB_MAX_TX_URBS) { /* * this urb is already released or always submitted, * let usb core free by itself
*/ continue;
}
/* then free all submitted Tx urbs */
usb_kill_anchored_urbs(&dev->tx_submitted);
atomic_set(&dev->active_tx_urbs, 0);
}
/* * called by netdev to close the corresponding CAN interface.
*/ staticint peak_usb_ndo_stop(struct net_device *netdev)
{ struct peak_usb_device *dev = netdev_priv(netdev);
/* unlink all pending urbs and free used memory */
peak_usb_unlink_all_urbs(dev);
if (dev->adapter->dev_stop)
dev->adapter->dev_stop(dev);
/* can set bus off now */ if (dev->adapter->dev_set_bus) { int err = dev->adapter->dev_set_bus(dev, 0);
if (err) return err;
}
return 0;
}
/* * handle end of waiting for the device to reset
*/ void peak_usb_restart_complete(struct peak_usb_device *dev)
{ /* finally MUST update can state */
dev->can.state = CAN_STATE_ERROR_ACTIVE;
/* netdev queue can be awaken now */
netif_wake_queue(dev->netdev);
}
/* * device (auto-)restart mechanism runs in a timer context => * MUST handle restart with asynchronous usb transfers
*/ staticint peak_usb_restart(struct peak_usb_device *dev)
{ struct urb *urb; int err;
u8 *buf;
/* * if device doesn't define any asynchronous restart handler, simply * wake the netdev queue up
*/ if (!dev->adapter->dev_restart_async) {
peak_usb_restart_complete(dev); return 0;
}
/* first allocate a urb to handle the asynchronous steps */
urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) return -ENOMEM;
/* also allocate enough space for the commands to send */
buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_ATOMIC); if (!buf) {
usb_free_urb(urb); return -ENOMEM;
}
/* call the device specific handler for the restart */
err = dev->adapter->dev_restart_async(dev, urb, buf); if (!err) return 0;
kfree(buf);
usb_free_urb(urb);
return err;
}
/* * candev callback used to change CAN mode. * Warning: this is called from a timer context!
*/ staticint peak_usb_set_mode(struct net_device *netdev, enum can_mode mode)
{ struct peak_usb_device *dev = netdev_priv(netdev); int err = 0;
switch (mode) { case CAN_MODE_START:
err = peak_usb_restart(dev); if (err)
netdev_err(netdev, "couldn't start device (err %d)\n",
err); break;
default: return -EOPNOTSUPP;
}
return err;
}
/* * candev callback used to set device nominal/arbitration bitrate.
*/ staticint peak_usb_set_bittiming(struct net_device *netdev)
{ struct peak_usb_device *dev = netdev_priv(netdev); conststruct peak_usb_adapter *pa = dev->adapter;
if (pa->dev_set_bittiming) { struct can_bittiming *bt = &dev->can.bittiming; int err = pa->dev_set_bittiming(dev, bt);
if (err)
netdev_info(netdev, "couldn't set bitrate (err %d)\n",
err); return err;
}
return 0;
}
/* * candev callback used to set device data bitrate.
*/ staticint peak_usb_set_data_bittiming(struct net_device *netdev)
{ struct peak_usb_device *dev = netdev_priv(netdev); conststruct peak_usb_adapter *pa = dev->adapter;
if (pa->dev_set_data_bittiming) { struct can_bittiming *bt = &dev->can.fd.data_bittiming; int err = pa->dev_set_data_bittiming(dev, bt);
if (err)
netdev_info(netdev, "couldn't set data bitrate (err %d)\n",
err);
/* CAN-USB devices generally handle 32-bit CAN channel IDs. * In case one doesn't, then it have to overload this function.
*/ int peak_usb_get_eeprom_len(struct net_device *netdev)
{ returnsizeof(u32);
}
/* Every CAN-USB device exports the dev_get_can_channel_id() operation. It is used * here to fill the data buffer with the user defined CAN channel ID.
*/ int peak_usb_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, u8 *data)
{ struct peak_usb_device *dev = netdev_priv(netdev);
u32 ch_id;
__le32 ch_id_le; int err;
err = dev->adapter->dev_get_can_channel_id(dev, &ch_id); if (err) return err;
/* ethtool operates on individual bytes. The byte order of the CAN * channel id in memory depends on the kernel architecture. We * convert the CAN channel id back to the native byte order of the PEAK * device itself to ensure that the order is consistent for all * host architectures.
*/
ch_id_le = cpu_to_le32(ch_id);
memcpy(data, (u8 *)&ch_id_le + eeprom->offset, eeprom->len);
/* Every CAN-USB device exports the dev_get_can_channel_id()/dev_set_can_channel_id() * operations. They are used here to set the new user defined CAN channel ID.
*/ int peak_usb_set_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, u8 *data)
{ struct peak_usb_device *dev = netdev_priv(netdev);
u32 ch_id;
__le32 ch_id_le; int err;
/* first, read the current user defined CAN channel ID */
err = dev->adapter->dev_get_can_channel_id(dev, &ch_id); if (err) {
netdev_err(netdev, "Failed to init CAN channel id (err %d)\n", err); return err;
}
/* do update the value with user given bytes. * ethtool operates on individual bytes. The byte order of the CAN * channel ID in memory depends on the kernel architecture. We * convert the CAN channel ID back to the native byte order of the PEAK * device itself to ensure that the order is consistent for all * host architectures.
*/
ch_id_le = cpu_to_le32(ch_id);
memcpy((u8 *)&ch_id_le + eeprom->offset, data, eeprom->len);
ch_id = le32_to_cpu(ch_id_le);
/* flash the new value now */
err = dev->adapter->dev_set_can_channel_id(dev, ch_id); if (err) {
netdev_err(netdev, "Failed to write new CAN channel id (err %d)\n",
err); return err;
}
/* update cached value with the new one */
dev->can_channel_id = ch_id;
/* * create one device which is attached to CAN controller #ctrl_idx of the * usb adapter.
*/ staticint peak_usb_create_dev(conststruct peak_usb_adapter *peak_usb_adapter, struct usb_interface *intf, int ctrl_idx)
{ struct usb_device *usb_dev = interface_to_usbdev(intf); int sizeof_candev = peak_usb_adapter->sizeof_dev_private; struct peak_usb_device *dev; struct net_device *netdev; int i, err;
u16 tmp16;
if (sizeof_candev < sizeof(struct peak_usb_device))
sizeof_candev = sizeof(struct peak_usb_device);
/* * called by the usb core when the device is unplugged from the system
*/ staticvoid peak_usb_disconnect(struct usb_interface *intf)
{ struct peak_usb_device *dev; struct peak_usb_device *dev_prev_siblings;
/* unregister as many netdev devices as siblings */ for (dev = usb_get_intfdata(intf); dev; dev = dev_prev_siblings) { struct net_device *netdev = dev->netdev; char name[IFNAMSIZ];
/* * probe function for new PEAK-System devices
*/ staticint peak_usb_probe(struct usb_interface *intf, conststruct usb_device_id *id)
{ conststruct peak_usb_adapter *peak_usb_adapter; int i, err = -ENOMEM;
/* got corresponding adapter: check if it handles current interface */ if (peak_usb_adapter->intf_probe) {
err = peak_usb_adapter->intf_probe(intf); if (err) return err;
}
for (i = 0; i < peak_usb_adapter->ctrl_count; i++) {
err = peak_usb_create_dev(peak_usb_adapter, intf, i); if (err) { /* deregister already created devices */
peak_usb_disconnect(intf); break;
}
}
return err;
}
/* usb specific object needed to register this driver with the usb subsystem */ staticstruct usb_driver peak_usb_driver = {
.name = PCAN_USB_DRIVER_NAME,
.disconnect = peak_usb_disconnect,
.probe = peak_usb_probe,
.id_table = peak_usb_table,
};
staticint __init peak_usb_init(void)
{ int err;
/* register this driver with the USB subsystem */
err = usb_register(&peak_usb_driver); if (err)
pr_err("%s: usb_register failed (err %d)\n",
PCAN_USB_DRIVER_NAME, err);
/* stop as many netdev devices as siblings */ for (dev = usb_get_intfdata(intf); dev; dev = dev->prev_siblings) { struct net_device *netdev = dev->netdev;
if (netif_device_present(netdev)) if (dev->adapter->dev_exit)
dev->adapter->dev_exit(dev);
}
return 0;
}
staticvoid __exit peak_usb_exit(void)
{ int err;
/* last chance do send any synchronous commands here */
err = driver_for_each_device(&peak_usb_driver.driver, NULL,
NULL, peak_usb_do_device_exit); if (err)
pr_err("%s: failed to stop all can devices (err %d)\n",
PCAN_USB_DRIVER_NAME, err);
/* deregister this driver with the USB subsystem */
usb_deregister(&peak_usb_driver);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.