📄 pcan_usb_kernel.c
字号:
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 + -