📄 pcan_usb.c
字号:
//****************************************************************************// Copyright (C) 2001,2002,2003 PEAK System-Technik GmbH//// linux@peak-system.com// www.peak-system.com//// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//// Maintainer(s): Klaus Hitschler (klaus.hitschler@gmx.de)//****************************************************************************//****************************************************************************//// pcan_usb.c - the outer usb parts for pcan-usb support//// $Log: pcan_usb.c,v $// Revision 1.2 2003/03/02 10:46:31 klaus// merged USB thread into main path//// Revision 1.1.2.36 2003/02/25 20:23:37 klaus// moved pcan_usb_start() from pcan_open() to pcan_device_open()//// Revision 1.1.2.35 2003/02/24 19:12:43 klaus// added debug message at 'while .. schedule()'//// Revision 1.1.2.34 2003/02/23 19:33:06 klaus// tried to fix "not possible to stop" bug//// Revision 1.1.2.33 2003/02/16 19:55:52 klaus// USB Integration, first non public release//// Revision 1.1.2.32 2003/02/16 16:36:16 klaus// pcan_usb_kernel.c returned to main modules//// Revision 1.1.2.31 2003/02/09 13:18:09 klaus// modifications to support linux 2.2.19 kernels//// Revision 1.1.2.30 2003/02/09 13:18:09 klaus// modifications to support linux 2.2.19 kernels//// Revision 1.1.2.29 2003/02/09 10:29:20 klaus// code cleanup, Release_20030208_x//// Revision 1.1.2.28 2003/02/08 19:33:48 klaus// cosmetic changes//// Revision 1.1.2.27 2003/02/08 17:32:43 klaus// modified to use pcan_usb_kernel as prorietary module//// Revision 1.1.2.26 2003/02/05 23:12:19 klaus// adapted to RedHat 7.2//// Revision 1.1.2.25 2003/01/29 20:34:20 klaus// release_20030129_a and release_20030129_u released////****************************************************************************//****************************************************************************// INCLUDES#include <src/pcan_common.h> // must always be the 1st include#include <linux/stddef.h> // NULL#include <linux/errno.h>#include <linux/slab.h> // kmalloc()#ifndef LINUX_22#include <linux/module.h> // MODULE_DEVICE_TABLE()#endif#include <linux/usb.h>#include <src/pcan_usb.h>#include <src/pcan_usb_kernel.h>//****************************************************************************// DEFINES#define PCAN_USB_MINOR_BASE 32 // starting point of minors for USB devices#define PCAN_USB_VENDOR_ID 0x0c72#define PCAN_USB_PRODUCT_ID 0x000c#define URB_READ_BUFFER_SIZE 1024 // buffer for read URB data (IN)#define URB_READ_BUFFER_SIZE_OLD 64 // used length for revision < 6//****************************************************************************// GLOBALS#ifndef LINUX_22static struct usb_device_id pcan_usb_ids[] ={ { USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USB_PRODUCT_ID) }, { } // Terminating entry};MODULE_DEVICE_TABLE (usb, pcan_usb_ids);#endif//****************************************************************************// LOCALSstatic u16 usb_devices = 0; // the number of accepted usb_devices//****************************************************************************// CODE//****************************************************************************// get cyclic data from endpoint 2static void pcan_usb_write_notify(purb_t purb);static int pcan_usb_write(struct pcandev *dev){ int err = 0; USB_PORT *u = &dev->port.usb; int nDataLength = u->Endpoint[3].wDataSz; DPRINTK(KERN_DEBUG "%s: pcan_usb_write()\n", DEVICE_NAME); // don't do anything with non-existent hardware if (!dev->ucPhysicallyInstalled) return -ENODEV; err = pcan_hw_Y(dev, u->pucWriteBuffer, &nDataLength); // fill the URB and submit if (nDataLength) { FILL_BULK_URB(u->write_data, u->usb_dev, usb_sndbulkpipe(u->usb_dev, u->Endpoint[3].ucNumber), u->pucWriteBuffer, nDataLength, pcan_usb_write_notify, dev); // start next urb if ((err = usb_submit_urb(u->write_data))) { dev->nLastError = err; dev->dwErrorCounter++; DPRINTK(KERN_ERR "%s: pcan_usb_write() can't submit! (%d)",DEVICE_NAME, err); } else atomic_add(1, &dev->port.usb.active_urbs); } // it's no error if I can't get more data but still a packet was sent if ((err == -ENODATA) && (nDataLength)) err = 0; return err;}//****************************************************************************// notify functions for read and write datastatic void pcan_usb_write_notify(purb_t purb){ int err = 0; u16 wwakeup = 0; struct pcandev *dev = purb->context; // DPRINTK(KERN_DEBUG "%s: pcan_usb_write_notify() (%d)\n", DEVICE_NAME, purb->status); // un-register outstanding urb atomic_sub(1, &dev->port.usb.active_urbs); // don't count interrupts - count packets dev->dwInterruptCounter++; // do write if (!purb->status) // stop with first error err = pcan_usb_write(dev); if (err == -ENODATA) wwakeup++; else { dev->nLastError = err; dev->dwErrorCounter++; dev->wCANStatus |= CAN_ERR_QXMTFULL; // fatal error! } if (wwakeup) { atomic_set(&dev->DataSendReady, 1); // signal to write I'm ready wake_up_interruptible(&dev->write_queue); }}static void pcan_usb_read_notify(purb_t purb){ int err = 0; struct pcandev *dev = purb->context; USB_PORT *u = &dev->port.usb; // DPRINTK(KERN_DEBUG "%s: pcan_usb_read_notify() (%d)\n", DEVICE_NAME, purb->status); // un-register outstanding urb atomic_sub(1, &dev->port.usb.active_urbs); // don't count interrupts - count packets dev->dwInterruptCounter++; // do interleaving read if (!purb->status && dev->ucPhysicallyInstalled) // stop with first error { u8 *m_pucTransferBuffer = purb->transfer_buffer; int m_nCurrentLength = purb->actual_length; // buffer interleave to increase speed if (m_pucTransferBuffer == u->pucReadBuffer[0]) { FILL_BULK_URB(purb, u->usb_dev, usb_rcvbulkpipe(u->usb_dev, u->Endpoint[2].ucNumber), u->pucReadBuffer[1], u->wReadBufferLength, pcan_usb_read_notify, dev); } else { FILL_BULK_URB(purb, u->usb_dev, usb_rcvbulkpipe(u->usb_dev, u->Endpoint[2].ucNumber), u->pucReadBuffer[0], u->wReadBufferLength, pcan_usb_read_notify, dev); } // start next urb if ((err = usb_submit_urb(purb))) { dev->nLastError = err; dev->dwErrorCounter++; printk(KERN_ERR "%s: pcan_usb_read_notify() can't submit! (%d)",DEVICE_NAME, err); } else atomic_add(1, &dev->port.usb.active_urbs); err = pcan_hw_X(dev, m_pucTransferBuffer, m_nCurrentLength); if (err) { dev->nLastError = err; dev->wCANStatus |= CAN_ERR_QOVERRUN; dev->dwErrorCounter++; DPRINTK(KERN_DEBUG "%s: error %d from hw_DecodeMessage()\n", DEVICE_NAME, err); } } else { printk(KERN_ERR "%s: read data stream torn off caused by ", DEVICE_NAME); if (!dev->ucPhysicallyInstalled) printk("device plug out!\n"); else printk("err %d!\n", purb->status); }}//****************************************************************************// usb resource allocation //static int pcan_usb_allocate_resources(struct pcandev *dev){ int err = 0; USB_PORT *u = &dev->port.usb; DPRINTK(KERN_DEBUG "%s: pcan_usb_allocate_resources()\n", DEVICE_NAME); // allocate X data for comparison if (!u->pvXptr) { if (!(u->pvXptr = kmalloc(pcan_X(), GFP_KERNEL))) { err = -ENOMEM; goto fail; } } dev->wInitStep = 4; // make param URB u->param_urb = usb_alloc_urb(0); if (!u->param_urb) err = -ENOMEM; dev->wInitStep = 5; // allocate write buffer u->pucWriteBuffer = kmalloc(u->Endpoint[3].wDataSz, GFP_KERNEL); DPRINTK(KERN_DEBUG "%s: kmalloc() = %p\n", DEVICE_NAME, u->pucWriteBuffer); if (!u->pucWriteBuffer) { err = -ENOMEM; goto fail; } dev->wInitStep = 6; // make write urb u->write_data = usb_alloc_urb(0); if (!u->write_data) { err = -ENOMEM; goto fail; } dev->wInitStep = 7; // reset telegram count u->dwTelegramCount = 0; // allocate both read buffers for URB u->pucReadBuffer[0] = kmalloc(URB_READ_BUFFER_SIZE * 2, GFP_KERNEL); DPRINTK(KERN_DEBUG "%s: kmalloc() = %p\n", DEVICE_NAME, u->pucReadBuffer[0]); if (!u->pucReadBuffer[0]) { err = -ENOMEM; goto fail; } u->pucReadBuffer[1] = u->pucReadBuffer[0] + URB_READ_BUFFER_SIZE; dev->wInitStep = 8; // make read urb u->read_data = usb_alloc_urb(0); if (!u->read_data) { err = -ENOMEM; goto fail; } dev->wInitStep = 9; // different revisions use different buffer sizes if (u->ucRevision < 6) u->wReadBufferLength = URB_READ_BUFFER_SIZE_OLD; else u->wReadBufferLength = URB_READ_BUFFER_SIZE; fail: return err;}//****************************************************************************// usb resource de-allocation //static int pcan_usb_free_resources(struct pcandev *dev){ int err = 0; USB_PORT *u = &dev->port.usb; DPRINTK(KERN_DEBUG "%s: pcan_usb_free_resources()\n", DEVICE_NAME); // at this point no URB must be pending // this is forced at pcan_usb_stop switch (dev->wInitStep) { case 9: // free read URB usb_free_urb(u->read_data); case 8: kfree(u->pucReadBuffer[0]); case 7: // free write urb usb_free_urb(u->write_data); case 6: kfree(u->pucWriteBuffer); case 5: // free param urb usb_free_urb(u->param_urb); case 4: // remove X information if (u->pvXptr) { kfree(u->pvXptr); u->pvXptr = NULL; } dev->wInitStep = 3; } return err;}//****************************************************************************// start and stop functions for CAN data IN and OUTstatic int pcan_usb_start(struct pcandev *dev){ int err = 0; USB_PORT *u = &dev->port.usb; DPRINTK(KERN_DEBUG "%s: pcan_usb_start()\n", DEVICE_NAME); FILL_BULK_URB(u->read_data, u->usb_dev, usb_rcvbulkpipe(u->usb_dev, u->Endpoint[2].ucNumber), u->pucReadBuffer[0], u->wReadBufferLength, pcan_usb_read_notify, dev); // submit urb if ((err = usb_submit_urb(u->read_data))) printk(KERN_ERR "%s: pcan_usb_start() can't submit! (%d)\n",DEVICE_NAME, err); else atomic_add(1, &dev->port.usb.active_urbs); return err;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -