📄 pcan_pccard_kernel.c
字号:
card->activity_timer.data = (unsigned long)card; card->activity_timer.expires = jiffies + HZ; // one second card->run_activity_timer_cyclic = 1; add_timer(&card->activity_timer);}static void pccard_stop_activity_scanner(PCAN_PCCARD *card){ DPRINTK(KERN_DEBUG "%s: pccard_stop_activity_scanner(%p)\n", DEVICE_NAME, card); card->run_activity_timer_cyclic = 0; del_timer_sync(&card->activity_timer);}//****************************************************************************// all about interrupt handling// make a special irqhandler since PCCARD irqs are ISA likestatic irqreturn_t IRQHANDLER(pcan_pccard_irqhandler, int irq, void *dev_id, struct pt_regs *regs){ struct pcandev *dev = (struct pcandev *)dev_id; PCAN_PCCARD *card = dev->port.pccard.card; int ret = 0; u16 stop_count = 100; // prevent to loop infinitely to get all shared interrupts cleared u16 loop_count; u16 index; // DPRINTK(KERN_DEBUG "%s: pcan_pccard_irqhandler(%p)\n", DEVICE_NAME, dev_id); for (index = 0, loop_count = 0; loop_count < PCCARD_CHANNELS; index++) { if ((dev = card->dev[index % PCCARD_CHANNELS])) // consider singel channel cards, too {/* XXX TODO */ int tmpret = IRQHANDLER(sja1000_base_irqhandler, irq, dev, regs); if (!tmpret) loop_count++; else { ret = 1; loop_count = 0; // restart, since all channels must respond in one pass with no interrupt pending } if (!stop_count--) { printk(KERN_ERR "%s: Too much PCCARD interrupt load, processing halted!\n", DEVICE_NAME); break; } } else loop_count++; if (loop_count == PCCARD_CHANNELS) break; } return PCAN_IRQ_RETVAL(ret);}static int pccard_req_irq(struct pcandev *dev){ int err; DPRINTK(KERN_DEBUG "%s: pccard_req_irq()\n", DEVICE_NAME); if (dev->wInitStep == 4) { if ((err = request_irq(dev->port.pccard.wIrq, pcan_pccard_irqhandler, IRQF_DISABLED | IRQF_SHARED, "pcan", dev))) return err; dev->wInitStep = 5; } return 0;}static void pccard_free_irq(struct pcandev *dev){ DPRINTK(KERN_DEBUG "%s: pccard_free_irq()\n", DEVICE_NAME); if (dev->wInitStep >= 5) { free_irq(dev->port.pccard.wIrq, dev); dev->wInitStep = 4; }}//****************************************************************************// free allocated resourcesstatic int pccard_cleanup(struct pcandev *dev){ DPRINTK(KERN_DEBUG "%s: pccard_cleanup()\n", DEVICE_NAME); if (dev) { switch(dev->wInitStep) { case 5: pccard_free_irq(dev); case 4: dev->ucActivityState = ACTIVITY_NONE; // temporary #ifdef NETDEV_SUPPORT pcan_netdev_unregister(dev); #endif case 3: pcan_drv.wDeviceCount--; pccard_devices--; case 2: dev->ucPhysicallyInstalled = 0; list_del(&dev->list); case 1: #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8) DPRINTK(KERN_DEBUG "%s: release_region(PCCARD_PORT_SIZE)\n", DEVICE_NAME); release_region(dev->port.pccard.dwPort, PCCARD_PORT_SIZE); #endif case 0: pcan_delete_filter_chain(dev->filter); dev->filter = NULL; dev->wInitStep = 0; DPRINTK(KERN_DEBUG "%s: kfree(PCANDEV=0x%p)\n", DEVICE_NAME, dev); kfree(dev); dev = NULL; } } return 0;}//****************************************************************************// interface depended open and closestatic int pccard_open(struct pcandev *dev){ DPRINTK(KERN_DEBUG "%s: pccard_open()\n", DEVICE_NAME); dev->ucActivityState = ACTIVITY_IDLE; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) dev->port.pccard.card->pcc_dev->open++; #else dev->port.pccard.card->link.open++; #endif return 0;}static int pccard_release(struct pcandev *dev){ DPRINTK(KERN_DEBUG "%s: pccard_release()\n", DEVICE_NAME); dev->ucActivityState = ACTIVITY_INITIALIZED; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) if (dev->port.pccard.card->pcc_dev->open > 0) dev->port.pccard.card->pcc_dev->open--; #else if (dev->port.pccard.card->link.open > 0) dev->port.pccard.card->link.open--; #endif return 0;}//****************************************************************************// create and init a single pccard pcan device structurestatic struct pcandev *pccard_create_single_device(PCAN_PCCARD *card, int nChannel, u32 dwPort, u16 wIrq){ struct pcandev *dev; PCCARD_PORT *p; int err = 0; DPRINTK(KERN_DEBUG "%s: pccard_create_single_device(%d, 0x%04x, %d)\n", DEVICE_NAME, nChannel, dwPort, wIrq); // allocate memory for my device if ((dev = (struct pcandev *)kmalloc(sizeof(struct pcandev), GFP_ATOMIC)) == NULL) { printk(KERN_ERR "%s: pccard_create_single_device - memory allocation failed!\n", DEVICE_NAME); err = -ENOMEM; goto fail; } DPRINTK(KERN_DEBUG "%s: kmalloc() = 0x%p\n", DEVICE_NAME, dev); memset(dev, 0x00, sizeof(*dev)); dev->wInitStep = 0; // init structure elements to defaults pcan_soft_init(dev, "pccard", HW_PCCARD); // device handling standards for sja1000 driven parts dev->device_open = sja1000_open; dev->device_release = sja1000_release; dev->device_write = sja1000_write; #ifdef NETDEV_SUPPORT dev->netdevice_write = sja1000_write_frame; #endif // 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->readreg = pccard_readreg; dev->writereg = pccard_writereg; dev->cleanup = pccard_cleanup; dev->req_irq = pccard_req_irq; dev->free_irq = pccard_free_irq; dev->open = pccard_open; dev->release = pccard_release; dev->nMinor = PCCARD_MINOR_BASE + pccard_devices; dev->filter = pcan_create_filter_chain(); dev->props.ucExternalClock = 1; dev->props.ucMasterDevice = (nChannel) ? CHANNEL_SLAVE : CHANNEL_MASTER; // reject illegal combination if (!dwPort || !wIrq) { err = -EINVAL; goto fail; } // fill struct pcandev, hardware specfic parts p = &dev->port.pccard; p->dwPort = dwPort; p->wIrq = wIrq; p->nChannel = nChannel; p->card = card; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8) // allocating io resources DPRINTK(KERN_DEBUG "%s: ___request_region(PCCARD_PORT_SIZE)\n", DEVICE_NAME); err = ___request_region(dev->port.pccard.dwPort, PCCARD_PORT_SIZE, DEVICE_NAME); if (err) goto fail; #endif dev->wInitStep = 1; // base init of hardware - reset channel pccard_channel_reset(card, nChannel); // probe hardware if ((err = sja1000_probe(dev))) goto fail; // add into list of devices and assign the device as plugged in dev->ucPhysicallyInstalled = 1; list_add_tail(&dev->list, &pcan_drv.devices); // add this device to the list dev->wInitStep = 2; // increment device counts pcan_drv.wDeviceCount++; pccard_devices++; dev->wInitStep = 3; dev->ucActivityState = ACTIVITY_INITIALIZED; dev->wInitStep = 4; printk(KERN_INFO "%s: pccard device minor %d found\n", DEVICE_NAME, dev->nMinor); return dev; fail: pccard_cleanup(dev); DPRINTK(KERN_INFO "%s: pccard_create_single_device(%d) failed! (%d)\n", DEVICE_NAME, nChannel, err); return NULL;}//****************************************************************************// allocate resources and common io area and initialize hardware of devicesint pccard_create_all_devices(PCAN_PCCARD *card){ int err = 0; DPRINTK(KERN_DEBUG "%s: pccard_create_all_devices()\n", DEVICE_NAME); if (card) { int chn = 0; struct pcandev *dev; int i; // fill card structure card->commonPort = card->basePort + PCCARD_COMMON; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8) // request commonly used io area DPRINTK(KERN_DEBUG "%s: ___request_region(PCCARD_COMMON_SIZE)\n", DEVICE_NAME); err = ___request_region(card->commonPort, PCCARD_COMMON_SIZE, DEVICE_NAME); if (err) goto fail; #endif // init common registers pccard_initreg_common(card); for (i = 0; i < PCCARD_CHANNELS; i++) { card->dev[i] = NULL; // probe devices and if successfully create device structues - channel 0 dev = pccard_create_single_device(card, i, card->basePort + i * PCCARD_CHANNEL_OFF, card->commonIrq); if (dev) { chn++; card->dev[i] = dev; #ifdef NETDEV_SUPPORT pcan_netdev_register(dev); #endif } } // no usable channel found if (!chn) { printk(KERN_ERR "%s: pccard with no channels found!\n", DEVICE_NAME); err = -ENODEV; goto fail; } // get version of hardware to log pccard_show_firmware_version(card); // enable power to connector pccard_enable_CAN_power(card); pccard_start_activity_scanner(card); // start scanning card's acitvity to control LEDs return 0; } fail: DPRINTK(KERN_DEBUG "%s: pccard_create_all_devices(%d) failed!\n", DEVICE_NAME, err); return err;}//****************************************************************************// deinit devices and release allocted resources of devices and common io areavoid pccard_release_all_devices(PCAN_PCCARD *card){ DPRINTK(KERN_DEBUG "%s: pccard_release_all_devices(0x%p)\n", DEVICE_NAME, card); if (card) { struct pcandev *dev; int i; pccard_stop_activity_scanner(card); // stop scanning card's acitvity to control LEDs if (pccard_plugged(card)) pccard_disable_CAN_power(card); for (i = 0; i < PCCARD_CHANNELS; i++) { // 1. release associated devices dev = card->dev[i]; pccard_cleanup(dev); card->dev[i] = NULL; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8) DPRINTK(KERN_DEBUG "%s: release_region(PCCARD_COMMON_SIZE)\n", DEVICE_NAME); release_region(card->commonPort, PCCARD_COMMON_SIZE); #endif }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -