162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * CAN driver for EMS Dr. Thomas Wuensche CPC-USB/ARM7 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2004-2009 EMS Dr. Thomas Wuensche 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/ethtool.h> 862306a36Sopenharmony_ci#include <linux/signal.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/netdevice.h> 1262306a36Sopenharmony_ci#include <linux/usb.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/can.h> 1562306a36Sopenharmony_ci#include <linux/can/dev.h> 1662306a36Sopenharmony_ci#include <linux/can/error.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ciMODULE_AUTHOR("Sebastian Haas <haas@ems-wuensche.com>"); 1962306a36Sopenharmony_ciMODULE_DESCRIPTION("CAN driver for EMS Dr. Thomas Wuensche CAN/USB interfaces"); 2062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* Control-Values for CPC_Control() Command Subject Selection */ 2362306a36Sopenharmony_ci#define CONTR_CAN_MESSAGE 0x04 2462306a36Sopenharmony_ci#define CONTR_CAN_STATE 0x0C 2562306a36Sopenharmony_ci#define CONTR_BUS_ERROR 0x1C 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* Control Command Actions */ 2862306a36Sopenharmony_ci#define CONTR_CONT_OFF 0 2962306a36Sopenharmony_ci#define CONTR_CONT_ON 1 3062306a36Sopenharmony_ci#define CONTR_ONCE 2 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* Messages from CPC to PC */ 3362306a36Sopenharmony_ci#define CPC_MSG_TYPE_CAN_FRAME 1 /* CAN data frame */ 3462306a36Sopenharmony_ci#define CPC_MSG_TYPE_RTR_FRAME 8 /* CAN remote frame */ 3562306a36Sopenharmony_ci#define CPC_MSG_TYPE_CAN_PARAMS 12 /* Actual CAN parameters */ 3662306a36Sopenharmony_ci#define CPC_MSG_TYPE_CAN_STATE 14 /* CAN state message */ 3762306a36Sopenharmony_ci#define CPC_MSG_TYPE_EXT_CAN_FRAME 16 /* Extended CAN data frame */ 3862306a36Sopenharmony_ci#define CPC_MSG_TYPE_EXT_RTR_FRAME 17 /* Extended remote frame */ 3962306a36Sopenharmony_ci#define CPC_MSG_TYPE_CONTROL 19 /* change interface behavior */ 4062306a36Sopenharmony_ci#define CPC_MSG_TYPE_CONFIRM 20 /* command processed confirmation */ 4162306a36Sopenharmony_ci#define CPC_MSG_TYPE_OVERRUN 21 /* overrun events */ 4262306a36Sopenharmony_ci#define CPC_MSG_TYPE_CAN_FRAME_ERROR 23 /* detected bus errors */ 4362306a36Sopenharmony_ci#define CPC_MSG_TYPE_ERR_COUNTER 25 /* RX/TX error counter */ 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* Messages from the PC to the CPC interface */ 4662306a36Sopenharmony_ci#define CPC_CMD_TYPE_CAN_FRAME 1 /* CAN data frame */ 4762306a36Sopenharmony_ci#define CPC_CMD_TYPE_CONTROL 3 /* control of interface behavior */ 4862306a36Sopenharmony_ci#define CPC_CMD_TYPE_CAN_PARAMS 6 /* set CAN parameters */ 4962306a36Sopenharmony_ci#define CPC_CMD_TYPE_RTR_FRAME 13 /* CAN remote frame */ 5062306a36Sopenharmony_ci#define CPC_CMD_TYPE_CAN_STATE 14 /* CAN state message */ 5162306a36Sopenharmony_ci#define CPC_CMD_TYPE_EXT_CAN_FRAME 15 /* Extended CAN data frame */ 5262306a36Sopenharmony_ci#define CPC_CMD_TYPE_EXT_RTR_FRAME 16 /* Extended CAN remote frame */ 5362306a36Sopenharmony_ci#define CPC_CMD_TYPE_CAN_EXIT 200 /* exit the CAN */ 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define CPC_CMD_TYPE_INQ_ERR_COUNTER 25 /* request the CAN error counters */ 5662306a36Sopenharmony_ci#define CPC_CMD_TYPE_CLEAR_MSG_QUEUE 8 /* clear CPC_MSG queue */ 5762306a36Sopenharmony_ci#define CPC_CMD_TYPE_CLEAR_CMD_QUEUE 28 /* clear CPC_CMD queue */ 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define CPC_CC_TYPE_SJA1000 2 /* Philips basic CAN controller */ 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define CPC_CAN_ECODE_ERRFRAME 0x01 /* Ecode type */ 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* Overrun types */ 6462306a36Sopenharmony_ci#define CPC_OVR_EVENT_CAN 0x01 6562306a36Sopenharmony_ci#define CPC_OVR_EVENT_CANSTATE 0x02 6662306a36Sopenharmony_ci#define CPC_OVR_EVENT_BUSERROR 0x04 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* 6962306a36Sopenharmony_ci * If the CAN controller lost a message we indicate it with the highest bit 7062306a36Sopenharmony_ci * set in the count field. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci#define CPC_OVR_HW 0x80 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* Size of the "struct ems_cpc_msg" without the union */ 7562306a36Sopenharmony_ci#define CPC_MSG_HEADER_LEN 11 7662306a36Sopenharmony_ci#define CPC_CAN_MSG_MIN_SIZE 5 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* Define these values to match your devices */ 7962306a36Sopenharmony_ci#define USB_CPCUSB_VENDOR_ID 0x12D6 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define USB_CPCUSB_ARM7_PRODUCT_ID 0x0444 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* Mode register NXP LPC2119/SJA1000 CAN Controller */ 8462306a36Sopenharmony_ci#define SJA1000_MOD_NORMAL 0x00 8562306a36Sopenharmony_ci#define SJA1000_MOD_RM 0x01 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* ECC register NXP LPC2119/SJA1000 CAN Controller */ 8862306a36Sopenharmony_ci#define SJA1000_ECC_SEG 0x1F 8962306a36Sopenharmony_ci#define SJA1000_ECC_DIR 0x20 9062306a36Sopenharmony_ci#define SJA1000_ECC_ERR 0x06 9162306a36Sopenharmony_ci#define SJA1000_ECC_BIT 0x00 9262306a36Sopenharmony_ci#define SJA1000_ECC_FORM 0x40 9362306a36Sopenharmony_ci#define SJA1000_ECC_STUFF 0x80 9462306a36Sopenharmony_ci#define SJA1000_ECC_MASK 0xc0 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* Status register content */ 9762306a36Sopenharmony_ci#define SJA1000_SR_BS 0x80 9862306a36Sopenharmony_ci#define SJA1000_SR_ES 0x40 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#define SJA1000_DEFAULT_OUTPUT_CONTROL 0xDA 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* 10362306a36Sopenharmony_ci * The device actually uses a 16MHz clock to generate the CAN clock 10462306a36Sopenharmony_ci * but it expects SJA1000 bit settings based on 8MHz (is internally 10562306a36Sopenharmony_ci * converted). 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ci#define EMS_USB_ARM7_CLOCK 8000000 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci#define CPC_TX_QUEUE_TRIGGER_LOW 25 11062306a36Sopenharmony_ci#define CPC_TX_QUEUE_TRIGGER_HIGH 35 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* 11362306a36Sopenharmony_ci * CAN-Message representation in a CPC_MSG. Message object type is 11462306a36Sopenharmony_ci * CPC_MSG_TYPE_CAN_FRAME or CPC_MSG_TYPE_RTR_FRAME or 11562306a36Sopenharmony_ci * CPC_MSG_TYPE_EXT_CAN_FRAME or CPC_MSG_TYPE_EXT_RTR_FRAME. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_cistruct cpc_can_msg { 11862306a36Sopenharmony_ci __le32 id; 11962306a36Sopenharmony_ci u8 length; 12062306a36Sopenharmony_ci u8 msg[8]; 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* Representation of the CAN parameters for the SJA1000 controller */ 12462306a36Sopenharmony_cistruct cpc_sja1000_params { 12562306a36Sopenharmony_ci u8 mode; 12662306a36Sopenharmony_ci u8 acc_code0; 12762306a36Sopenharmony_ci u8 acc_code1; 12862306a36Sopenharmony_ci u8 acc_code2; 12962306a36Sopenharmony_ci u8 acc_code3; 13062306a36Sopenharmony_ci u8 acc_mask0; 13162306a36Sopenharmony_ci u8 acc_mask1; 13262306a36Sopenharmony_ci u8 acc_mask2; 13362306a36Sopenharmony_ci u8 acc_mask3; 13462306a36Sopenharmony_ci u8 btr0; 13562306a36Sopenharmony_ci u8 btr1; 13662306a36Sopenharmony_ci u8 outp_contr; 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* CAN params message representation */ 14062306a36Sopenharmony_cistruct cpc_can_params { 14162306a36Sopenharmony_ci u8 cc_type; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* Will support M16C CAN controller in the future */ 14462306a36Sopenharmony_ci union { 14562306a36Sopenharmony_ci struct cpc_sja1000_params sja1000; 14662306a36Sopenharmony_ci } cc_params; 14762306a36Sopenharmony_ci}; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* Structure for confirmed message handling */ 15062306a36Sopenharmony_cistruct cpc_confirm { 15162306a36Sopenharmony_ci u8 error; /* error code */ 15262306a36Sopenharmony_ci}; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* Structure for overrun conditions */ 15562306a36Sopenharmony_cistruct cpc_overrun { 15662306a36Sopenharmony_ci u8 event; 15762306a36Sopenharmony_ci u8 count; 15862306a36Sopenharmony_ci}; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci/* SJA1000 CAN errors (compatible to NXP LPC2119) */ 16162306a36Sopenharmony_cistruct cpc_sja1000_can_error { 16262306a36Sopenharmony_ci u8 ecc; 16362306a36Sopenharmony_ci u8 rxerr; 16462306a36Sopenharmony_ci u8 txerr; 16562306a36Sopenharmony_ci}; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* structure for CAN error conditions */ 16862306a36Sopenharmony_cistruct cpc_can_error { 16962306a36Sopenharmony_ci u8 ecode; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci struct { 17262306a36Sopenharmony_ci u8 cc_type; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* Other controllers may also provide error code capture regs */ 17562306a36Sopenharmony_ci union { 17662306a36Sopenharmony_ci struct cpc_sja1000_can_error sja1000; 17762306a36Sopenharmony_ci } regs; 17862306a36Sopenharmony_ci } cc; 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci/* 18262306a36Sopenharmony_ci * Structure containing RX/TX error counter. This structure is used to request 18362306a36Sopenharmony_ci * the values of the CAN controllers TX and RX error counter. 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_cistruct cpc_can_err_counter { 18662306a36Sopenharmony_ci u8 rx; 18762306a36Sopenharmony_ci u8 tx; 18862306a36Sopenharmony_ci}; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/* Main message type used between library and application */ 19162306a36Sopenharmony_cistruct __packed ems_cpc_msg { 19262306a36Sopenharmony_ci u8 type; /* type of message */ 19362306a36Sopenharmony_ci u8 length; /* length of data within union 'msg' */ 19462306a36Sopenharmony_ci u8 msgid; /* confirmation handle */ 19562306a36Sopenharmony_ci __le32 ts_sec; /* timestamp in seconds */ 19662306a36Sopenharmony_ci __le32 ts_nsec; /* timestamp in nano seconds */ 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci union __packed { 19962306a36Sopenharmony_ci u8 generic[64]; 20062306a36Sopenharmony_ci struct cpc_can_msg can_msg; 20162306a36Sopenharmony_ci struct cpc_can_params can_params; 20262306a36Sopenharmony_ci struct cpc_confirm confirmation; 20362306a36Sopenharmony_ci struct cpc_overrun overrun; 20462306a36Sopenharmony_ci struct cpc_can_error error; 20562306a36Sopenharmony_ci struct cpc_can_err_counter err_counter; 20662306a36Sopenharmony_ci u8 can_state; 20762306a36Sopenharmony_ci } msg; 20862306a36Sopenharmony_ci}; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/* 21162306a36Sopenharmony_ci * Table of devices that work with this driver 21262306a36Sopenharmony_ci * NOTE: This driver supports only CPC-USB/ARM7 (LPC2119) yet. 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_cistatic struct usb_device_id ems_usb_table[] = { 21562306a36Sopenharmony_ci {USB_DEVICE(USB_CPCUSB_VENDOR_ID, USB_CPCUSB_ARM7_PRODUCT_ID)}, 21662306a36Sopenharmony_ci {} /* Terminating entry */ 21762306a36Sopenharmony_ci}; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, ems_usb_table); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci#define RX_BUFFER_SIZE 64 22262306a36Sopenharmony_ci#define CPC_HEADER_SIZE 4 22362306a36Sopenharmony_ci#define INTR_IN_BUFFER_SIZE 4 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci#define MAX_RX_URBS 10 22662306a36Sopenharmony_ci#define MAX_TX_URBS 10 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistruct ems_usb; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistruct ems_tx_urb_context { 23162306a36Sopenharmony_ci struct ems_usb *dev; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci u32 echo_index; 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistruct ems_usb { 23762306a36Sopenharmony_ci struct can_priv can; /* must be the first member */ 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci struct sk_buff *echo_skb[MAX_TX_URBS]; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci struct usb_device *udev; 24262306a36Sopenharmony_ci struct net_device *netdev; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci atomic_t active_tx_urbs; 24562306a36Sopenharmony_ci struct usb_anchor tx_submitted; 24662306a36Sopenharmony_ci struct ems_tx_urb_context tx_contexts[MAX_TX_URBS]; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci struct usb_anchor rx_submitted; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci struct urb *intr_urb; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci u8 *tx_msg_buffer; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci u8 *intr_in_buffer; 25562306a36Sopenharmony_ci unsigned int free_slots; /* remember number of available slots */ 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci struct ems_cpc_msg active_params; /* active controller parameters */ 25862306a36Sopenharmony_ci void *rxbuf[MAX_RX_URBS]; 25962306a36Sopenharmony_ci dma_addr_t rxbuf_dma[MAX_RX_URBS]; 26062306a36Sopenharmony_ci}; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic void ems_usb_read_interrupt_callback(struct urb *urb) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct ems_usb *dev = urb->context; 26562306a36Sopenharmony_ci struct net_device *netdev = dev->netdev; 26662306a36Sopenharmony_ci int err; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (!netif_device_present(netdev)) 26962306a36Sopenharmony_ci return; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci switch (urb->status) { 27262306a36Sopenharmony_ci case 0: 27362306a36Sopenharmony_ci dev->free_slots = dev->intr_in_buffer[1]; 27462306a36Sopenharmony_ci if (dev->free_slots > CPC_TX_QUEUE_TRIGGER_HIGH && 27562306a36Sopenharmony_ci netif_queue_stopped(netdev)) 27662306a36Sopenharmony_ci netif_wake_queue(netdev); 27762306a36Sopenharmony_ci break; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci case -ECONNRESET: /* unlink */ 28062306a36Sopenharmony_ci case -ENOENT: 28162306a36Sopenharmony_ci case -EPIPE: 28262306a36Sopenharmony_ci case -EPROTO: 28362306a36Sopenharmony_ci case -ESHUTDOWN: 28462306a36Sopenharmony_ci return; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci default: 28762306a36Sopenharmony_ci netdev_info(netdev, "Rx interrupt aborted %d\n", urb->status); 28862306a36Sopenharmony_ci break; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci err = usb_submit_urb(urb, GFP_ATOMIC); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (err == -ENODEV) 29462306a36Sopenharmony_ci netif_device_detach(netdev); 29562306a36Sopenharmony_ci else if (err) 29662306a36Sopenharmony_ci netdev_err(netdev, "failed resubmitting intr urb: %d\n", err); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic void ems_usb_rx_can_msg(struct ems_usb *dev, struct ems_cpc_msg *msg) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct can_frame *cf; 30262306a36Sopenharmony_ci struct sk_buff *skb; 30362306a36Sopenharmony_ci int i; 30462306a36Sopenharmony_ci struct net_device_stats *stats = &dev->netdev->stats; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci skb = alloc_can_skb(dev->netdev, &cf); 30762306a36Sopenharmony_ci if (skb == NULL) 30862306a36Sopenharmony_ci return; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci cf->can_id = le32_to_cpu(msg->msg.can_msg.id); 31162306a36Sopenharmony_ci cf->len = can_cc_dlc2len(msg->msg.can_msg.length & 0xF); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (msg->type == CPC_MSG_TYPE_EXT_CAN_FRAME || 31462306a36Sopenharmony_ci msg->type == CPC_MSG_TYPE_EXT_RTR_FRAME) 31562306a36Sopenharmony_ci cf->can_id |= CAN_EFF_FLAG; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (msg->type == CPC_MSG_TYPE_RTR_FRAME || 31862306a36Sopenharmony_ci msg->type == CPC_MSG_TYPE_EXT_RTR_FRAME) { 31962306a36Sopenharmony_ci cf->can_id |= CAN_RTR_FLAG; 32062306a36Sopenharmony_ci } else { 32162306a36Sopenharmony_ci for (i = 0; i < cf->len; i++) 32262306a36Sopenharmony_ci cf->data[i] = msg->msg.can_msg.msg[i]; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci stats->rx_bytes += cf->len; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci stats->rx_packets++; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci netif_rx(skb); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct can_frame *cf; 33462306a36Sopenharmony_ci struct sk_buff *skb; 33562306a36Sopenharmony_ci struct net_device_stats *stats = &dev->netdev->stats; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci skb = alloc_can_err_skb(dev->netdev, &cf); 33862306a36Sopenharmony_ci if (skb == NULL) 33962306a36Sopenharmony_ci return; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (msg->type == CPC_MSG_TYPE_CAN_STATE) { 34262306a36Sopenharmony_ci u8 state = msg->msg.can_state; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (state & SJA1000_SR_BS) { 34562306a36Sopenharmony_ci dev->can.state = CAN_STATE_BUS_OFF; 34662306a36Sopenharmony_ci cf->can_id |= CAN_ERR_BUSOFF; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci dev->can.can_stats.bus_off++; 34962306a36Sopenharmony_ci can_bus_off(dev->netdev); 35062306a36Sopenharmony_ci } else if (state & SJA1000_SR_ES) { 35162306a36Sopenharmony_ci dev->can.state = CAN_STATE_ERROR_WARNING; 35262306a36Sopenharmony_ci dev->can.can_stats.error_warning++; 35362306a36Sopenharmony_ci } else { 35462306a36Sopenharmony_ci dev->can.state = CAN_STATE_ERROR_ACTIVE; 35562306a36Sopenharmony_ci dev->can.can_stats.error_passive++; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci } else if (msg->type == CPC_MSG_TYPE_CAN_FRAME_ERROR) { 35862306a36Sopenharmony_ci u8 ecc = msg->msg.error.cc.regs.sja1000.ecc; 35962306a36Sopenharmony_ci u8 txerr = msg->msg.error.cc.regs.sja1000.txerr; 36062306a36Sopenharmony_ci u8 rxerr = msg->msg.error.cc.regs.sja1000.rxerr; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* bus error interrupt */ 36362306a36Sopenharmony_ci dev->can.can_stats.bus_error++; 36462306a36Sopenharmony_ci stats->rx_errors++; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci switch (ecc & SJA1000_ECC_MASK) { 36962306a36Sopenharmony_ci case SJA1000_ECC_BIT: 37062306a36Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_BIT; 37162306a36Sopenharmony_ci break; 37262306a36Sopenharmony_ci case SJA1000_ECC_FORM: 37362306a36Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_FORM; 37462306a36Sopenharmony_ci break; 37562306a36Sopenharmony_ci case SJA1000_ECC_STUFF: 37662306a36Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_STUFF; 37762306a36Sopenharmony_ci break; 37862306a36Sopenharmony_ci default: 37962306a36Sopenharmony_ci cf->data[3] = ecc & SJA1000_ECC_SEG; 38062306a36Sopenharmony_ci break; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* Error occurred during transmission? */ 38462306a36Sopenharmony_ci if ((ecc & SJA1000_ECC_DIR) == 0) 38562306a36Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_TX; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (dev->can.state == CAN_STATE_ERROR_WARNING || 38862306a36Sopenharmony_ci dev->can.state == CAN_STATE_ERROR_PASSIVE) { 38962306a36Sopenharmony_ci cf->can_id |= CAN_ERR_CRTL; 39062306a36Sopenharmony_ci cf->data[1] = (txerr > rxerr) ? 39162306a36Sopenharmony_ci CAN_ERR_CRTL_TX_PASSIVE : CAN_ERR_CRTL_RX_PASSIVE; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci } else if (msg->type == CPC_MSG_TYPE_OVERRUN) { 39462306a36Sopenharmony_ci cf->can_id |= CAN_ERR_CRTL; 39562306a36Sopenharmony_ci cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci stats->rx_over_errors++; 39862306a36Sopenharmony_ci stats->rx_errors++; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci netif_rx(skb); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci/* 40562306a36Sopenharmony_ci * callback for bulk IN urb 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_cistatic void ems_usb_read_bulk_callback(struct urb *urb) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct ems_usb *dev = urb->context; 41062306a36Sopenharmony_ci struct net_device *netdev; 41162306a36Sopenharmony_ci int retval; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci netdev = dev->netdev; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (!netif_device_present(netdev)) 41662306a36Sopenharmony_ci return; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci switch (urb->status) { 41962306a36Sopenharmony_ci case 0: /* success */ 42062306a36Sopenharmony_ci break; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci case -ENOENT: 42362306a36Sopenharmony_ci return; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci default: 42662306a36Sopenharmony_ci netdev_info(netdev, "Rx URB aborted (%d)\n", urb->status); 42762306a36Sopenharmony_ci goto resubmit_urb; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (urb->actual_length > CPC_HEADER_SIZE) { 43162306a36Sopenharmony_ci struct ems_cpc_msg *msg; 43262306a36Sopenharmony_ci u8 *ibuf = urb->transfer_buffer; 43362306a36Sopenharmony_ci u8 msg_count, start; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci msg_count = ibuf[0] & ~0x80; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci start = CPC_HEADER_SIZE; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci while (msg_count) { 44062306a36Sopenharmony_ci msg = (struct ems_cpc_msg *)&ibuf[start]; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci switch (msg->type) { 44362306a36Sopenharmony_ci case CPC_MSG_TYPE_CAN_STATE: 44462306a36Sopenharmony_ci /* Process CAN state changes */ 44562306a36Sopenharmony_ci ems_usb_rx_err(dev, msg); 44662306a36Sopenharmony_ci break; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci case CPC_MSG_TYPE_CAN_FRAME: 44962306a36Sopenharmony_ci case CPC_MSG_TYPE_EXT_CAN_FRAME: 45062306a36Sopenharmony_ci case CPC_MSG_TYPE_RTR_FRAME: 45162306a36Sopenharmony_ci case CPC_MSG_TYPE_EXT_RTR_FRAME: 45262306a36Sopenharmony_ci ems_usb_rx_can_msg(dev, msg); 45362306a36Sopenharmony_ci break; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci case CPC_MSG_TYPE_CAN_FRAME_ERROR: 45662306a36Sopenharmony_ci /* Process errorframe */ 45762306a36Sopenharmony_ci ems_usb_rx_err(dev, msg); 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci case CPC_MSG_TYPE_OVERRUN: 46162306a36Sopenharmony_ci /* Message lost while receiving */ 46262306a36Sopenharmony_ci ems_usb_rx_err(dev, msg); 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci start += CPC_MSG_HEADER_LEN + msg->length; 46762306a36Sopenharmony_ci msg_count--; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (start > urb->transfer_buffer_length) { 47062306a36Sopenharmony_ci netdev_err(netdev, "format error\n"); 47162306a36Sopenharmony_ci break; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ciresubmit_urb: 47762306a36Sopenharmony_ci usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 2), 47862306a36Sopenharmony_ci urb->transfer_buffer, RX_BUFFER_SIZE, 47962306a36Sopenharmony_ci ems_usb_read_bulk_callback, dev); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci retval = usb_submit_urb(urb, GFP_ATOMIC); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (retval == -ENODEV) 48462306a36Sopenharmony_ci netif_device_detach(netdev); 48562306a36Sopenharmony_ci else if (retval) 48662306a36Sopenharmony_ci netdev_err(netdev, 48762306a36Sopenharmony_ci "failed resubmitting read bulk urb: %d\n", retval); 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci/* 49162306a36Sopenharmony_ci * callback for bulk IN urb 49262306a36Sopenharmony_ci */ 49362306a36Sopenharmony_cistatic void ems_usb_write_bulk_callback(struct urb *urb) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct ems_tx_urb_context *context = urb->context; 49662306a36Sopenharmony_ci struct ems_usb *dev; 49762306a36Sopenharmony_ci struct net_device *netdev; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci BUG_ON(!context); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci dev = context->dev; 50262306a36Sopenharmony_ci netdev = dev->netdev; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* free up our allocated buffer */ 50562306a36Sopenharmony_ci usb_free_coherent(urb->dev, urb->transfer_buffer_length, 50662306a36Sopenharmony_ci urb->transfer_buffer, urb->transfer_dma); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci atomic_dec(&dev->active_tx_urbs); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (!netif_device_present(netdev)) 51162306a36Sopenharmony_ci return; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (urb->status) 51462306a36Sopenharmony_ci netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci netif_trans_update(netdev); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* transmission complete interrupt */ 51962306a36Sopenharmony_ci netdev->stats.tx_packets++; 52062306a36Sopenharmony_ci netdev->stats.tx_bytes += can_get_echo_skb(netdev, context->echo_index, 52162306a36Sopenharmony_ci NULL); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* Release context */ 52462306a36Sopenharmony_ci context->echo_index = MAX_TX_URBS; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci/* 52962306a36Sopenharmony_ci * Send the given CPC command synchronously 53062306a36Sopenharmony_ci */ 53162306a36Sopenharmony_cistatic int ems_usb_command_msg(struct ems_usb *dev, struct ems_cpc_msg *msg) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci int actual_length; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci /* Copy payload */ 53662306a36Sopenharmony_ci memcpy(&dev->tx_msg_buffer[CPC_HEADER_SIZE], msg, 53762306a36Sopenharmony_ci msg->length + CPC_MSG_HEADER_LEN); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /* Clear header */ 54062306a36Sopenharmony_ci memset(&dev->tx_msg_buffer[0], 0, CPC_HEADER_SIZE); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), 54362306a36Sopenharmony_ci &dev->tx_msg_buffer[0], 54462306a36Sopenharmony_ci msg->length + CPC_MSG_HEADER_LEN + CPC_HEADER_SIZE, 54562306a36Sopenharmony_ci &actual_length, 1000); 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci/* 54962306a36Sopenharmony_ci * Change CAN controllers' mode register 55062306a36Sopenharmony_ci */ 55162306a36Sopenharmony_cistatic int ems_usb_write_mode(struct ems_usb *dev, u8 mode) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci dev->active_params.msg.can_params.cc_params.sja1000.mode = mode; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci return ems_usb_command_msg(dev, &dev->active_params); 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci/* 55962306a36Sopenharmony_ci * Send a CPC_Control command to change behaviour when interface receives a CAN 56062306a36Sopenharmony_ci * message, bus error or CAN state changed notifications. 56162306a36Sopenharmony_ci */ 56262306a36Sopenharmony_cistatic int ems_usb_control_cmd(struct ems_usb *dev, u8 val) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci struct ems_cpc_msg cmd; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci cmd.type = CPC_CMD_TYPE_CONTROL; 56762306a36Sopenharmony_ci cmd.length = CPC_MSG_HEADER_LEN + 1; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci cmd.msgid = 0; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci cmd.msg.generic[0] = val; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci return ems_usb_command_msg(dev, &cmd); 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci/* 57762306a36Sopenharmony_ci * Start interface 57862306a36Sopenharmony_ci */ 57962306a36Sopenharmony_cistatic int ems_usb_start(struct ems_usb *dev) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci struct net_device *netdev = dev->netdev; 58262306a36Sopenharmony_ci int err, i; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci dev->intr_in_buffer[0] = 0; 58562306a36Sopenharmony_ci dev->free_slots = 50; /* initial size */ 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci for (i = 0; i < MAX_RX_URBS; i++) { 58862306a36Sopenharmony_ci struct urb *urb = NULL; 58962306a36Sopenharmony_ci u8 *buf = NULL; 59062306a36Sopenharmony_ci dma_addr_t buf_dma; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* create a URB, and a buffer for it */ 59362306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_KERNEL); 59462306a36Sopenharmony_ci if (!urb) { 59562306a36Sopenharmony_ci err = -ENOMEM; 59662306a36Sopenharmony_ci break; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL, 60062306a36Sopenharmony_ci &buf_dma); 60162306a36Sopenharmony_ci if (!buf) { 60262306a36Sopenharmony_ci netdev_err(netdev, "No memory left for USB buffer\n"); 60362306a36Sopenharmony_ci usb_free_urb(urb); 60462306a36Sopenharmony_ci err = -ENOMEM; 60562306a36Sopenharmony_ci break; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci urb->transfer_dma = buf_dma; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 2), 61162306a36Sopenharmony_ci buf, RX_BUFFER_SIZE, 61262306a36Sopenharmony_ci ems_usb_read_bulk_callback, dev); 61362306a36Sopenharmony_ci urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 61462306a36Sopenharmony_ci usb_anchor_urb(urb, &dev->rx_submitted); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci err = usb_submit_urb(urb, GFP_KERNEL); 61762306a36Sopenharmony_ci if (err) { 61862306a36Sopenharmony_ci usb_unanchor_urb(urb); 61962306a36Sopenharmony_ci usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf, 62062306a36Sopenharmony_ci urb->transfer_dma); 62162306a36Sopenharmony_ci usb_free_urb(urb); 62262306a36Sopenharmony_ci break; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci dev->rxbuf[i] = buf; 62662306a36Sopenharmony_ci dev->rxbuf_dma[i] = buf_dma; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* Drop reference, USB core will take care of freeing it */ 62962306a36Sopenharmony_ci usb_free_urb(urb); 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci /* Did we submit any URBs */ 63362306a36Sopenharmony_ci if (i == 0) { 63462306a36Sopenharmony_ci netdev_warn(netdev, "couldn't setup read URBs\n"); 63562306a36Sopenharmony_ci return err; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* Warn if we've couldn't transmit all the URBs */ 63962306a36Sopenharmony_ci if (i < MAX_RX_URBS) 64062306a36Sopenharmony_ci netdev_warn(netdev, "rx performance may be slow\n"); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci /* Setup and start interrupt URB */ 64362306a36Sopenharmony_ci usb_fill_int_urb(dev->intr_urb, dev->udev, 64462306a36Sopenharmony_ci usb_rcvintpipe(dev->udev, 1), 64562306a36Sopenharmony_ci dev->intr_in_buffer, 64662306a36Sopenharmony_ci INTR_IN_BUFFER_SIZE, 64762306a36Sopenharmony_ci ems_usb_read_interrupt_callback, dev, 1); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci err = usb_submit_urb(dev->intr_urb, GFP_KERNEL); 65062306a36Sopenharmony_ci if (err) { 65162306a36Sopenharmony_ci netdev_warn(netdev, "intr URB submit failed: %d\n", err); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return err; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci /* CPC-USB will transfer received message to host */ 65762306a36Sopenharmony_ci err = ems_usb_control_cmd(dev, CONTR_CAN_MESSAGE | CONTR_CONT_ON); 65862306a36Sopenharmony_ci if (err) 65962306a36Sopenharmony_ci goto failed; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci /* CPC-USB will transfer CAN state changes to host */ 66262306a36Sopenharmony_ci err = ems_usb_control_cmd(dev, CONTR_CAN_STATE | CONTR_CONT_ON); 66362306a36Sopenharmony_ci if (err) 66462306a36Sopenharmony_ci goto failed; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* CPC-USB will transfer bus errors to host */ 66762306a36Sopenharmony_ci err = ems_usb_control_cmd(dev, CONTR_BUS_ERROR | CONTR_CONT_ON); 66862306a36Sopenharmony_ci if (err) 66962306a36Sopenharmony_ci goto failed; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci err = ems_usb_write_mode(dev, SJA1000_MOD_NORMAL); 67262306a36Sopenharmony_ci if (err) 67362306a36Sopenharmony_ci goto failed; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci dev->can.state = CAN_STATE_ERROR_ACTIVE; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci return 0; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cifailed: 68062306a36Sopenharmony_ci netdev_warn(netdev, "couldn't submit control: %d\n", err); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci return err; 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic void unlink_all_urbs(struct ems_usb *dev) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci int i; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci usb_unlink_urb(dev->intr_urb); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci usb_kill_anchored_urbs(&dev->rx_submitted); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci for (i = 0; i < MAX_RX_URBS; ++i) 69462306a36Sopenharmony_ci usb_free_coherent(dev->udev, RX_BUFFER_SIZE, 69562306a36Sopenharmony_ci dev->rxbuf[i], dev->rxbuf_dma[i]); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci usb_kill_anchored_urbs(&dev->tx_submitted); 69862306a36Sopenharmony_ci atomic_set(&dev->active_tx_urbs, 0); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci for (i = 0; i < MAX_TX_URBS; i++) 70162306a36Sopenharmony_ci dev->tx_contexts[i].echo_index = MAX_TX_URBS; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic int ems_usb_open(struct net_device *netdev) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci struct ems_usb *dev = netdev_priv(netdev); 70762306a36Sopenharmony_ci int err; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci err = ems_usb_write_mode(dev, SJA1000_MOD_RM); 71062306a36Sopenharmony_ci if (err) 71162306a36Sopenharmony_ci return err; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* common open */ 71462306a36Sopenharmony_ci err = open_candev(netdev); 71562306a36Sopenharmony_ci if (err) 71662306a36Sopenharmony_ci return err; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* finally start device */ 71962306a36Sopenharmony_ci err = ems_usb_start(dev); 72062306a36Sopenharmony_ci if (err) { 72162306a36Sopenharmony_ci if (err == -ENODEV) 72262306a36Sopenharmony_ci netif_device_detach(dev->netdev); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci netdev_warn(netdev, "couldn't start device: %d\n", err); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci close_candev(netdev); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci return err; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci netif_start_queue(netdev); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci return 0; 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cistatic netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *netdev) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci struct ems_usb *dev = netdev_priv(netdev); 74062306a36Sopenharmony_ci struct ems_tx_urb_context *context = NULL; 74162306a36Sopenharmony_ci struct net_device_stats *stats = &netdev->stats; 74262306a36Sopenharmony_ci struct can_frame *cf = (struct can_frame *)skb->data; 74362306a36Sopenharmony_ci struct ems_cpc_msg *msg; 74462306a36Sopenharmony_ci struct urb *urb; 74562306a36Sopenharmony_ci u8 *buf; 74662306a36Sopenharmony_ci int i, err; 74762306a36Sopenharmony_ci size_t size = CPC_HEADER_SIZE + CPC_MSG_HEADER_LEN 74862306a36Sopenharmony_ci + sizeof(struct cpc_can_msg); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (can_dev_dropped_skb(netdev, skb)) 75162306a36Sopenharmony_ci return NETDEV_TX_OK; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci /* create a URB, and a buffer for it, and copy the data to the URB */ 75462306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_ATOMIC); 75562306a36Sopenharmony_ci if (!urb) 75662306a36Sopenharmony_ci goto nomem; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci buf = usb_alloc_coherent(dev->udev, size, GFP_ATOMIC, &urb->transfer_dma); 75962306a36Sopenharmony_ci if (!buf) { 76062306a36Sopenharmony_ci netdev_err(netdev, "No memory left for USB buffer\n"); 76162306a36Sopenharmony_ci usb_free_urb(urb); 76262306a36Sopenharmony_ci goto nomem; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci msg = (struct ems_cpc_msg *)&buf[CPC_HEADER_SIZE]; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci msg->msg.can_msg.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK); 76862306a36Sopenharmony_ci msg->msg.can_msg.length = cf->len; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci if (cf->can_id & CAN_RTR_FLAG) { 77162306a36Sopenharmony_ci msg->type = cf->can_id & CAN_EFF_FLAG ? 77262306a36Sopenharmony_ci CPC_CMD_TYPE_EXT_RTR_FRAME : CPC_CMD_TYPE_RTR_FRAME; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci msg->length = CPC_CAN_MSG_MIN_SIZE; 77562306a36Sopenharmony_ci } else { 77662306a36Sopenharmony_ci msg->type = cf->can_id & CAN_EFF_FLAG ? 77762306a36Sopenharmony_ci CPC_CMD_TYPE_EXT_CAN_FRAME : CPC_CMD_TYPE_CAN_FRAME; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci for (i = 0; i < cf->len; i++) 78062306a36Sopenharmony_ci msg->msg.can_msg.msg[i] = cf->data[i]; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci msg->length = CPC_CAN_MSG_MIN_SIZE + cf->len; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci for (i = 0; i < MAX_TX_URBS; i++) { 78662306a36Sopenharmony_ci if (dev->tx_contexts[i].echo_index == MAX_TX_URBS) { 78762306a36Sopenharmony_ci context = &dev->tx_contexts[i]; 78862306a36Sopenharmony_ci break; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci /* 79362306a36Sopenharmony_ci * May never happen! When this happens we'd more URBs in flight as 79462306a36Sopenharmony_ci * allowed (MAX_TX_URBS). 79562306a36Sopenharmony_ci */ 79662306a36Sopenharmony_ci if (!context) { 79762306a36Sopenharmony_ci usb_free_coherent(dev->udev, size, buf, urb->transfer_dma); 79862306a36Sopenharmony_ci usb_free_urb(urb); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci netdev_warn(netdev, "couldn't find free context\n"); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci return NETDEV_TX_BUSY; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci context->dev = dev; 80662306a36Sopenharmony_ci context->echo_index = i; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), buf, 80962306a36Sopenharmony_ci size, ems_usb_write_bulk_callback, context); 81062306a36Sopenharmony_ci urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 81162306a36Sopenharmony_ci usb_anchor_urb(urb, &dev->tx_submitted); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci can_put_echo_skb(skb, netdev, context->echo_index, 0); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci atomic_inc(&dev->active_tx_urbs); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci err = usb_submit_urb(urb, GFP_ATOMIC); 81862306a36Sopenharmony_ci if (unlikely(err)) { 81962306a36Sopenharmony_ci can_free_echo_skb(netdev, context->echo_index, NULL); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci usb_unanchor_urb(urb); 82262306a36Sopenharmony_ci usb_free_coherent(dev->udev, size, buf, urb->transfer_dma); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci atomic_dec(&dev->active_tx_urbs); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (err == -ENODEV) { 82762306a36Sopenharmony_ci netif_device_detach(netdev); 82862306a36Sopenharmony_ci } else { 82962306a36Sopenharmony_ci netdev_warn(netdev, "failed tx_urb %d\n", err); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci stats->tx_dropped++; 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci } else { 83462306a36Sopenharmony_ci netif_trans_update(netdev); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* Slow down tx path */ 83762306a36Sopenharmony_ci if (atomic_read(&dev->active_tx_urbs) >= MAX_TX_URBS || 83862306a36Sopenharmony_ci dev->free_slots < CPC_TX_QUEUE_TRIGGER_LOW) { 83962306a36Sopenharmony_ci netif_stop_queue(netdev); 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci /* 84462306a36Sopenharmony_ci * Release our reference to this URB, the USB core will eventually free 84562306a36Sopenharmony_ci * it entirely. 84662306a36Sopenharmony_ci */ 84762306a36Sopenharmony_ci usb_free_urb(urb); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci return NETDEV_TX_OK; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_cinomem: 85262306a36Sopenharmony_ci dev_kfree_skb(skb); 85362306a36Sopenharmony_ci stats->tx_dropped++; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci return NETDEV_TX_OK; 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic int ems_usb_close(struct net_device *netdev) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct ems_usb *dev = netdev_priv(netdev); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci /* Stop polling */ 86362306a36Sopenharmony_ci unlink_all_urbs(dev); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci netif_stop_queue(netdev); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci /* Set CAN controller to reset mode */ 86862306a36Sopenharmony_ci if (ems_usb_write_mode(dev, SJA1000_MOD_RM)) 86962306a36Sopenharmony_ci netdev_warn(netdev, "couldn't stop device"); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci close_candev(netdev); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci return 0; 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic const struct net_device_ops ems_usb_netdev_ops = { 87762306a36Sopenharmony_ci .ndo_open = ems_usb_open, 87862306a36Sopenharmony_ci .ndo_stop = ems_usb_close, 87962306a36Sopenharmony_ci .ndo_start_xmit = ems_usb_start_xmit, 88062306a36Sopenharmony_ci .ndo_change_mtu = can_change_mtu, 88162306a36Sopenharmony_ci}; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_cistatic const struct ethtool_ops ems_usb_ethtool_ops = { 88462306a36Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 88562306a36Sopenharmony_ci}; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_cistatic const struct can_bittiming_const ems_usb_bittiming_const = { 88862306a36Sopenharmony_ci .name = KBUILD_MODNAME, 88962306a36Sopenharmony_ci .tseg1_min = 1, 89062306a36Sopenharmony_ci .tseg1_max = 16, 89162306a36Sopenharmony_ci .tseg2_min = 1, 89262306a36Sopenharmony_ci .tseg2_max = 8, 89362306a36Sopenharmony_ci .sjw_max = 4, 89462306a36Sopenharmony_ci .brp_min = 1, 89562306a36Sopenharmony_ci .brp_max = 64, 89662306a36Sopenharmony_ci .brp_inc = 1, 89762306a36Sopenharmony_ci}; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_cistatic int ems_usb_set_mode(struct net_device *netdev, enum can_mode mode) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci struct ems_usb *dev = netdev_priv(netdev); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci switch (mode) { 90462306a36Sopenharmony_ci case CAN_MODE_START: 90562306a36Sopenharmony_ci if (ems_usb_write_mode(dev, SJA1000_MOD_NORMAL)) 90662306a36Sopenharmony_ci netdev_warn(netdev, "couldn't start device"); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci if (netif_queue_stopped(netdev)) 90962306a36Sopenharmony_ci netif_wake_queue(netdev); 91062306a36Sopenharmony_ci break; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci default: 91362306a36Sopenharmony_ci return -EOPNOTSUPP; 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci return 0; 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_cistatic int ems_usb_set_bittiming(struct net_device *netdev) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci struct ems_usb *dev = netdev_priv(netdev); 92262306a36Sopenharmony_ci struct can_bittiming *bt = &dev->can.bittiming; 92362306a36Sopenharmony_ci u8 btr0, btr1; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6); 92662306a36Sopenharmony_ci btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) | 92762306a36Sopenharmony_ci (((bt->phase_seg2 - 1) & 0x7) << 4); 92862306a36Sopenharmony_ci if (dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) 92962306a36Sopenharmony_ci btr1 |= 0x80; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci netdev_info(netdev, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci dev->active_params.msg.can_params.cc_params.sja1000.btr0 = btr0; 93462306a36Sopenharmony_ci dev->active_params.msg.can_params.cc_params.sja1000.btr1 = btr1; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci return ems_usb_command_msg(dev, &dev->active_params); 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_cistatic void init_params_sja1000(struct ems_cpc_msg *msg) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci struct cpc_sja1000_params *sja1000 = 94262306a36Sopenharmony_ci &msg->msg.can_params.cc_params.sja1000; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci msg->type = CPC_CMD_TYPE_CAN_PARAMS; 94562306a36Sopenharmony_ci msg->length = sizeof(struct cpc_can_params); 94662306a36Sopenharmony_ci msg->msgid = 0; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci msg->msg.can_params.cc_type = CPC_CC_TYPE_SJA1000; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci /* Acceptance filter open */ 95162306a36Sopenharmony_ci sja1000->acc_code0 = 0x00; 95262306a36Sopenharmony_ci sja1000->acc_code1 = 0x00; 95362306a36Sopenharmony_ci sja1000->acc_code2 = 0x00; 95462306a36Sopenharmony_ci sja1000->acc_code3 = 0x00; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci /* Acceptance filter open */ 95762306a36Sopenharmony_ci sja1000->acc_mask0 = 0xFF; 95862306a36Sopenharmony_ci sja1000->acc_mask1 = 0xFF; 95962306a36Sopenharmony_ci sja1000->acc_mask2 = 0xFF; 96062306a36Sopenharmony_ci sja1000->acc_mask3 = 0xFF; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci sja1000->btr0 = 0; 96362306a36Sopenharmony_ci sja1000->btr1 = 0; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci sja1000->outp_contr = SJA1000_DEFAULT_OUTPUT_CONTROL; 96662306a36Sopenharmony_ci sja1000->mode = SJA1000_MOD_RM; 96762306a36Sopenharmony_ci} 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci/* 97062306a36Sopenharmony_ci * probe function for new CPC-USB devices 97162306a36Sopenharmony_ci */ 97262306a36Sopenharmony_cistatic int ems_usb_probe(struct usb_interface *intf, 97362306a36Sopenharmony_ci const struct usb_device_id *id) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci struct net_device *netdev; 97662306a36Sopenharmony_ci struct ems_usb *dev; 97762306a36Sopenharmony_ci int i, err = -ENOMEM; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci netdev = alloc_candev(sizeof(struct ems_usb), MAX_TX_URBS); 98062306a36Sopenharmony_ci if (!netdev) { 98162306a36Sopenharmony_ci dev_err(&intf->dev, "ems_usb: Couldn't alloc candev\n"); 98262306a36Sopenharmony_ci return -ENOMEM; 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci dev = netdev_priv(netdev); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci dev->udev = interface_to_usbdev(intf); 98862306a36Sopenharmony_ci dev->netdev = netdev; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci dev->can.state = CAN_STATE_STOPPED; 99162306a36Sopenharmony_ci dev->can.clock.freq = EMS_USB_ARM7_CLOCK; 99262306a36Sopenharmony_ci dev->can.bittiming_const = &ems_usb_bittiming_const; 99362306a36Sopenharmony_ci dev->can.do_set_bittiming = ems_usb_set_bittiming; 99462306a36Sopenharmony_ci dev->can.do_set_mode = ems_usb_set_mode; 99562306a36Sopenharmony_ci dev->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci netdev->netdev_ops = &ems_usb_netdev_ops; 99862306a36Sopenharmony_ci netdev->ethtool_ops = &ems_usb_ethtool_ops; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci netdev->flags |= IFF_ECHO; /* we support local echo */ 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci init_usb_anchor(&dev->rx_submitted); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci init_usb_anchor(&dev->tx_submitted); 100562306a36Sopenharmony_ci atomic_set(&dev->active_tx_urbs, 0); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci for (i = 0; i < MAX_TX_URBS; i++) 100862306a36Sopenharmony_ci dev->tx_contexts[i].echo_index = MAX_TX_URBS; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL); 101162306a36Sopenharmony_ci if (!dev->intr_urb) 101262306a36Sopenharmony_ci goto cleanup_candev; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci dev->intr_in_buffer = kzalloc(INTR_IN_BUFFER_SIZE, GFP_KERNEL); 101562306a36Sopenharmony_ci if (!dev->intr_in_buffer) 101662306a36Sopenharmony_ci goto cleanup_intr_urb; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci dev->tx_msg_buffer = kzalloc(CPC_HEADER_SIZE + 101962306a36Sopenharmony_ci sizeof(struct ems_cpc_msg), GFP_KERNEL); 102062306a36Sopenharmony_ci if (!dev->tx_msg_buffer) 102162306a36Sopenharmony_ci goto cleanup_intr_in_buffer; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci usb_set_intfdata(intf, dev); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci SET_NETDEV_DEV(netdev, &intf->dev); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci init_params_sja1000(&dev->active_params); 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci err = ems_usb_command_msg(dev, &dev->active_params); 103062306a36Sopenharmony_ci if (err) { 103162306a36Sopenharmony_ci netdev_err(netdev, "couldn't initialize controller: %d\n", err); 103262306a36Sopenharmony_ci goto cleanup_tx_msg_buffer; 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci err = register_candev(netdev); 103662306a36Sopenharmony_ci if (err) { 103762306a36Sopenharmony_ci netdev_err(netdev, "couldn't register CAN device: %d\n", err); 103862306a36Sopenharmony_ci goto cleanup_tx_msg_buffer; 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci return 0; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_cicleanup_tx_msg_buffer: 104462306a36Sopenharmony_ci kfree(dev->tx_msg_buffer); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cicleanup_intr_in_buffer: 104762306a36Sopenharmony_ci kfree(dev->intr_in_buffer); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_cicleanup_intr_urb: 105062306a36Sopenharmony_ci usb_free_urb(dev->intr_urb); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cicleanup_candev: 105362306a36Sopenharmony_ci free_candev(netdev); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci return err; 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci/* 105962306a36Sopenharmony_ci * called by the usb core when the device is removed from the system 106062306a36Sopenharmony_ci */ 106162306a36Sopenharmony_cistatic void ems_usb_disconnect(struct usb_interface *intf) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci struct ems_usb *dev = usb_get_intfdata(intf); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci usb_set_intfdata(intf, NULL); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if (dev) { 106862306a36Sopenharmony_ci unregister_netdev(dev->netdev); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci unlink_all_urbs(dev); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci usb_free_urb(dev->intr_urb); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci kfree(dev->intr_in_buffer); 107562306a36Sopenharmony_ci kfree(dev->tx_msg_buffer); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci free_candev(dev->netdev); 107862306a36Sopenharmony_ci } 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci/* usb specific object needed to register this driver with the usb subsystem */ 108262306a36Sopenharmony_cistatic struct usb_driver ems_usb_driver = { 108362306a36Sopenharmony_ci .name = KBUILD_MODNAME, 108462306a36Sopenharmony_ci .probe = ems_usb_probe, 108562306a36Sopenharmony_ci .disconnect = ems_usb_disconnect, 108662306a36Sopenharmony_ci .id_table = ems_usb_table, 108762306a36Sopenharmony_ci}; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_cimodule_usb_driver(ems_usb_driver); 1090