📄 mc68328digi.c
字号:
#ifdef USE_PENIRQ_PULLUP PDDATA |= PEN_MASK_2; /* Pull up I/0 2 of PENIRQ */#endif PENIRQ_DIR &= ~PEN_MASK; /* I/O 1 of PENIRQ as input */ PENIRQ_DATA |= PEN_MASK; /* Pull down I/O 2 of PENIRQ */}/* * Ask for an X conversion. */static void ask_x_conv(void) { SET_SPIMDATA(SPIMDATA_ASKX); SPIMCONT |= SPIMCONT_XCH; /* initiate exchange */}/* * Ask for an Y conversion. */static void ask_y_conv(void) { SET_SPIMDATA(SPIMDATA_ASKY); SPIMCONT |= SPIMCONT_XCH; /* initiate exchange */}/* * Get the X conversion. Re-enable the PENIRQ. */static void read_x_conv(void) { current_pos.x = (SPIMDATA & 0x7FF8) >> 3; /* * The first clock is used to fall the BUSY line and the following 15 clks * to transfert the 12 bits of the conversion, MSB first. * The result will then be in the SPIM register in the bits 14 to 3. */ SET_SPIMDATA(SPIMDATA_NOP); /* nop with a start bit to re-enable */ SPIMCONT |= SPIMCONT_XCH; /* the pen irq. */ rescale_xpos(¤t_pos.x);}/* * Get the Y result. Clock the Burr-Brown to fall the BUSY. */static void read_y_conv(void) { current_pos.y = (SPIMDATA & 0x7FF8) >> 3; /* Same remark as upper. */ SET_SPIMDATA(SPIMDATA_NULL); /* No start bit to fall the BUSY without */ SPIMCONT |= SPIMCONT_XCH; /* initiating another BUSY... */ rescale_ypos(¤t_pos.y);}/* * Get one char from the queue buffer. * AND the head with 'TS_BUF_SIZE -1' to have the loopback */static unsigned char get_char_from_queue(void) { unsigned int result; result = queue->buf[queue->tail]; queue->tail = (queue->tail + 1) & (TS_BUF_SIZE - 1); return result;}/* * Write one event in the queue buffer. * Test if there is place for an event = the head cannot be just one event * length after the queue. */static void put_in_queue(char *in, int len) { unsigned long head = queue->head; unsigned long maxhead = (queue->tail - len) & (TS_BUF_SIZE - 1); int i; if(head != maxhead) /* There is place for the event */ for(i=0;i<len;i++) { queue->buf[head] = in[i]; head++; head &= (TS_BUF_SIZE - 1); } //else printk("%0: Queue is full !!!!\n", __file__); queue->head = head;}/* * Test if queue is empty. */static inline int queue_empty(void) { return queue->head == queue->tail;}/* * Test if the delta move of the pen is enough big to say that this is a really * move and not due to noise. */static int is_moving(void) { int threshold; int dx, dy; threshold=((ts_pen_prev.event & EV_PEN_MOVE) > 0 ? current_params.follow_thrs : current_params.mv_thrs); dx = current_pos.x-ts_pen_prev.x; dy = current_pos.y-ts_pen_prev.y; if(dx < 0) dx = -dx; /* abs() */ if(dy < 0) dy = -dy; return (dx > threshold ? 1 : (dy > threshold ? 1 : 0));}static void copy_info(void) { ts_pen_prev.x = ts_pen.x; ts_pen_prev.y = ts_pen.y; ts_pen_prev.dx = ts_pen.dx; ts_pen_prev.dy = ts_pen.dy; ts_pen_prev.event = ts_pen.event; ts_pen_prev.state = ts_pen.state; ts_pen_prev.ev_no = ts_pen.ev_no; ts_pen_prev.ev_time = ts_pen.ev_time;}unsigned long set_ev_time(void) { struct timeval now; do_gettimeofday(&now); return (now.tv_sec -first_tick.tv_sec )*1000 + (now.tv_usec-first_tick.tv_usec)/1000;}static void cause_event(int conv) { switch(conv) { case CONV_ERROR: /* error occure during conversion */ ts_pen.state &= 0; /* clear */ ts_pen.state |= ST_PEN_UP; /* recover a stable state for the drv. */ ts_pen.state |= ST_PEN_ERROR; /* tell that the state is due to an error */ ts_pen.event = EV_PEN_UP; /* event = pen go to up */ ts_pen.x = ts_pen_prev.x; /* get previous coord as current to by-pass */ ts_pen.y = ts_pen_prev.y; /* possible errors */ ts_pen.dx = 0; ts_pen.dy = 0; ts_pen.ev_no = ev_counter++; /* get no of event */ ts_pen.ev_time = set_ev_time(); /* get time of event */ copy_info(); /* remember info */ if(current_params.event_queue_on) put_in_queue((char *)&ts_pen,DATA_LENGTH); /* queue event */ /* tell user space progs that a new state occure */ new_pen_state = 1; /* signal asynchronous readers that data arrives */ if(queue->fasync) kill_fasync(&queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); /* tell user space progs */ break; case CONV_LOOP: /* pen is down, conversion continue */ ts_pen.state &= 0; /* clear */ ts_pen.state &= ST_PEN_DOWN; switch(state_counter) { /* It could be a move */ case 1: /* the pen just went down, it's a new state */ ts_pen.x = current_pos.x; ts_pen.y = current_pos.y; ts_pen.dx = 0; ts_pen.dy = 0; ts_pen.event = EV_PEN_DOWN; /* event = pen go to down */ ts_pen.ev_no = ev_counter++; /* get no of event */ ts_pen.ev_time = set_ev_time(); /* get time of event */ copy_info(); /* remember info */ if(current_params.event_queue_on) put_in_queue((char *)&ts_pen,DATA_LENGTH); /* queue event */ /* tell user space progs that a new state occure */ new_pen_state = 1; /* signal asynchronous readers that data arrives */ if(queue->fasync) kill_fasync(&queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); /* tell user space progs */ break; case 2: /* the pen is down for at least 2 loop of the state machine */ if(is_moving()) { ts_pen.event = EV_PEN_MOVE; ts_pen.x = current_pos.x; ts_pen.y = current_pos.y; ts_pen.dx = ts_pen.x - ts_pen_prev.x; ts_pen.dy = ts_pen.y - ts_pen_prev.y; ts_pen.ev_no = ev_counter++; /* get no of event */ ts_pen.ev_time = set_ev_time(); /* get time of event */ copy_info(); /* remember info */ if(current_params.event_queue_on) put_in_queue((char *)&ts_pen,DATA_LENGTH); /* queue event */ /* * pen is moving, then it's anyway a good reason to tell it to * user space progs */ new_pen_state = 1; /* signal asynchronous readers that data arrives */ if(queue->fasync) kill_fasync(&queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); } else { if(ts_pen_prev.event == EV_PEN_MOVE) /* if previous state was moving */ ts_pen.event = EV_PEN_MOVE; /* -> keep it! */ ts_pen.x = ts_pen_prev.x; /* No coord passing to */ ts_pen.y = ts_pen_prev.y; /* avoid Parkinson effects */ ts_pen.dx = 0; ts_pen.dy = 0; /* no wake-up interruptible because nothing new */ copy_info(); /* remember info */ } break; } break; case CONV_END: /* pen is up, conversion ends */ ts_pen.state &= 0; /* clear */ ts_pen.state |= ST_PEN_UP; ts_pen.event = EV_PEN_UP; ts_pen.x = current_pos.x; ts_pen.y = current_pos.y; ts_pen.dx = ts_pen.x - ts_pen_prev.x; ts_pen.dy = ts_pen.y - ts_pen_prev.y; ts_pen.ev_time = set_ev_time(); /* get time of event */ ts_pen.ev_no = ev_counter++; /* get no of event */ copy_info(); /* remember info */ if(current_params.event_queue_on) put_in_queue((char *)&ts_pen,DATA_LENGTH); /* queue event */ /* tell user space progs that a new state occure */ new_pen_state = 1; /* signal asynchronous readers that data arrives */ if(queue->fasync) kill_fasync(&queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); break; }}/*----------------------------------------------------------------------------*//* Interrupt functions -------------------------------------------------------*//* * pen irq. */static void handle_pen_irq(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; int bypass_initial_timer = 0; /* if unwanted interrupts come, trash them */ if(!device_open) return; PENIRQ_DATA &= ~PEN_MASK;#ifdef CONFIG_XCOPILOT_BUGS if(IMR&IMR_MPEN) { return; }#endif save_flags(flags); /* disable interrupts */ cli(); switch(ts_drv_state) { case TS_DRV_IDLE: DISABLE_PEN_IRQ; ts_drv_state++; /* update driver state */ if(current_params.deglitch_on) // if(current_params.deglitch_ms) //changed by duwei at 07/02/2003 set_timer_irq(&ts_wake_time,sample_ticks); else bypass_initial_timer = 1; break; default: /* Error */ /* PENIRQ is enable then just init the driver * Its not necessary to pull down the busy signal */ init_ts_state(); break; } restore_flags(flags); /* Enable interrupts */ /* if deglitching is off, we haven't started the deglitching timeout * so we do the inital sampling immediately: */ if(bypass_initial_timer) handle_timeout();}/* * timer irq. */static void handle_timeout(void) { unsigned long flags; /* if unwanted interrupts come, trash them */ if(!device_open) return; save_flags(flags); /* disable interrupts */ cli(); switch(ts_drv_state) { case TS_DRV_IDLE: /* Error in the idle state of the driver */ printk("%s: Error in the idle state of the driver\n", __file__); goto treat_error; case TS_DRV_ASKX: /* Error in release SPIM */ printk("%s: Error in release SPIM\n", __file__); goto treat_error; case TS_DRV_ASKY: /* Error in ask Y coord */ printk("%s: Error in ask Y coord\n", __file__); goto treat_error; case TS_DRV_READX: /* Error in read X coord */ printk("%s: Error in read X coord\n", __file__); goto treat_error; case TS_DRV_READY: /* Error in read Y coord */ printk("%s: Error in read Y coord\n", __file__); goto treat_error; treat_error: /* Force re-enable of PENIRQ because of an abnormal termination. Limit this * initialization with a timer to define a more FATAL error ... */ set_timer_irq(&ts_wake_time,TICKS(CONV_TIME_LIMIT)); ts_drv_state = TS_DRV_ERROR; CLEAR_SPIM_IRQ; /* Consume residual irq from spim */ ENABLE_SPIM_IRQ; fall_BUSY_enable_PENIRQ(); break; case TS_DRV_WAIT: if(state_counter) { cause_event(CONV_LOOP); /* only after one loop */ } if(IS_PEN_DOWN) { if(state_counter < 2) state_counter++; set_timer_irq(&ts_wake_time,TICKS(CONV_TIME_LIMIT)); set_SPIM_transfert(); ts_drv_state++; CLEAR_SPIM_IRQ; /* Consume residual irq from spim */ ENABLE_SPIM_IRQ; fall_BUSY_enable_PENIRQ(); } else { if(state_counter) {#ifdef CONFIG_XCOPILOT_BUGS /* on xcopilot, we read the last mouse position now, because we * missed the moves, during which the position should have been * read */ xcopilot_read_now();#endif cause_event(CONV_END); } init_ts_state(); } break; case TS_DRV_ERROR: /* Busy doesn't want to fall down -> reboot? */ panic(__FILE__": cannot fall pull BUSY signal\n"); default: init_ts_state(); } restore_flags(flags); /* Enable interrupts */#ifdef CONFIG_XCOPILOT_BUGS if (ts_drv_state==TS_DRV_ASKX) { handle_spi_irq(); } PENIRQ_DATA |= PEN_MASK;#endif}/* * spi irq. */static void handle_spi_irq(void) { unsigned long flags; /* if unwanted interrupts come, trash them */ if(!device_open) return; save_flags(flags); /* disable interrupts */ cli(); CLEAR_SPIM_IRQ; /* clear source of interrupt */ switch(ts_drv_state) { case TS_DRV_ASKX:#ifdef CONFIG_XCOPILOT_BUGS /* for xcopilot we bypass all SPI interrupt-related stuff * and read the pos immediately */ xcopilot_read_now(); ts_drv_state = TS_DRV_WAIT; DISABLE_SPIM_IRQ; release_SPIM_transfert(); set_timer_irq(&ts_wake_time,sample_ticks); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -