/* handle device specific info used by the netdevices */ struct pcan_usb_pro_interface { struct peak_usb_device *dev[PCAN_USBPRO_CHANNEL_COUNT]; struct peak_time_ref time_ref; int cm_ignore_count; int dev_opened_count;
};
/* internal structure used to handle messages sent to bulk urb */ struct pcan_usb_pro_msg {
u8 *rec_ptr; int rec_buffer_size; int rec_buffer_len; union {
__le16 *rec_cnt_rd;
__le32 *rec_cnt;
u8 *rec_buffer;
} u;
};
/* * add one record to a message being built
*/ staticint pcan_msg_add_rec(struct pcan_usb_pro_msg *pm, int id, ...)
{ int len, i;
u8 *pc;
va_list ap;
va_start(ap, id);
pc = pm->rec_ptr + 1;
i = 0; switch (id) { case PCAN_USBPRO_TXMSG8:
i += 4;
fallthrough; case PCAN_USBPRO_TXMSG4:
i += 4;
fallthrough; case PCAN_USBPRO_TXMSG0:
*pc++ = va_arg(ap, int);
*pc++ = va_arg(ap, int);
*pc++ = va_arg(ap, int);
*(__le32 *)pc = cpu_to_le32(va_arg(ap, u32));
pc += 4;
memcpy(pc, va_arg(ap, int *), i);
pc += i; break;
case PCAN_USBPRO_SETBTR: case PCAN_USBPRO_GETDEVID: case PCAN_USBPRO_SETDEVID:
*pc++ = va_arg(ap, int);
pc += 2;
*(__le32 *)pc = cpu_to_le32(va_arg(ap, u32));
pc += 4; break;
case PCAN_USBPRO_SETFILTR: case PCAN_USBPRO_SETBUSACT: case PCAN_USBPRO_SETSILENT:
*pc++ = va_arg(ap, int);
*(__le16 *)pc = cpu_to_le16(va_arg(ap, int));
pc += 2; break;
case PCAN_USBPRO_SETLED:
*pc++ = va_arg(ap, int);
*(__le16 *)pc = cpu_to_le16(va_arg(ap, int));
pc += 2;
*(__le32 *)pc = cpu_to_le32(va_arg(ap, u32));
pc += 4; break;
case PCAN_USBPRO_SETTS:
pc++;
*(__le16 *)pc = cpu_to_le16(va_arg(ap, int));
pc += 2; break;
default:
pr_err("%s: %s(): unknown data type %02Xh (%d)\n",
PCAN_USB_DRIVER_NAME, __func__, id, id);
pc--; break;
}
len = pc - pm->rec_ptr; if (len > 0) {
le32_add_cpu(pm->u.rec_cnt, 1);
*pm->rec_ptr = id;
pm->rec_ptr = pc;
pm->rec_buffer_len += len;
}
va_end(ap);
return len;
}
/* * send PCAN-USB Pro command synchronously
*/ staticint pcan_usb_pro_send_cmd(struct peak_usb_device *dev, struct pcan_usb_pro_msg *pum)
{ int actual_length; int err;
/* usb device unregistered? */ if (!(dev->state & PCAN_USB_STATE_CONNECTED)) return 0;
/* if bus=on, be sure the bitrate being set before! */ if (onoff) { struct pcan_usb_pro_device *pdev =
container_of(dev, struct pcan_usb_pro_device, dev);
/* nothing should be sent while in BUS_OFF state */ if (dev->can.state == CAN_STATE_BUS_OFF) return 0;
if (!raw_status) { /* no error bit (back to active state) */
dev->can.state = CAN_STATE_ERROR_ACTIVE; return 0;
}
if (raw_status & (PCAN_USBPRO_STATUS_OVERRUN |
PCAN_USBPRO_STATUS_QOVERRUN)) { /* trick to bypass next comparison and process other errors */
new_state = CAN_STATE_MAX;
}
rec_ptr = pcan_msg_init(&usb_msg, urb->transfer_buffer,
urb->actual_length); if (!rec_ptr) {
netdev_err(netdev, "bad msg hdr len %d\n", urb->actual_length); return -EINVAL;
}
/* loop reading all the records from the incoming message */
msg_end = urb->transfer_buffer + urb->actual_length;
rec_cnt = le16_to_cpu(*usb_msg.u.rec_cnt_rd); for (; rec_cnt > 0; rec_cnt--) { union pcan_usb_pro_rec *pr = (union pcan_usb_pro_rec *)rec_ptr;
u16 sizeof_rec = pcan_usb_pro_sizeof_rec[pr->data_type];
if (!sizeof_rec) {
netdev_err(netdev, "got unsupported rec in usb msg:\n");
err = -ENOTSUPP; break;
}
/* check if the record goes out of current packet */ if (rec_ptr + sizeof_rec > msg_end) {
netdev_err(netdev, "got frag rec: should inc usb rx buf size\n");
err = -EBADMSG; break;
}
switch (pr->data_type) { case PCAN_USBPRO_RXMSG8: case PCAN_USBPRO_RXMSG4: case PCAN_USBPRO_RXMSG0: case PCAN_USBPRO_RXRTR:
err = pcan_usb_pro_handle_canmsg(usb_if, &pr->rx_msg); if (err < 0) goto fail; break;
case PCAN_USBPRO_RXSTATUS:
err = pcan_usb_pro_handle_error(usb_if, &pr->rx_status); if (err < 0) goto fail; break;
case PCAN_USBPRO_RXTS:
pcan_usb_pro_handle_ts(usb_if, &pr->rx_ts); break;
/* * stop interface * (last chance before set bus off)
*/ staticint pcan_usb_pro_stop(struct peak_usb_device *dev)
{ struct pcan_usb_pro_device *pdev =
container_of(dev, struct pcan_usb_pro_device, dev);
/* turn off ts msgs for that interface if no other dev opened */ if (pdev->usb_if->dev_opened_count == 1)
pcan_usb_pro_set_ts(dev, 0);
pdev->usb_if->dev_opened_count--;
return 0;
}
/* * called when probing to initialize a device object.
*/ staticint pcan_usb_pro_init(struct peak_usb_device *dev)
{ struct pcan_usb_pro_device *pdev =
container_of(dev, struct pcan_usb_pro_device, dev); struct pcan_usb_pro_interface *usb_if = NULL; struct pcan_usb_pro_fwinfo *fi = NULL; struct pcan_usb_pro_blinfo *bi = NULL; int err;
/* do this for 1st channel only */ if (!dev->prev_siblings) { /* allocate netdevices common structure attached to first one */
usb_if = kzalloc(sizeof(struct pcan_usb_pro_interface),
GFP_KERNEL);
fi = kmalloc(sizeof(struct pcan_usb_pro_fwinfo), GFP_KERNEL);
bi = kmalloc(sizeof(struct pcan_usb_pro_blinfo), GFP_KERNEL); if (!usb_if || !fi || !bi) {
err = -ENOMEM; goto err_out;
}
/* number of ts msgs to ignore before taking one into account */
usb_if->cm_ignore_count = 5;
/* * explicit use of dev_xxx() instead of netdev_xxx() here: * information displayed are related to the device itself, not * to the canx netdevices.
*/
err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
PCAN_USBPRO_INFO_FW,
fi, sizeof(*fi)); if (err) {
dev_err(dev->netdev->dev.parent, "unable to read %s firmware info (err %d)\n",
pcan_usb_pro.name, err); goto err_out;
}
err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
PCAN_USBPRO_INFO_BL,
bi, sizeof(*bi)); if (err) {
dev_err(dev->netdev->dev.parent, "unable to read %s bootloader info (err %d)\n",
pcan_usb_pro.name, err); goto err_out;
}
/* tell the device the can driver is running */
err = pcan_usb_pro_drv_loaded(dev, 1); if (err) goto err_out;
/* * 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_pro_set_bus(dev, 0);
}
/* 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_pro_set_ts(dev, 0);
/* tell the PCAN-USB Pro device the driver is being unloaded */
pcan_usb_pro_drv_loaded(dev, 0);
}
}
/* * called when PCAN-USB Pro adapter is unplugged
*/ staticvoid pcan_usb_pro_free(struct peak_usb_device *dev)
{ /* last device: can free pcan_usb_pro_interface object now */ if (!dev->prev_siblings && !dev->next_siblings)
kfree(pcan_usb_pro_dev_if(dev));
}
/* * probe function for new PCAN-USB Pro usb interface
*/ int pcan_usb_pro_probe(struct usb_interface *intf)
{ struct usb_host_interface *if_desc; int i;
if_desc = intf->altsetting;
/* check interface endpoint addresses */ for (i = 0; i < if_desc->desc.bNumEndpoints; i++) { struct usb_endpoint_descriptor *ep = &if_desc->endpoint[i].desc;
/* * below is the list of valid ep addresses. Any other ep address * is considered as not-CAN interface address => no dev created
*/ switch (ep->bEndpointAddress) { case PCAN_USBPRO_EP_CMDOUT: case PCAN_USBPRO_EP_CMDIN: case PCAN_USBPRO_EP_MSGOUT_0: case PCAN_USBPRO_EP_MSGOUT_1: case PCAN_USBPRO_EP_MSGIN: case PCAN_USBPRO_EP_UNUSED: break; default: return -ENODEV;
}
}
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.