📄 pcan_usb.c
字号:
}static int pcan_usb_stop(struct pcandev *dev){ int err = 0; USB_PORT *u = &dev->port.usb; unsigned long dwFlags = 0; int i = 100; DPRINTK(KERN_DEBUG "%s: pcan_usb_stop()\n", DEVICE_NAME); err = pcan_hw_SetCANOff(dev); // wait until all has settled mdelay(5); // unlink URB spin_lock_irqsave(&u->lock, dwFlags); if (u->read_data->status == -EINPROGRESS) { err = usb_unlink_urb(u->read_data); DPRINTK(KERN_DEBUG "%s: usb_unlink_urb(), read = %d\n", DEVICE_NAME, err); } spin_unlock_irqrestore (&u->lock, dwFlags); // unlink writeURB spin_lock_irqsave(&u->lock, dwFlags); if (u->write_data->status == -EINPROGRESS) { err = usb_unlink_urb(u->write_data); DPRINTK(KERN_DEBUG "%s: usb_unlink_urb(), write = %d\n", DEVICE_NAME, err); } spin_unlock_irqrestore (&u->lock, dwFlags); // unlink parameter urb spin_lock_irqsave(&u->lock, dwFlags); if (u->param_urb->status == -EINPROGRESS) { err = usb_unlink_urb(u->param_urb); DPRINTK(KERN_DEBUG "%s: usb_unlink_urb(), param = %d\n", DEVICE_NAME, err); } spin_unlock_irqrestore (&u->lock, dwFlags); // wait until all urbs returned to sender // (I hope) this should be no problem because all urb's are unlinked while ((atomic_read(&u->active_urbs) > 0) && (i--)) schedule(); if (i <= 0) { DPRINTK(KERN_ERR "%s: have still active URBs: %d!\n", DEVICE_NAME, atomic_read(&u->active_urbs)); } return err;}//****************************************************************************// remove device resources //static int pcan_usb_cleanup(struct pcandev *dev){ DPRINTK(KERN_DEBUG "%s: pcan_usb_cleanup()\n", DEVICE_NAME); if (dev) { pcan_usb_free_resources(dev); switch(dev->wInitStep) { case 3: usb_devices--; pcan_drv.wDeviceCount--; case 2: list_del(&dev->list); case 1: case 0: dev->wInitStep = 0; kfree(dev); } } return 0;}// dummy entries for request and free irqstatic int pcan_usb_req_irq(struct pcandev *dev){ DPRINTK(KERN_DEBUG "%s: pcan_usb_req_irq()\n", DEVICE_NAME); return 0;}static void pcan_usb_free_irq(struct pcandev *dev){ DPRINTK(KERN_DEBUG "%s: pcan_usb_free_irq()\n", DEVICE_NAME); // mis-used here for another purpose // pcan_usb_free_irq() calls when the last path to device just closing // and the device itself is already plugged out if ((dev) && (!dev->ucPhysicallyInstalled)) pcan_usb_cleanup(dev);}// interface depended open and closestatic int pcan_usb_open(struct pcandev *dev){ DPRINTK(KERN_DEBUG "%s: pcan_usb_open()\n", DEVICE_NAME); return 0;}static int pcan_usb_release(struct pcandev *dev){ DPRINTK(KERN_DEBUG "%s: pcan_usb_release()\n", DEVICE_NAME); return 0;}// emulated device access functions// call is only possible if device existsstatic int pcan_usb_device_open(struct pcandev *dev, u16 btr0btr1, u8 bExtended, u8 bListenOnly){ int err = 0; DPRINTK(KERN_DEBUG "%s: pcan_usb_device_open()\n", DEVICE_NAME); // first action: turn CAN off if ((err = pcan_hw_SetCANOff(dev))) goto fail; if ((err = pcan_usb_start(dev))) goto fail; // init hardware specific parts if ((err = pcan_hw_Init(dev, btr0btr1, bListenOnly))) goto fail; // store extended mode (standard still accepted) dev->bExtended = bExtended; // take a fresh status dev->wCANStatus = 0; // copy from NT driver mdelay(20); // last action: turn CAN on if ((err = pcan_hw_SetCANOn(dev))) goto fail; fail: return err;}static void pcan_usb_device_release(struct pcandev *dev){ DPRINTK(KERN_DEBUG "%s: pcan_usb_device_release()\n", DEVICE_NAME); // do not stop usb immediately, give a chance for the USB-dongle to send this telegram mdelay(100); pcan_usb_stop(dev);}static int pcan_usb_device_write(struct pcandev *dev){ return pcan_usb_write(dev);}//****************************************************************************// special assignment of minors due to PuP//static int assignMinorNumber(struct pcandev *dev){ int searchedMinor; u8 occupied; struct pcandev *devWork = (struct pcandev *)NULL; struct list_head *ptr; DPRINTK(KERN_DEBUG "%s: assignMinorNumber()\n", DEVICE_NAME); for (searchedMinor = PCAN_USB_MINOR_BASE; searchedMinor < (PCAN_USB_MINOR_BASE + 8); searchedMinor++) { occupied = 0; // loop trough my devices for (ptr = pcan_drv.devices.next; ptr != &pcan_drv.devices; ptr = ptr->next) { devWork = (struct pcandev *)ptr; // stop if it is occupied if (devWork->nMinor == searchedMinor) { occupied = 1; break; } } // jump out when the first available number is found if (!occupied) break; } if (!occupied) { dev->nMinor = searchedMinor; return 0; } else { dev->nMinor = -1; return -ENXIO; }}//****************************************************************************// things todo after plugin or plugout of device (and power on too)//#ifndef LINUX_22static void *pcan_usb_plugin(struct usb_device *usb_dev, unsigned int interface, const struct usb_device_id *id_table)#elsestatic void *pcan_usb_plugin(struct usb_device *usb_dev, unsigned int interface)#endif{ struct pcandev *dev = NULL; int err = 0; int i; USB_PORT *u; struct usb_interface_descriptor *current_interface_setting; DPRINTK(KERN_DEBUG "%s: pcan_usb_plugin(0x%04x, 0x%04x, %d)\n", DEVICE_NAME, usb_dev->descriptor.idVendor, usb_dev->descriptor.idProduct, interface); if ((usb_dev->descriptor.idVendor == PCAN_USB_VENDOR_ID) && (usb_dev->descriptor.idProduct == PCAN_USB_PRODUCT_ID)) { // take the 1st configuration (it's default) if (usb_set_configuration (usb_dev, usb_dev->config[0].bConfigurationValue) < 0) { printk(KERN_ERR "%s: usb_set_configuration() failed!\n", DEVICE_NAME); goto reject; } // only 1 interface is supported if (usb_set_interface (usb_dev, 0, 0) < 0) { printk(KERN_ERR "%s: usb_set_interface() failed!\n", DEVICE_NAME); goto reject; } // allocate memory for my device if ((dev = (struct pcandev *)kmalloc(sizeof(struct pcandev), GFP_KERNEL)) == NULL) { printk(KERN_ERR "%s: pcan_usb_plugin - memory allocation failed!\n", DEVICE_NAME); goto reject; } dev->wInitStep = 0; u = &dev->port.usb; // init structure elements to defaults pcan_soft_init(dev, "usb", HW_USB); // preset finish flags atomic_set(&u->param_xmit_finished, 0); // preset active URB counter atomic_set(&u->active_urbs, 0); // override standard device access functions dev->device_open = pcan_usb_device_open; dev->device_release = pcan_usb_device_release; dev->device_write = pcan_usb_device_write; // init process wait queues init_waitqueue_head(&dev->read_queue); init_waitqueue_head(&dev->write_queue); // set this before any instructions, fill struct pcandev, part 1 dev->wInitStep = 0; dev->readreg = NULL; dev->writereg = NULL; dev->cleanup = pcan_usb_cleanup; dev->req_irq = pcan_usb_req_irq; dev->free_irq = pcan_usb_free_irq; dev->open = pcan_usb_open; dev->release = pcan_usb_release; if ((err = assignMinorNumber(dev))) goto reject; // store pointer to kernel supplied usb_dev u->usb_dev = usb_dev; u->ucHardcodedDevNr = (u8)(usb_dev->descriptor.bcdDevice & 0xff); u->ucRevision = (u8)(usb_dev->descriptor.bcdDevice >> 8); u->pvXptr = NULL; printk(KERN_INFO "%s: Hardware Revision = %d\n", DEVICE_NAME, u->ucRevision); // get endpoint addresses (numbers) and associated max data length current_interface_setting = &usb_dev->actconfig->interface->altsetting[usb_dev->actconfig->interface->act_altsetting]; for (i = 0; i < 4; i++) { u->Endpoint[i].ucNumber = current_interface_setting->endpoint[i].bEndpointAddress; u->Endpoint[i].wDataSz = current_interface_setting->endpoint[i].wMaxPacketSize; } spin_lock_init(&u->lock); init_waitqueue_head(&u->usb_wait_queue); dev->wInitStep = 1; // add into list of devices list_add_tail(&dev->list, &pcan_drv.devices); // add this device to the list dev->wInitStep = 2; // assign the device as plugged in dev->ucPhysicallyInstalled = 1; pcan_drv.wDeviceCount++; usb_devices++; dev->wInitStep = 3; if ((err = pcan_usb_allocate_resources(dev))) goto reject; printk(KERN_INFO "%s: pcan_usb_plugin() is OK (minor = %d).\n", DEVICE_NAME, dev->nMinor); return (void *)dev; reject: pcan_usb_cleanup(dev); printk(KERN_ERR "%s: pcan_usb_plugin() failed! (%d)\n", DEVICE_NAME, err); } return NULL;}//****************************************************************************// is called at plug out of device//static void pcan_usb_plugout(struct usb_device *usb_dev, void *drv_context){ struct pcandev *dev = (struct pcandev *)drv_context; if (dev) { DPRINTK(KERN_DEBUG "%s: pcan_usb_plugout(%d)\n", DEVICE_NAME, dev->nMinor); // mark this device as plugged out dev->ucPhysicallyInstalled = 0; // do not remove resources if the device is still in use if (!dev->nOpenPaths) pcan_usb_cleanup(dev); }}//****************************************************************************// propagate getting of serial number to my 'small' interface//int pcan_usb_getSerialNumber(struct pcandev *dev){ if (dev && dev->ucPhysicallyInstalled) return pcan_hw_getSNR(dev, &dev->port.usb.dwSerialNumber); else return -ENODEV;}//****************************************************************************// small interface to rest of driver, only init and deinit//int pcan_usb_init(void){ DPRINTK(KERN_DEBUG "%s: pcan_usb_init()\n", DEVICE_NAME); memset (&pcan_drv.usbdrv, 0, sizeof(pcan_drv.usbdrv)); pcan_drv.usbdrv.probe = pcan_usb_plugin; pcan_drv.usbdrv.disconnect = pcan_usb_plugout; pcan_drv.usbdrv.name = DEVICE_NAME; pcan_drv.usbdrv.minor = PCAN_USB_MINOR_BASE; #ifndef LINUX_22 pcan_drv.usbdrv.id_table = pcan_usb_ids; #endif return usb_register(&pcan_drv.usbdrv);}void pcan_usb_deinit(void){ DPRINTK(KERN_DEBUG "%s: pcan_usb_deinit()\n", DEVICE_NAME); // unregister usb parts, makes a plugout of registered devices usb_deregister(&pcan_drv.usbdrv);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -