📄 stepper.c
字号:
switch(cmd) { case(STEPPER_SET_DEBUG): /* unfriendly user might crash system */ /* by setting debug too high. Only allow */ /* root to change debug */ if((current->uid==0) || (current->euid==0)) { debug=arg; } else { return(EPERM); } break; case(STEPPER_SET_SKIPTICKS): skipticks=arg; break; case(STEPPER_SET_VERBOSE_IO): verbose_io=arg; break; case(STEPPER_SET_VERBOSE_MOVE): verbose_move=arg; break; case(TCGETS): break; #if 0 /* autostart and start/stop are not implemented */ /* these would be used to enable interrupts */ /* only when the driver is in use and to */ /* allow a program to turn them on and off */ case(STEPPER_START): if(debug) printk("stepper_ioctl(): start\n"); stepper_start(); break; case(STEPPER_STOP): if(debug) printk("stepper_ioctl(): stop\n"); stepper_stop(); break; case(STEPPER_CLEAR_BUFFERS): if(debug) { printk("stepper_ioctl(): clear buffers\n"); } ring_buffer_init(&read_buffer); ring_buffer_init(&write_buffer); break; case(STEPPER_AUTO): if(debug) { printk("stepper_ioctl(): enable autostart\n"); } autostart = 1; break; case(STEPPER_NOAUTO): if(debug) { printk("stepper_ioctl(): disable autostart\n"); } autostart = 0; break; #endif default: printk("stepper_ioctl(): Unknown ioctl %d\n",cmd); break; } return(0); } static int stepper_open(struct inode *inode, struct file *file) { int rc; int minor; minor = MINOR(inode->i_rdev); printk("stepper: stepper_open() - file->f_mode=%d\n", file->f_mode); /* * As written, only one process can have the device * open at once. For some applications, it might be * nice to have multiple processes (one controlling, for * example, X and Y while the other controls Z). * I use two separate entries in /dev/, with * corresponding minor device numbers, to allow a * program to open for ioctl while another program * has the data connection open. * This would allow a Panic Stop application to be * written, * for example. * Minor device = 0 - read and write * Minor device = 1 - ioctl() only */ /* if minor!=0, we are just opening for ioctl */ if(minor!=0) { MOD_INC_USE_COUNT; return(0); } if(autostart) stepper_start(); if(file->f_mode==1) { /* read */ if(read_is_open) { printk("stepper: stepper_open() - read busy\n"); return(-EBUSY); } else { read_is_open=1; abort_read=0; MOD_INC_USE_COUNT; } } else if(file->f_mode==2) { /* write */ if(write_is_open) { printk("stepper: stepper_open() - write busy\n"); return(-EBUSY); } else { write_is_open=1; abort_write=0; MOD_INC_USE_COUNT; } } else { printk("stepper: stepper_open() - unknown mode\n"); return(-EINVAL); } if(debug) printk("stepper: stepper_open() - success\n"); return(0); } void stepper_release(struct inode *inode, struct file *file) { int minor; minor = MINOR(inode->i_rdev); if(minor!=0) { MOD_DEC_USE_COUNT; return; } printk("stepper: stepper_release() - file->f_mode=%d\n", file->f_mode); if(file->f_mode==1) { /* read */ if(read_is_open) { abort_read=1; if(read_is_sleeping) { wake_up_interruptible(&read_wait); } read_is_open=0; MOD_DEC_USE_COUNT; } else { printk("stepper: ERROR: stepper_release() " "called unexpectedly (read)\n"); } } else if(file->f_mode==2) { /* write */ if(write_is_open) { abort_write=1; if(write_is_sleeping) { wake_up_interruptible(&write_wait); } write_is_open=0; MOD_DEC_USE_COUNT; } else { printk("stepper: ERROR: stepper_release() called" " unexpectedly (write)\n"); } } else { printk("stepper: stepper_release() " "- invalid file mode\n"); } if(!read_is_open && !write_is_open) { stepper_stop(); } } static struct file_operations stepper_fops = { stepper_lseek, stepper_read, stepper_write, NULL, /* readdir */ NULL, /* select */ stepper_ioctl, /* ioctl */ NULL, /* mmap */ stepper_open, stepper_release, NULL, /* fsync */ NULL, /* fasync */ NULL, /* check_media_change */ NULL /* revalidate */ }; static int using_jiffies = 0; static struct wait_queue *tick_die_wait_queue = NULL; /* forward declaration to resolve circular reference */ static void timer_tick_handler(void *junk); static struct tq_struct tick_queue_entry = { NULL, 0, timer_tick_handler, NULL }; static void bottom_half() { int rc; char c; tick_counter++; if(tick_die_wait_queue) { /* cleanup_module() is waiting for us */ /* Don't reschedule interrupt and wake up cleanup */ using_jiffies = 0; wake_up(&tick_die_wait_queue); } else { if((skipticks==0) || ((tick_counter % skipticks)==0)) { /* Don't process any move commands if */ /* we haven't finished the last one */ if( (xdest==xpos) && (ydest==ypos) && (zdest==zpos) ) { /* process command characters */ while( (rc=ring_buffer_read(&write_buffer,&c,1))==1 ){ parse_one_char(c); if((xdest!=xpos) || (ydest!=ypos) || (zdest!=zpos) ) { /* parse_one_char() started a move; */ /* stop reading commands so current move*/ /* can complete first. */ break; } } if(write_is_sleeping) { wake_up_interruptible(&write_wait); } } } move_one_step(); /* put ourselves back in the queue for the next tick*/ if(using_jiffies) { queue_task(&tick_queue_entry, &tq_timer); } } } static void timer_tick_handler(void *junk) { /* let bottom_half() do the work */ bottom_half(); } void interrupt_handler(int irq, void *dev_id, struct pt_regs *regs) { /* let bottom_half() do the work */ bottom_half(); } int init_module(void) { int rc; ring_buffer_init(&read_buffer); ring_buffer_init(&write_buffer); read_is_sleeping=0; write_is_sleeping=0; if ((stepper_major = register_chrdev(major,"step", &stepper_fops)) <0 ) { printk("stepper: unable to get major device\n"); return(-EIO); } /* register_chrdev() does not return the major device */ /* number, workaround will not be correct if major=0 */ stepper_major = major; if(debug) printk("stepper:init_module():stepper_major=%d\n", stepper_major); if(check_region(base,4)) { printk("stepper: port in use"); unregister_chrdev(stepper_major, "step"); return; } request_region(base,4); if(irq && (!interrupts_are_enabled)) { rc=request_irq(irq,interrupt_handler,0,"stepper",NULL); if(rc) { printk("stepper: stepper_start() - request_irq() " "returned %d\n",rc); } else { printk("stepper: stepper_start() " "- enabled interrupts\n"); interrupts_are_enabled = 1; /* now that we are ready to receive them */ /* enable interrupts on parallel card */ word = irq_enable_bit; verbose_outb( (word >> 8), base+2); } } if(!irq) { using_jiffies = 1; queue_task(&tick_queue_entry, &tq_timer); } /* give ourselves some work to do */ xdest = ydest = zdest = 400; if(debug) printk( "stepper: module loaded\n"); return(0); } void cleanup_module(void) { abort_write=1; if(write_is_sleeping) wake_up_interruptible(&write_wait); abort_read=1; if(read_is_sleeping) wake_up_interruptible(&read_wait); #if 1 /* Delay 1s for read and write to exit */ current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + 100; schedule(); #endif release_region(base,4); if(MOD_IN_USE) { printk("stepper: device busy, remove delayed\n"); return; } printk("unregister_chrdev(%d,%s)\n",stepper_major, "step"); if( unregister_chrdev(stepper_major, "step") ) { printk("stepper: unregister_chrdev() failed.\n"); printk("stepper: /proc/devices will cause core dumps\n"); /* Note: if we get here, we have a problem */ /* There is still a pointer to the name of the device */ /* which is in the address space of the LKM */ /* which is about to go away and we cannot abort /* the unloading of the module */ } /* note: we need to release the interrupt here if */ /* necessary otherwise, interrupts may cause kernel */ /* page faults */ if(interrupts_are_enabled) { /* Disable interrupts on card before we unregister */ word &= ~irq_enable_bit; verbose_outb( (word >> 8), base+2); free_irq(irq,NULL); } if(using_jiffies) { /* If we unload while we are still in the jiffie */ /* queue, bad things will happen. We have to wait */ /* for the next jiffie interrupt */ sleep_on(&tick_die_wait_queue); } if(power_down_on_exit) { word=flipbits; /* output low byte to data register */ verbose_outb( (word & 0x00FF), base+0); /* output high byte to control register */ verbose_outb( (word >> 8), base+2); } if(debug) printk("stepper: module unloaded\n"); }#else /* ! __KERNEL__ */main(){ char c; /* unbuffer output so we can see in real time */ setbuf(stdout,NULL); printf("this program must be run as root\n"); iopl(3); /* Enable i/o (if root) */ printf("Here are some example motion commands:\n"); printf(" X=100,Y=100,Z=50\n"); printf(" X=100,Y=100\n"); printf(" Y=100,Z=50\n"); printf(" X=+100,Y=-100\n"); printf(" ? (reports position)"); printf("End each command with a newline.\n"); printf("Begin typing motion commands\n"); while(!feof(stdin)) { c = getc(stdin); parse_one_char(c); move_all(); } if(power_down_on_exit) { word=flipbits; /* output low byte to data register */ verbose_outb( (word & 0x00FF), base+0); /* output high byte to control register */ verbose_outb( (word >> 8), base+2); }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -