⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcan_usb_kernel.c

📁 linux下的CAN BUS驱动代码。适合在arm平台使用。
💻 C
📖 第 1 页 / 共 3 页
字号:
            memset(&ef, 0, sizeof(ef));            // declare as status Msg      msg.Msg.MSGTYPE = MSGTYPE_STATUS;      // prepare length of data      ucLen = ucStatusLen & STLN_DATA_LENGTH;      if (ucLen > 8)        ucLen = 8;      msg.Msg.LEN = ucLen;      // get function and number      ucFunction = *ucMsgPtr++;      ucNumber   = *ucMsgPtr++;      if (ucStatusLen & STLN_WITH_TIMESTAMP)      {        // only the first packet supplies a word timestamp        if (!i)        {          #if defined(__LITTLE_ENDIAN)          wTimeStamp.uc[0] = *ucMsgPtr++;          wTimeStamp.uc[1] = *ucMsgPtr++;          #elif defined(__BIG_ENDIAN)          wTimeStamp.uc[1] = *ucMsgPtr++;          wTimeStamp.uc[0] = *ucMsgPtr++;          #else            #error  "Please fix the endianness defines in <asm/byteorder.h>"          #endif          pcan_updateTimeStampFromWord(dev, wTimeStamp.uw, i);        }        else          pcan_updateTimeStampFromByte(dev, *ucMsgPtr++);      }            switch (ucFunction)      {        case 1: // can_error. number = flags, special decoding in PCAN-USB          if ((ucNumber & CAN_RECEIVE_QUEUE_OVERRUN) || (ucNumber & QUEUE_OVERRUN))          {            dev->wCANStatus |= CAN_ERR_OVERRUN;            ef.can_id  |= CAN_ERR_CRTL;            ef.data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;            dev->dwErrorCounter++;          }          if (ucNumber & BUS_OFF)          {            dev->wCANStatus |=  CAN_ERR_BUSOFF;            ef.can_id |= CAN_ERR_BUSOFF_NETDEV;            dev->dwErrorCounter++;                  }          if (ucNumber & BUS_HEAVY)          {            dev->wCANStatus |=  CAN_ERR_BUSHEAVY;            ef.can_id  |= CAN_ERR_CRTL;            ef.data[1] |= CAN_ERR_CRTL_RX_WARNING;            dev->dwErrorCounter++;                  }          if (ucNumber & BUS_LIGHT)            dev->wCANStatus |= CAN_ERR_BUSLIGHT;                    // version 3: sometimes the telegram carries 3 additional data without note in ucStatusLen.           // Don't know what to do ??          j = 0;          while (ucLen--)            msg.Msg.DATA[j++] = *ucMsgPtr++;          break;        case 2: // get_analog_value, remove bytes          dummy = *ucMsgPtr++;           dummy = *ucMsgPtr++;          break;        case 3: // get_bus_load, remove byte          dummy = *ucMsgPtr++;           break;        case 4: // only timestamp          #if defined(__LITTLE_ENDIAN)          wTimeStamp.uc[0] = *ucMsgPtr++;          wTimeStamp.uc[1] = *ucMsgPtr++;          #elif defined(__BIG_ENDIAN)          wTimeStamp.uc[1] = *ucMsgPtr++;          wTimeStamp.uc[0] = *ucMsgPtr++;          #else            #error  "Please fix the endianness defines in <asm/byteorder.h>"          #endif          pcan_updateTimeStampFromWord(dev, wTimeStamp.uw, i);          break;        case 5: // ErrorFrame/ErrorBusEvent.          if (ucNumber & QUEUE_XMT_FULL)           {            printk(KERN_ERR "%s: QUEUE_XMT_FULL signaled, ucNumber = 0x%02x\n", DEVICE_NAME, ucNumber);            dev->wCANStatus |= CAN_ERR_QXMTFULL; // fatal error!            dev->dwErrorCounter++;          }           j = 0;          while (ucLen--)            msg.Msg.DATA[j++] = *ucMsgPtr++;          break;        case 10: // prepared for future          break;        default:          printk(KERN_ERR "%s: unexpected function, i = %d, ucStatusLen = 0x%02x\n", DEVICE_NAME,                   i, ucStatusLen);          buffer_dump(org, 4);      }            /* if an error condition occurred, send an error frame to the userspace */      if (ef.can_id)       {        ef.can_id  |= CAN_ERR_FLAG;        ef.can_dlc  = CAN_ERR_DLC;        if ((err = pcan_xxxdev_rx(dev, &ef, &tv)) < 0) // put into data sink          goto fail;                if (err > 0) // successfully enqueued into chardev FIFO          rwakeup++;      }     }    // check for 'read from'-buffer overrun    if ((ucMsgPtr - ucMsgStart) > lCurrentLength)    // must be <= dev->port.usb.Endpoint[2].wDataSz)    {      // sometimes version 3 overrides the buffer by 1 byte      if ((dev->port.usb.ucRevision > 3) ||           ((dev->port.usb.ucRevision <= 3) && ((ucMsgPtr - ucMsgStart) > (lCurrentLength + 1))))      {        err = -EFAULT;        #ifdef __LP64__        printk(KERN_ERR "%s: Internal Error = %d (%ld, %d)\n", DEVICE_NAME, err, (ucMsgPtr - ucMsgStart), lCurrentLength);        #else        printk(KERN_ERR "%s: Internal Error = %d (%d, %d)\n", DEVICE_NAME, err, (ucMsgPtr - ucMsgStart), lCurrentLength);        #endif        buffer_dump(org, 4);        goto fail;      }    }  }  if (rwakeup)    wake_up_interruptible(&dev->read_queue);  fail:  return err;}// gets messages out of write-fifo, encodes and puts them into USB buffer ucMsgPtr// returns -ENODATA and *pnDataLength > 0 if I made a telegram and no more data are available//         -ENODATA and *pnDataLength == 0 if I made no telegram and no more data are available//         any ERROR else if something happend//         no ERROR if I made a telegram and there are more data availableint pcan_hw_EncodeMessage(struct pcandev *dev, u8 *ucMsgPtr, int *pnDataLength){  int err         = 0;  int nMsgCounter = 0;          // counts the messages stored in this URB packet  u8  *ptr        = ucMsgPtr;   // work pointer into write buffer  u8  ucLen;                    // CAN data length  ULCONV localID;               // for easy endian conversion  u8    *pucStatusLen;          // pointer to ucStatusLen byte in URB message buffer  u8    *pucMsgCountPtr;        // pointer to MsgCount byte in URB message buffer  int   j;                      // working counter  u8    bFinish = 0;  int   nDataLength = *pnDataLength;    int   nBufferTop  = nDataLength - 14;  // buffer fill high water mark   // DPRINTK(KERN_DEBUG "%s: pcan_hw_EncodeMessage() %d %d\n", DEVICE_NAME, dev->writeFifo.nStored, pcan_fifo_empty(&dev->writeFifo));  // indicate no packet  *pnDataLength = 0;  // put packet type information  *ptr++ = 2;  pucMsgCountPtr = ptr++;  // fill later the count of messages  // pack packet  while (!bFinish && ((ptr - ucMsgPtr) < nBufferTop))  {    int nRtrFrame;    TPCANMsg msg;                // pointer to supplied CAN message        // release fifo buffer and step forward in fifo    if ((err = pcan_fifo_get(&dev->writeFifo, &msg)))    {      bFinish = 1;            if (err != -ENODATA)      {        DPRINTK(KERN_DEBUG "%s: can't get data out of writeFifo, avail data: %d, err: %d\n", DEVICE_NAME, dev->writeFifo.nStored, err);      }              continue;    }          // get ptr to ucStatusLen byte    pucStatusLen = ptr++;        *pucStatusLen = ucLen = msg.LEN & STLN_DATA_LENGTH;          nRtrFrame = msg.MSGTYPE & MSGTYPE_RTR;    if (nRtrFrame)      *pucStatusLen |= STLN_RTR;  // add RTR flag    j = 0;    localID.ul = msg.ID;    if (msg.MSGTYPE & MSGTYPE_EXTENDED)    {      *pucStatusLen |= STLN_EXTENDED_ID;      localID.ul   <<= 3;      #if defined(__LITTLE_ENDIAN)      *ptr++ = localID.uc[0];      *ptr++ = localID.uc[1];      *ptr++ = localID.uc[2];      *ptr++ = localID.uc[3];      #elif defined(__BIG_ENDIAN)      *ptr++ = localID.uc[3];      *ptr++ = localID.uc[2];      *ptr++ = localID.uc[1];      *ptr++ = localID.uc[0];      #else        #error  "Please fix the endianness defines in <asm/byteorder.h>"      #endif    }    else    {      localID.ul   <<= 5;      #if defined(__LITTLE_ENDIAN)      *ptr++ = localID.uc[0];      *ptr++ = localID.uc[1];      #elif defined(__BIG_ENDIAN)      *ptr++ = localID.uc[3];      *ptr++ = localID.uc[2];      #else        #error  "Please fix the endianness defines in <asm/byteorder.h>"      #endif    }    if (!nRtrFrame)    {      // put data      j = 0;      while (ucLen--)        *ptr++ = msg.DATA[j++];    }    nMsgCounter++;  }  // generate external nDataLength if I carry payload  if ((ptr - ucMsgPtr) > 2)  {    *pnDataLength = nDataLength;    // set count of telegrams    ptr = ucMsgPtr + nDataLength - 1;    *ptr = (u8)(dev->port.usb.dwTelegramCount++ & 0xff);    // last to do: put count of messages    *pucMsgCountPtr = nMsgCounter;  }  else  {    *pnDataLength   = 0;    *pucMsgCountPtr = 0;  }  return err;}#ifdef NETDEV_SUPPORT// writes a CAN-Frame pointed to by *cf into USB buffer ucMsgPtr// returns -ENODATA and *pnDataLength > 0 if I made a telegram and no more data are available//         -ENODATA and *pnDataLength == 0 if I made no telegram and no more data are available//         any ERROR else if something happend//         no ERROR if I made a telegram and there are more data availableint pcan_hw_EncodeMessage_frame(struct pcandev *dev, struct can_frame *cf, u8 *ucMsgPtr, int *pnDataLength){  int nMsgCounter = 0;          // counts the messages stored in this URB packet  u8  *ptr        = ucMsgPtr;   // work pointer into write buffer  u8  ucLen;                    // CAN data length  ULCONV localID;               // for easy endian conversion  u8    *pucStatusLen;          // pointer to ucStatusLen byte in URB message buffer  u8    *pucMsgCountPtr;        // pointer to MsgCount byte in URB message buffer  int   j;                      // working counter  int   nDataLength = *pnDataLength;    DPRINTK(KERN_DEBUG "%s: pcan_hw_EncodeMessage_frame() %d %d\n", DEVICE_NAME, dev->writeFifo.nStored, pcan_fifo_empty(&dev->writeFifo));  // indicate no packet  *pnDataLength = 0;  // put packet type information  *ptr++ = 2;  pucMsgCountPtr = ptr++;  // fill later the count of messages  // pack packet  // get ptr to ucStatusLen byte  pucStatusLen = ptr++;        *pucStatusLen = ucLen = cf->can_dlc & STLN_DATA_LENGTH;          if (cf->can_id & CAN_RTR_FLAG)    *pucStatusLen |= STLN_RTR;  // add RTR flag  if (cf->can_id & CAN_EFF_FLAG)  {    localID.ul = cf->can_id & CAN_EFF_MASK;    *pucStatusLen |= STLN_EXTENDED_ID;    localID.ul   <<= 3;    #if defined(__LITTLE_ENDIAN)    *ptr++ = localID.uc[0];    *ptr++ = localID.uc[1];    *ptr++ = localID.uc[2];    *ptr++ = localID.uc[3];    #elif defined(__BIG_ENDIAN)    *ptr++ = localID.uc[3];    *ptr++ = localID.uc[2];    *ptr++ = localID.uc[1];    *ptr++ = localID.uc[0];    #else      #error  "Please fix the endianness defines in <asm/byteorder.h>"    #endif  }  else  {    localID.ul = cf->can_id & CAN_SFF_MASK;    localID.ul   <<= 21;    #if defined(__LITTLE_ENDIAN)    *ptr++ = localID.uc[2];    *ptr++ = localID.uc[3];    #elif defined(__BIG_ENDIAN)    *ptr++ = localID.uc[3];    *ptr++ = localID.uc[2];    #else      #error  "Please fix the endianness defines in <asm/byteorder.h>"    #endif  }  // put data  j = 0;  while (ucLen--)    *ptr++ = cf->data[j++];  nMsgCounter++;  // generate external nDataLength if I carry payload  if ((ptr - ucMsgPtr) > 2)  {    *pnDataLength = nDataLength;    // set count of telegrams    ptr = ucMsgPtr + nDataLength - 1;    *ptr = (u8)(dev->port.usb.dwTelegramCount++ & 0xff);    // last to do: put count of messages    *pucMsgCountPtr = nMsgCounter;  }  else  {    *pnDataLength   = 0;    *pucMsgCountPtr = 0;  }  return -ENODATA; /* simulate empty fifo return value */}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -