📄 galil_1800.c
字号:
read_unlock(&dev->siglock); spin_lock_irqsave(&dev->irqlock, flags); if (sz < dev->irqstack_sz) for (i=0; i<dev->irqstack_sz-sz; ++i) dev->irqstack[i] = dev->irqstack[i+sz]; dev->irqstack_sz -= sz; spin_unlock_irqrestore(&dev->irqlock, flags); }static int galil_1800_del_from_siglist(struct galil_1800_state *dev, struct task_struct *task){ struct list_head *list; struct list_head *head = &dev->siglist; struct galil_1800_siglist_t *elem; unsigned long flags; write_lock_irqsave(&dev->siglock, flags); list_for_each(list, head) { elem = list_entry(list, struct galil_1800_siglist_t, list); if (elem->owner == task) break; } if (list == head) { write_unlock_irqrestore(&dev->siglock, flags); return -ESRCH; } if (task->pid != elem->owner->pid) { printk(KERN_WARNING PFX "bad PID (%d) in the signaling process list\n", elem->owner->pid); return -EFAULT; } list_del(list); write_unlock_irqrestore(&dev->siglock, flags); kfree(elem); printk(KERN_INFO PFX "deregistered PID %d for device #%d\n", task->pid, dev->index); return 0;}static int galil_1800_add_to_siglist(struct galil_1800_state *dev, char * userbuf, struct task_struct *task){ struct list_head *list; struct list_head *head = &dev->siglist; struct galil_1800_siglist_t *elem; unsigned long flags; if (!userbuf) return -EINVAL; write_lock_irqsave(&dev->siglock, flags); list_for_each(list, head) if (list_entry(list,struct galil_1800_siglist_t,list)->owner==task) { write_unlock_irqrestore(&dev->siglock, flags); printk(KERN_INFO PFX "PID %d already registered for device #%d\n", task->pid, dev->index); return -EINVAL; } elem = kmalloc(sizeof(struct galil_1800_siglist_t), GFP_ATOMIC); if (!elem) { printk(KERN_ERR PFX "cannot allocate memory\n"); return -ENOMEM; } elem->owner = task; elem->pid = task->pid; elem->ubuf = userbuf; list_add(&elem->list, head); write_unlock_irqrestore(&dev->siglock, flags); printk(KERN_INFO PFX "registered PID %d for device #%d\n", task->pid, dev->index); return 0;}static ssize_t galil_1800_read(struct file * filp, char * buf, size_t size, loff_t *poff){ struct galil_1800_state *dev = (struct galil_1800_state *) filp->private_data; char _buf[GALIL_1800_READ_FIFO_SIZE], *p = _buf; ssize_t count; ssize_t request = (size < GALIL_1800_READ_FIFO_SIZE ? size : GALIL_1800_READ_FIFO_SIZE); int rc; for (count = 0; count < request && galil_1800_may_read(dev); ++count) *p++ = inb(GALIL_1800_READ_REG(dev)); if (!count) return 0; rc = copy_to_user(buf, _buf, count); return (rc > 0 ? -EFAULT : count);}static ssize_t galil_1800_write(struct file * filp, const char * buf, size_t size, loff_t *poff){ struct galil_1800_state *dev = (struct galil_1800_state *) filp->private_data; char _buf[GALIL_1800_WRITE_FIFO_SIZE], *p = _buf; ssize_t count; ssize_t request = (size < GALIL_1800_WRITE_FIFO_SIZE ? size : GALIL_1800_WRITE_FIFO_SIZE); int rc, written = 0; if (!request) return 0; if (!buf) return -EINVAL; rc = copy_from_user(_buf, buf, request); if (rc) return -EFAULT; rc = request; if (galil_1800_may_write(dev) == 2) { /* write in burst mode */ if (rc > GALIL_1800_WRITE_FIFO_SIZE / 2) { request = GALIL_1800_WRITE_FIFO_SIZE / 2; rc -= GALIL_1800_WRITE_FIFO_SIZE / 2; } else { request = rc; rc = 0; } for (count = 0; count < request; ++count, ++p) outb_p(*p, GALIL_1800_WRITE_REG(dev)); written = request; } for (count = 0; count < rc && galil_1800_may_write(dev); ++count, p++) outb(*p, GALIL_1800_WRITE_REG(dev)); return count+written;}static int galil_1800_open(struct inode * inode, struct file * file){ int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); struct list_head *list; struct galil_1800_state *s; read_lock(&galil_1800_devs_lock); list_for_each(list, &galil_1800_devs) { s = list_entry(list, struct galil_1800_state, devs); if (!((s->index ^ minor) & ~0xf)) break; } read_unlock(&galil_1800_devs_lock); if (list == &galil_1800_devs) return -ENODEV; file->private_data = s; /* wait for device to become free */ down(&s->open_sem); while (s->open_mode & file->f_mode) { if (file->f_flags & O_NONBLOCK) { up(&s->open_sem); return -EBUSY; } add_wait_queue(&s->open_wait, &wait); __set_current_state(TASK_INTERRUPTIBLE); up(&s->open_sem); schedule(); remove_wait_queue(&s->open_wait, &wait); set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); } s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); if (++s->opens == 1) { galil_1800_clear_FIFO(s, 0); galil_1800_enable_IRQ(s); } up(&s->open_sem); return 0;}static int galil_1800_release(struct inode * inode, struct file * file){ struct galil_1800_state *s = (struct galil_1800_state *) file->private_data; down(&s->open_sem); if (!--s->opens) { galil_1800_disable_IRQ(s); galil_1800_clear_FIFO(s, 0); } galil_1800_del_from_siglist(s, current); s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); up(&s->open_sem); wake_up(&s->open_wait); return 0;}static int galil_1800_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct galil_1800_state *dev = (struct galil_1800_state *) file->private_data; switch (cmd) { case GALIL_CLEAR_FIFO: galil_1800_clear_FIFO(dev, arg); return 0; case GALIL_MAY_READ: return galil_1800_may_read(dev); case GALIL_MAY_WRITE: return galil_1800_may_write(dev); case GALIL_GET_SERIAL_NUMBER: {#define SN_BUF_SIZE 256 char buf[SN_BUF_SIZE]; int rc = galil_1800_get_serial_number(dev, buf); return (rc < 0 ? rc : copy_to_user((void *)arg, buf, strlen(buf)) ? -EFAULT : 0);#undef SN_BUF_SIZE } case GALIL_SIGNAL_INTERRUPTS: if ((char *) arg == NULL) return galil_1800_del_from_siglist(dev, current); else return galil_1800_add_to_siglist(dev, (char *) arg, current); break; case GALIL_GET_IRQ_STACK: { int rc = copy_to_user((void *) arg, dev->irqstack, GALIL_1800_IRQ_STACK_SZ*sizeof(dev->irqstack[0])); if (!rc) return -EFAULT; rc = dev->irqstack_sz; dev->irqstack_sz = 0; return rc; } break; case GALIL_READ_2ND_FIFO: { char buf[GALIL_1800_READ_FIFO2_SIZE]; int n = galil_1800_read_FIFO2(dev, buf, GALIL_1800_READ_FIFO2_SIZE); if (!n) return 0; return (copy_to_user((void *)arg, buf, n) ? -EFAULT : n); } break; } return -EINVAL;}/* module/hotplug stuff */static int __devinit galil_1800_probe(struct pci_dev *pcidev, const struct pci_device_id *devid){ struct galil_1800_state *s; if (pcidev->irq == 0) return -1; if (!(s = kmalloc(sizeof(struct galil_1800_state), GFP_KERNEL))) { printk(KERN_ERR PFX "alloc of galil_1800_state struct failed\n"); return -1; } memset(s, 0, sizeof(struct galil_1800_state)); init_waitqueue_head(&s->open_wait); init_MUTEX(&s->open_sem); spin_lock_init(&s->hwlock); spin_lock_init(&s->irqlock); rwlock_init(&s->siglock); INIT_LIST_HEAD(&s->siglist); tasklet_init(&s->tlet, galil_1800_send_signals, (unsigned long) s); s->index = devindex; s->dev = pcidev; s->io = pci_resource_start(pcidev, 2); s->ctrl_reg = s->io + 4; s->irq_reg = s->io + 8; s->chan2_reg = s->io + 12; s->irq = pcidev->irq; s->irqstack_sz = 0; s->opens = 0; if (!request_region(s->io, pci_resource_len(pcidev,2), GALIL_1800_MODULE_NAME)) { printk(KERN_ERR PFX "io ports %#lx->%#lx in use\n", s->io, s->io + pci_resource_len(pcidev,2)-1); goto err_region; } if (request_irq(s->irq, galil_1800_interrupt, SA_SHIRQ, GALIL_1800_MODULE_NAME, s)) { printk(KERN_ERR PFX "irq %u in use\n", s->irq); goto err_irq; } printk(KERN_INFO PFX "device #%d, base I/O: 0x%lx, IRQ: %d\n", s->index, s->io, s->irq); if (pci_enable_device(pcidev)) goto err_pci; pci_set_drvdata(pcidev, s); /* pcidev->dma_mask = 0xffffffff; */ /* put it into driver list */ write_lock(&galil_1800_devs_lock); list_add_tail(&s->devs, &galil_1800_devs); write_unlock(&galil_1800_devs_lock); devindex++; return 0; err_pci: printk(KERN_ERR PFX "cannot enable PCI device\n"); free_irq(s->irq, s); err_irq: release_region(s->io, pci_resource_len(pcidev,2)); err_region: kfree(s); return -1;}static void __devexit galil_1800_remove(struct pci_dev *dev){ struct galil_1800_state *s = pci_get_drvdata(dev); if (!s) return; write_lock(&galil_1800_devs_lock); list_del(&s->devs); write_unlock(&galil_1800_devs_lock); synchronize_irq(); free_irq(s->irq, s); release_region(s->io, pci_resource_len(dev,2)); kfree(s); pci_set_drvdata(dev, NULL); }static struct __devinitdata pci_device_id galil_1800_idtable[] = { { vendor: PLX_PCI_VENDOR_ID, device: PLX_PCI_DEVICE_ID, subvendor: GALIL_SUB_VENDOR, subdevice: GALIL_SUB_DEVICE_1800, class: 0, class_mask: 0, driver_data: 0 }, { 0, }};static struct pci_driver galil_1800_driver = { name: GALIL_1800_MODULE_NAME, id_table: galil_1800_idtable, probe: galil_1800_probe, remove: __devexit_p(galil_1800_remove), save_state: NULL, suspend: NULL, resume: NULL, enable_wake: NULL};static struct file_operations galil_1800_fops = { read: galil_1800_read, write: galil_1800_write, ioctl: galil_1800_ioctl, open: galil_1800_open, release: galil_1800_release};static int __init galil_1800_init(void){ int rc, maj; rc = pci_module_init(&galil_1800_driver); if (rc == -ENODEV) { printk(KERN_INFO PFX "no Galil 1800 device was found\n"); return rc; } if (rc) { printk(KERN_ERR PFX "cannot register the device driver\n"); return rc; } maj = (major != -1 ? major : 0); rc = register_chrdev(maj, GALIL_1800_MODULE_NAME, &galil_1800_fops); if (rc < 0) { printk(KERN_ERR PFX "cannot register the device files\n"); pci_unregister_driver(&galil_1800_driver); return 1; } major = (rc == 0 ? maj : rc); SET_MODULE_OWNER(&galil_1800_fops); printk(KERN_INFO PFX "module loaded\n"); return 0;}static void __exit galil_1800_cleanup(void){ unregister_chrdev(major, GALIL_1800_MODULE_NAME); pci_unregister_driver(&galil_1800_driver); printk(KERN_INFO PFX "module unloaded\n"); }/* __setup("galil_1800=", galil_1800_setup); */module_init(galil_1800_init);module_exit(galil_1800_cleanup);MODULE_AUTHOR("Shell Technologies s.r.l. (M. Cesati)");MODULE_DESCRIPTION("Galil 1800 Motion Controller Driver");MODULE_LICENSE("GPL");MODULE_PARM(major,"i");MODULE_PARM_DESC(major, "Major number of the device file");EXPORT_NO_SYMBOLS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -