/* struct pcan_ufd_fw_info::type */ #define PCAN_USBFD_TYPE_STD 1 #define PCAN_USBFD_TYPE_EXT 2 /* includes EP numbers */
/* read some versions info from the hw device */ struct __packed pcan_ufd_fw_info {
__le16 size_of; /* sizeof this */
__le16 type; /* type of this structure */
u8 hw_type; /* Type of hardware (HW_TYPE_xxx) */
u8 bl_version[3]; /* Bootloader version */
u8 hw_version; /* Hardware version (PCB) */
u8 fw_version[3]; /* Firmware version */
__le32 dev_id[2]; /* "device id" per CAN */
__le32 ser_no; /* S/N */
__le32 flags; /* special functions */
/* extended data when type >= PCAN_USBFD_TYPE_EXT */
u8 cmd_out_ep; /* ep for cmd */
u8 cmd_in_ep; /* ep for replies */
u8 data_out_ep[2]; /* ep for CANx TX */
u8 data_in_ep; /* ep for CAN RX */
u8 dummy[3];
};
/* handle device specific info used by the netdevices */ struct pcan_usb_fd_if { struct peak_usb_device *dev[PCAN_USB_MAX_CHANNEL]; struct pcan_ufd_fw_info fw_info; struct peak_time_ref time_ref; int cm_ignore_count; int dev_opened_count;
};
/* usb device unregistered? */ if (!(dev->state & PCAN_USB_STATE_CONNECTED)) return 0;
/* if a packet is not filled completely by commands, the command list * is terminated with an "end of collection" record.
*/
cmd_len = cmd_tail - cmd_head; if (cmd_len <= (PCAN_UFD_CMD_BUFFER_SIZE - sizeof(u64))) {
memset(cmd_tail, 0xff, sizeof(u64));
cmd_len += sizeof(u64);
}
packet_ptr = cmd_head;
packet_len = cmd_len;
/* firmware is not able to re-assemble 512 bytes buffer in full-speed */ if (unlikely(dev->udev->speed != USB_SPEED_HIGH))
packet_len = min(packet_len, PCAN_UFD_LOSPD_PKT_SIZE);
/* build the commands list in the given buffer, to enter operational mode */ staticint pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf)
{ struct pucan_wr_err_cnt *prc; struct pucan_command *cmd;
u8 *pc = buf;
/* select both counters */
prc->sel_mask = cpu_to_le16(PUCAN_WRERRCNT_TE|PUCAN_WRERRCNT_RE);
/* and reset their values */
prc->tx_counter = 0;
prc->rx_counter = 0;
/* moves the pointer forward */
pc += sizeof(struct pucan_wr_err_cnt);
/* add command to switch from ISO to non-ISO mode, if fw allows it */ if (dev->can.ctrlmode_supported & CAN_CTRLMODE_FD_NON_ISO) { struct pucan_options *puo = (struct pucan_options *)pc;
/* to be sure that no other extended bits will be taken into * account
*/
puo->unused = 0;
/* moves the pointer forward */
pc += sizeof(struct pucan_options);
}
/* next, go back to operational mode */
cmd = (struct pucan_command *)pc;
cmd->opcode_channel = pucan_cmd_opcode_channel(dev->ctrl_idx,
(dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) ?
PUCAN_CMD_LISTEN_ONLY_MODE :
PUCAN_CMD_NORMAL_MODE);
pc += sizeof(struct pucan_command);
return pc - buf;
}
/* set CAN bus on/off */ staticint pcan_usb_fd_set_bus(struct peak_usb_device *dev, u8 onoff)
{
u8 *pc = pcan_usb_fd_cmd_buffer(dev); int l;
if (onoff) { /* build the cmds list to enter operational mode */
l = pcan_usb_fd_build_restart_cmd(dev, pc);
} else { struct pucan_command *cmd = (struct pucan_command *)pc;
/* build cmd to go back to reset mode */
cmd->opcode_channel = pucan_cmd_opcode_channel(dev->ctrl_idx,
PUCAN_CMD_RESET_MODE);
l = sizeof(struct pucan_command);
}
/* send the command */ return pcan_usb_fd_send_cmd(dev, pc + l);
}
/* set filtering masks: * * idx in range [0..63] selects a row #idx, all rows otherwise * mask in range [0..0xffffffff] defines up to 32 CANIDs in the row(s) * * Each bit of this 64 x 32 bits array defines a CANID value: * * bit[i,j] = 1 implies that CANID=(i x 32)+j will be received, while * bit[i,j] = 0 implies that CANID=(i x 32)+j will be discarded.
*/ staticint pcan_usb_fd_set_filter_std(struct peak_usb_device *dev, int idx,
u32 mask)
{ struct pucan_filter_std *cmd = pcan_usb_fd_cmd_buffer(dev); int i, n;
/* select all rows when idx is out of range [0..63] */ if ((idx < 0) || (idx >= (1 << PUCAN_FLTSTD_ROW_IDX_BITS))) {
n = 1 << PUCAN_FLTSTD_ROW_IDX_BITS;
idx = 0;
/* select the row (and only the row) otherwise */
} else {
n = idx + 1;
}
for (i = idx; i < n; i++, cmd++) {
cmd->opcode_channel = pucan_cmd_opcode_channel(dev->ctrl_idx,
PUCAN_CMD_FILTER_STD);
cmd->idx = cpu_to_le16(i);
cmd->mask = cpu_to_le32(mask);
}
/* send the command */ return pcan_usb_fd_send_cmd(dev, cmd);
}
/* set/unset options * * onoff set(1)/unset(0) options * mask each bit defines a kind of options to set/unset
*/ staticint pcan_usb_fd_set_options(struct peak_usb_device *dev, bool onoff, u16 ucan_mask, u16 usb_mask)
{ struct pcan_ufd_options *cmd = pcan_usb_fd_cmd_buffer(dev);
/* send the command */ return pcan_usb_fd_send_cmd(dev, ++cmd);
}
/* read user CAN channel id from device */ staticint pcan_usb_fd_get_can_channel_id(struct peak_usb_device *dev,
u32 *can_ch_id)
{ int err; struct pcan_usb_fd_if *usb_if = pcan_usb_fd_dev_if(dev);
err = pcan_usb_fd_read_fwinfo(dev, &usb_if->fw_info); if (err) return err;
/* set a new CAN channel id in the flash memory of the device */ staticint pcan_usb_fd_set_can_channel_id(struct peak_usb_device *dev, u32 can_ch_id)
{ struct pcan_ufd_device_id *cmd = pcan_usb_fd_cmd_buffer(dev);
/* should wait until clock is stabilized */ if (usb_if->cm_ignore_count > 0)
usb_if->cm_ignore_count--; else
peak_usb_set_ts_now(&usb_if->time_ref, le32_to_cpu(ts->ts_low));
}
/* loop reading all the records from the incoming message */
msg_ptr = urb->transfer_buffer;
msg_end = urb->transfer_buffer + urb->actual_length; for (; msg_ptr < msg_end;) {
u16 rx_msg_type, rx_msg_size;
rx_msg = (struct pucan_msg *)msg_ptr; if (!rx_msg->size) { /* null packet found: end of list */ break;
}
/* check if the record goes out of current packet */ if (msg_ptr + rx_msg_size > msg_end) {
netdev_err(netdev, "got frag rec: should inc usb rx buf sze\n");
err = -EBADMSG; break;
}
switch (rx_msg_type) { case PUCAN_MSG_CAN_RX:
err = pcan_usb_fd_decode_canmsg(usb_if, rx_msg); if (err < 0) goto fail; break;
case PCAN_UFD_MSG_CALIBRATION:
pcan_usb_fd_decode_ts(usb_if, rx_msg); break;
case PUCAN_MSG_ERROR:
err = pcan_usb_fd_decode_error(usb_if, rx_msg); if (err < 0) goto fail; break;
case PUCAN_MSG_STATUS:
err = pcan_usb_fd_decode_status(usb_if, rx_msg); if (err < 0) goto fail; break;
case PCAN_UFD_MSG_OVERRUN:
err = pcan_usb_fd_decode_overrun(usb_if, rx_msg); if (err < 0) goto fail; break;
/* socket callback used to copy berr counters values received through USB */ staticint pcan_usb_fd_get_berr_counter(conststruct net_device *netdev, struct can_berr_counter *bec)
{ struct peak_usb_device *dev = netdev_priv(netdev); struct pcan_usb_fd_device *pdev =
container_of(dev, struct pcan_usb_fd_device, dev);
*bec = pdev->bec;
/* must return 0 */ return 0;
}
/* probe function for all PCAN-USB FD family usb interfaces */ staticint pcan_usb_fd_probe(struct usb_interface *intf)
{ struct usb_host_interface *iface_desc = &intf->altsetting[0];
/* CAN interface is always interface #0 */ return iface_desc->desc.bInterfaceNumber;
}
/* stop interface (last chance before set bus off) */ staticint pcan_usb_fd_stop(struct peak_usb_device *dev)
{ struct pcan_usb_fd_device *pdev =
container_of(dev, struct pcan_usb_fd_device, dev);
/* turn off special msgs for that interface if no other dev opened */ if (pdev->usb_if->dev_opened_count == 1)
pcan_usb_fd_set_options(dev, 0,
PUCAN_OPTION_ERROR,
PCAN_UFD_FLTEXT_CALIBRATION);
pdev->usb_if->dev_opened_count--;
return 0;
}
/* called when probing, to initialize a device object */ staticint pcan_usb_fd_init(struct peak_usb_device *dev)
{ struct pcan_usb_fd_device *pdev =
container_of(dev, struct pcan_usb_fd_device, dev); struct pcan_ufd_fw_info *fw_info; int i, err = -ENOMEM;
/* do this for 1st channel only */ if (!dev->prev_siblings) { /* allocate netdevices common structure attached to first one */
pdev->usb_if = kzalloc(sizeof(*pdev->usb_if), GFP_KERNEL); if (!pdev->usb_if) goto err_out;
/* allocate command buffer once for all for the interface */
pdev->cmd_buffer_addr = kzalloc(PCAN_UFD_CMD_BUFFER_SIZE,
GFP_KERNEL); if (!pdev->cmd_buffer_addr) goto err_out_1;
/* number of ts msgs to ignore before taking one into account */
pdev->usb_if->cm_ignore_count = 5;
fw_info = &pdev->usb_if->fw_info;
err = pcan_usb_fd_read_fwinfo(dev, fw_info); if (err) {
dev_err(dev->netdev->dev.parent, "unable to read %s firmware info (err %d)\n",
dev->adapter->name, err); goto err_out_2;
}
/* explicit use of dev_xxx() instead of netdev_xxx() here: * information displayed are related to the device itself, not * to the canx (channel) device.
*/
dev_info(dev->netdev->dev.parent, "PEAK-System %s v%u fw v%u.%u.%u (%u channels)\n",
dev->adapter->name, fw_info->hw_version,
fw_info->fw_version[0],
fw_info->fw_version[1],
fw_info->fw_version[2],
dev->adapter->ctrl_count);
/* check for ability to switch between ISO/non-ISO modes */ if (fw_info->fw_version[0] >= 2) { /* firmware >= 2.x supports ISO/non-ISO switching */
dev->can.ctrlmode_supported |= CAN_CTRLMODE_FD_NON_ISO;
} else { /* firmware < 2.x only supports fixed(!) non-ISO */
dev->can.ctrlmode |= CAN_CTRLMODE_FD_NON_ISO;
}
/* if vendor rsp type is greater than or equal to 2, then it * contains EP numbers to use for cmds pipes. If not, then * default EP should be used.
*/ if (le16_to_cpu(fw_info->type) < PCAN_USBFD_TYPE_EXT) {
fw_info->cmd_out_ep = PCAN_USBPRO_EP_CMDOUT;
fw_info->cmd_in_ep = PCAN_USBPRO_EP_CMDIN;
}
/* tell the hardware the can driver is running */
err = pcan_usb_fd_drv_loaded(dev, 1); if (err) {
dev_err(dev->netdev->dev.parent, "unable to tell %s driver is loaded (err %d)\n",
dev->adapter->name, err); goto err_out_2;
}
} else { /* otherwise, simply copy previous sibling's values */ struct pcan_usb_fd_device *ppdev =
container_of(dev->prev_siblings, struct pcan_usb_fd_device, dev);
/* do a copy of the ctrlmode[_supported] too */
dev->can.ctrlmode = ppdev->dev.can.ctrlmode;
dev->can.ctrlmode_supported = ppdev->dev.can.ctrlmode_supported;
/* if vendor rsp type is greater than or equal to 2, then it contains EP * numbers to use for data pipes. If not, then statically defined EP are * used (see peak_usb_create_dev()).
*/ if (le16_to_cpu(fw_info->type) >= PCAN_USBFD_TYPE_EXT) {
dev->ep_msg_in = fw_info->data_in_ep;
dev->ep_msg_out = fw_info->data_out_ep[dev->ctrl_idx];
}
/* set clock domain */ for (i = 0; i < ARRAY_SIZE(pcan_usb_fd_clk_freq); i++) if (dev->adapter->clock.freq == pcan_usb_fd_clk_freq[i]) break;
if (i >= ARRAY_SIZE(pcan_usb_fd_clk_freq)) {
dev_warn(dev->netdev->dev.parent, "incompatible clock frequencies\n");
err = -EINVAL; goto err_out_2;
}
pcan_usb_fd_set_clock_domain(dev, i);
/* set LED in default state (end of init phase) */
pcan_usb_fd_set_can_led(dev, PCAN_UFD_LED_DEF);
/* called when driver module is being unloaded */ staticvoid pcan_usb_fd_exit(struct peak_usb_device *dev)
{ struct pcan_usb_fd_device *pdev =
container_of(dev, struct pcan_usb_fd_device, dev);
/* when rmmod called before unplug and if down, should reset things * before leaving
*/ if (dev->can.state != CAN_STATE_STOPPED) { /* set bus off on the corresponding channel */
pcan_usb_fd_set_bus(dev, 0);
}
/* switch off corresponding CAN LEDs */
pcan_usb_fd_set_can_led(dev, PCAN_UFD_LED_OFF);
/* if channel #0 (only) */ if (dev->ctrl_idx == 0) { /* turn off calibration message if any device were opened */ if (pdev->usb_if->dev_opened_count > 0)
pcan_usb_fd_set_options(dev, 0,
PUCAN_OPTION_ERROR,
PCAN_UFD_FLTEXT_CALIBRATION);
/* tell USB adapter that the driver is being unloaded */
pcan_usb_fd_drv_loaded(dev, 0);
}
}
/* called when the USB adapter is unplugged */ staticvoid pcan_usb_fd_free(struct peak_usb_device *dev)
{ /* last device: can free shared objects now */ if (!dev->prev_siblings && !dev->next_siblings) { struct pcan_usb_fd_device *pdev =
container_of(dev, struct pcan_usb_fd_device, dev);
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.