S3C2440 Linux 触摸屏驱动


主机:VM - RedHat 9.0

开发板:FL2440,linux-2.6.12

arm-linux-gcc:3.4.1

代码中的第90行,若不支持拖拽,则可以获取到笔触坐标,但是LCD上的图标没有响应,不知什么原因。

  1. #include <linux/config.h>   
  2. #include <linux/module.h>   
  3. #include <linux/moduleparam.h>   
  4. #include <linux/kernel.h>   
  5. #include <linux/sched.h>   
  6. #include <linux/init.h>   
  7. #include <linux/device.h>   
  8. #include <linux/miscdevice.h>   
  9. #include <linux/delay.h>   
  10. #include <linux/poll.h>   
  11. #include <linux/spinlock.h>   
  12. #include <linux/interrupt.h>   
  13. #include <linux/delay.h>   
  14. #include <linux/devfs_fs_kernel.h>   
  15.   
  16. #include <asm/hardware/clock.h>   
  17. #include <asm/hardware.h>   
  18. #include <asm/io.h>   
  19. #include <asm/arch/regs-gpio.h>   
  20.   
  21. // YM_SEN输出驱动器使能,XP_SEN,YP_SEN输出驱动器禁止   
  22. // S3C2410_ADCTSC_XY_PST(3) -- 手动测量X、Y方向,等待中断模式   
  23. // x=0, 将ADCTSC[8]设置为0,即检测笔尖落下中断信号   
  24. #define WAIT4INT(x)  (((x)<<8) | \   
  25.              S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \  
  26.              S3C2410_ADCTSC_XY_PST(3))  
  27.                
  28. /* ADCTSC Register Bits */  
  29. #define S3C2410_ADCTSC_YM_SEN       (1<<7)   
  30. #define S3C2410_ADCTSC_YP_SEN       (1<<6)   
  31. #define S3C2410_ADCTSC_XM_SEN       (1<<5)   
  32. #define S3C2410_ADCTSC_XP_SEN       (1<<4)   
  33. #define S3C2410_ADCTSC_PULL_UP_DISABLE  (1<<3)   
  34. #define S3C2410_ADCTSC_AUTO_PST     (1<<2)   
  35. #define S3C2410_ADCTSC_XY_PST(x)    (((x)&0x3)<<0)   
  36.   
  37. /* ADCCON Register Bits */  
  38. #define S3C2410_ADCCON_ECFLG        (1<<15)   
  39. #define S3C2410_ADCCON_PRSCEN       (1<<14)   
  40. #define S3C2410_ADCCON_PRSCVL(x)    (((x)&0xFF)<<6)   
  41. #define S3C2410_ADCCON_PRSCVLMASK   (0xFF<<6)   
  42. #define S3C2410_ADCCON_SELMUX(x)    (((x)&0x7)<<3)   
  43. #define S3C2410_ADCCON_MUXMASK      (0x7<<3)   
  44. #define S3C2410_ADCCON_STDBM        (1<<2)   
  45. #define S3C2410_ADCCON_READ_START   (1<<1)   
  46. #define S3C2410_ADCCON_ENABLE_START (1<<0)   
  47. #define S3C2410_ADCCON_STARTMASK    (0x3<<0)   
  48.   
  49. #ifdef S3C2410_ADCCON   
  50. #undef S3C2410_ADCCON   
  51. #endif   
  52.   
  53. #ifdef S3C2410_ADCTSC   
  54. #undef S3C2410_ADCTSC   
  55. #endif   
  56.   
  57. #ifdef S3C2410_ADCDLY   
  58. #undef S3C2410_ADCDLY   
  59. #endif   
  60.   
  61. #ifdef S3C2410_ADCDAT0   
  62. #undef S3C2410_ADCDAT0   
  63. #endif   
  64.   
  65. #ifdef S3C2410_ADCDAT1   
  66. #undef S3C2410_ADCDAT1   
  67. #endif   
  68.   
  69. #ifdef S3C2410_PA_ADC   
  70. #undef S3C2410_PA_ADC   
  71. #endif   
  72.   
  73. #define S3C2410_PA_ADC     (0x58000000)    
  74.   
  75. static void __iomem *base_addr;  
  76. #define S3C2410_ADCCON (base_addr+(0x00))   
  77. #define S3C2410_ADCTSC (base_addr+(0x04))   
  78. #define S3C2410_ADCDLY (base_addr+(0x08))   
  79. #define S3C2410_ADCDAT0 (base_addr+(0x0c))   
  80. #define S3C2410_ADCDAT1 (base_addr+(0x10))   
  81.   
  82.   
  83. #ifdef CONFIG_PM   
  84. #include <linux/pm.h>   
  85. #endif   
  86.   
  87. // 支持拖拽   
  88. // 若不支持拖拽,则可以获取到笔触坐标,但是LCD上的图标没有响应。   
  89. // 可以看到read接口被调用到,不知为何图标没有响应。   
  90. #define HOOK_FOR_DRAG   
  91.   
  92.   
  93. //#define   DEBUG   
  94. #ifdef DEBUG   
  95. #define DPRINTK printk   
  96. #else   
  97. #define DPRINTK   
  98. #endif   
  99.   
  100. typedef struct {  
  101.   unsigned short pressure;  
  102.   unsigned short x;  
  103.   unsigned short y;  
  104.   unsigned short pad;  
  105. } TS_RET;  
  106.   
  107. typedef struct {  
  108.   int xscale;  
  109.   int xtrans;  
  110.   int yscale;  
  111.   int ytrans;  
  112.   int xyswap;  
  113. } TS_CAL;  
  114.   
  115. #define PEN_UP          0          
  116. #define PEN_DOWN    1   
  117. #define PEN_FLEETING    2   
  118. #define MAX_TS_BUF  16  /* how many do we want to buffer */   
  119.   
  120. #undef USE_ASYNC       
  121. #define DEVICE_NAME "s3c2410-ts"   
  122. #define TSRAW_MINOR 1   
  123.   
  124. typedef struct {  
  125.     unsigned int penStatus;     /* PEN_UP, PEN_DOWN, PEN_SAMPLE */  
  126.     TS_RET buf[MAX_TS_BUF];     /* protect against overrun */  
  127.     unsigned int head, tail;    /* head and tail for queued events */  
  128.     wait_queue_head_t wq;  
  129.     spinlock_t lock;  
  130. #ifdef USE_ASYNC   
  131.     struct fasync_struct *aq;  
  132. #endif   
  133. #ifdef CONFIG_PM   
  134.     struct pm_dev *pm_dev;  
  135. #endif   
  136. } TS_DEV;  
  137.   
  138. static TS_DEV tsdev;  
  139.   
  140. #define BUF_HEAD    (tsdev.buf[tsdev.head])   
  141. #define BUF_TAIL    (tsdev.buf[tsdev.tail])   
  142. #define INCBUF(x,mod)   ((++(x)) & ((mod) - 1))   
  143.   
  144. static int tsMajor = 0;  
  145.   
  146. static void (*tsEvent)(void);  
  147.   
  148. #ifdef HOOK_FOR_DRAG   
  149. #define TS_TIMER_DELAY  (HZ/100) /* 10 ms */   
  150. static struct timer_list ts_timer;  
  151. #endif   
  152.   
  153. // pick-up regs val from 2.4.18&2440   
  154. // YM_SEN输出驱动器使能,XP上拉使能,正常ADC转换,检测笔尖落下中断信号,等待中断模式   
  155. #define wait_down_int() __raw_writel(0x000000d3,S3C2410_ADCTSC)   
  156.   
  157. // YM_SEN输出驱动器使能,XP上拉使能,正常ADC转换,检测笔尖抬起中断信号,等待中断模式   
  158. #define wait_up_int()   __raw_writel(0x000001d3, S3C2410_ADCTSC)   
  159.   
  160. // XM_SEN、XP_SEN输出驱动器使能,XP上拉禁止,正常ADC转换,X方向测量模式   
  161. #define mode_x_axis()   __raw_writel(0x00000069, S3C2410_ADCTSC)   
  162.   
  163. // 相当于__raw_writel(0x00000068, S3C2410_ADCTSC),即   
  164. // XM_SEN、YP_SEN使能,XP上拉禁止,正常ADC转换,无操作模式   
  165. #define mode_x_axis_n() __raw_writel(XP_EXTVLT | XM_GND | YP_AIN | YM_HIZ | \   
  166.                 XP_PULL_UP_DIS | XP_PST(NOP_MODE), S3C2410_ADCTSC)  
  167.                   
  168. // YM_SEN、YP_SEN使能,XP上拉禁止,正常ADC转换,Y方向测量模式   
  169. #define mode_y_axis()   __raw_writel(0x0000009a, S3C2410_ADCTSC)   
  170.   
  171. // __raw_writel(0x00007ffa, S3C2410_ADCCON); -- A/D转换器预分频器使能,预分频值0xff,模拟输入通道SEL_MUX为XP,正常工作模式,使能读启动操作   
  172. // __raw_readl(S3C2410_ADCDAT0); -- 读取ADCDAT)的值   
  173. #define start_adc_x()   do {__raw_writel(0x00007ffa, S3C2410_ADCCON); \   
  174.                 __raw_readl(S3C2410_ADCDAT0); } while(0)  
  175.                   
  176. // 怎么跟start_adc_x()配置一样?应该为0x00007fea?   
  177. #define start_adc_y()   do {__raw_writel(0x00007ffa, S3C2410_ADCCON); \   
  178.                 __raw_readl(S3C2410_ADCDAT1); } while(0)  
  179.                   
  180.   
  181. // 禁止读启动操作,即READ_START位置0   
  182. #define disable_ts_adc()    __raw_writel(__raw_readl(S3C2410_ADCCON)&0xfffffffd, S3C2410_ADCCON)   
  183.   
  184.   
  185. static int adc_state = 0;  
  186. static int x, y;    /* touch screen coorinates */  
  187.   
  188. #ifdef HOOK_FOR_DRAG   
  189.     #define RT_BT_EMU_TM    ((HZ>>1)+(HZ>>2))   //0.75S   
  190.     //static u16 ts_r_x[5];   
  191.     //static u16 ts_r_y[5];   
  192.     //static u16 ts_r_idx;   
  193.     //static u16 ts_r_beg;   
  194.     static u32 dn_start;  
  195. #endif   
  196.   
  197. static void tsEvent_raw(void)  
  198. {  
  199. DPRINTK("@@@@@@@@ tvEvent_raw() @@@@@@@@@\n");  
  200.     if (tsdev.penStatus == PEN_DOWN)  
  201.     {  
  202.         //u16 i, j;   
  203. #ifdef HOOK_FOR_DRAG    
  204.         ts_timer.expires = jiffies + TS_TIMER_DELAY;  
  205.         add_timer(&ts_timer);  
  206. #endif   
  207.         BUF_HEAD.x = x;  
  208.         BUF_HEAD.y = y;  
  209.           
  210. #ifdef HOOK_FOR_DRAG   
  211.                 BUF_HEAD.pressure = ((jiffies - dn_start) >= RT_BT_EMU_TM) ? PEN_FLEETING : PEN_DOWN;  
  212. #else   
  213.                 BUF_HEAD.pressure = PEN_DOWN;  
  214. #endif   
  215.           
  216.           
  217.     }/* if (tsdev.penStatus == PEN_DOWN) */  
  218.     else  
  219.     {  
  220. #ifdef HOOK_FOR_DRAG    
  221.         del_timer(&ts_timer);  
  222. #endif   
  223.         BUF_HEAD.x = x;  
  224.         BUF_HEAD.y = y;  
  225.         BUF_HEAD.pressure = PEN_UP;  
  226.     }  
  227.   
  228.     tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF);  
  229. DPRINTK("@@@@@@@@ wake_up_interruptible() in tvEvent_raw() @@@@@@@@@\n");  
  230.     wake_up_interruptible(&(tsdev.wq));  
  231.   
  232. #ifdef USE_ASYNC   
  233.     if (tsdev.aq)  
  234.         kill_fasync(&(tsdev.aq), SIGIO, POLL_IN);  
  235. #endif   
  236.   
  237. #ifdef CONFIG_PM   
  238.     pm_access(tsdev.pm_dev);  
  239. #endif   
  240. }  
  241.   
  242. static int tsRead(TS_RET * ts_ret)  
  243. {  
  244.     spin_lock_irq(&(tsdev.lock));  
  245.     ts_ret->x = BUF_TAIL.x;  
  246.     ts_ret->y = BUF_TAIL.y;  
  247.     ts_ret->pressure = BUF_TAIL.pressure;  
  248.     tsdev.tail = INCBUF(tsdev.tail, MAX_TS_BUF);  
  249.     spin_unlock_irq(&(tsdev.lock));  
  250.   
  251.     return sizeof(TS_RET);  
  252. }  
  253.   
  254. static ssize_t s3c2410_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)  
  255. {  
  256.     TS_RET ts_ret;  
  257.   
  258. retry:   
  259.     if (tsdev.head != tsdev.tail)  
  260.     {  
  261.         int count;  
  262.         count = tsRead(&ts_ret);  
  263.         if (count)  
  264.         {  
  265. printk("@@@@@ ts_ret.x: %hd, ts_ret.y: %hd @@@@@@@\n", ts_ret.x, ts_ret.y);  
  266.             copy_to_user(buffer, (char *)&ts_ret, count);  
  267.         }  
  268.         return count;  
  269.     }   
  270.     else  
  271.     {  
  272.         if (filp->f_flags & O_NONBLOCK)  
  273.             return -EAGAIN;  
  274.         interruptible_sleep_on(&(tsdev.wq));  
  275.         if (signal_pending(current))  
  276.             return -ERESTARTSYS;  
  277.         goto retry;  
  278.     }  
  279.   
  280.     return sizeof(TS_RET);  
  281. }  
  282.   
  283. #ifdef USE_ASYNC   
  284. static int s3c2410_ts_fasync(int fd, struct file *filp, int mode)   
  285. {  
  286.     return fasync_helper(fd, filp, mode, &(tsdev.aq));  
  287. }  
  288. #endif   
  289.   
  290. static unsigned int s3c2410_ts_poll(struct file *filp, struct poll_table_struct *wait)  
  291. {  
  292.     poll_wait(filp, &(tsdev.wq), wait);  
  293.     return (tsdev.head == tsdev.tail) ? 0 : (POLLIN | POLLRDNORM);   
  294. }  
  295.   
  296. static inline void start_ts_adc(void)  
  297. {  
  298.     adc_state = 0;  
  299.     mode_x_axis();  
  300.     start_adc_x();  
  301. }  
  302.   
  303. static inline void s3c2410_get_XY(void)  
  304. {  
  305.     if (adc_state == 0)  
  306.     {   
  307.         adc_state = 1;  
  308.         disable_ts_adc();  
  309.         y = __raw_readl(S3C2410_ADCDAT1) & 0x3ff;       //x:f04 y:f0e dh  by pht.   
  310.         mode_y_axis();  
  311.         start_adc_y();  
  312.     }  
  313.     else if (adc_state == 1)  
  314.     {   
  315.         adc_state = 0;  
  316.         disable_ts_adc();  
  317.         x = __raw_readl(S3C2410_ADCDAT0) & 0x3ff;         //y:f04 x:f0e dh by pht.   
  318. printk("@@@@@@ PEN DOWN: x: %d, y: %d @@@@@@\n", x, y);  
  319.         wait_up_int();  
  320.         tsdev.penStatus = PEN_DOWN;  
  321.         tsEvent();  
  322.     }  
  323. }  
  324.   
  325. static irqreturn_t s3c2410_isr_adc(int irq, void *dev_id, struct pt_regs *reg)  
  326. {  
  327. DPRINTK("@@@@@@@@ s3c2410_isr_adc() @@@@@@@@\n");  
  328.     spin_lock_irq(&(tsdev.lock));  
  329.     if (tsdev.penStatus == PEN_UP)  
  330.     {  
  331. DPRINTK("@@@@@@ s3c2410_isr_adc 1 @@@@@@\n");  
  332.             s3c2410_get_XY();  
  333.     }  
  334. #ifdef HOOK_FOR_DRAG   
  335.     else  
  336.     {  
  337. DPRINTK("@@@@@@ s3c2410_isr_adc 2 @@@@@@\n");  
  338.             s3c2410_get_XY();  
  339.     }  
  340. #endif   
  341.     spin_unlock_irq(&(tsdev.lock));  
  342.   
  343.     return IRQ_HANDLED;  
  344. }  
  345.   
  346. static irqreturn_t s3c2410_isr_tc(int irq, void *dev_id, struct pt_regs *reg)  
  347. {  
  348. DPRINTK("@@@@@@@@ s3c2410_isr_tc() @@@@@@@@\n");  
  349.     spin_lock_irq(&(tsdev.lock));  
  350.     if (tsdev.penStatus == PEN_UP)  
  351.     {  
  352. DPRINTK("@@@@@@@@ s3c2410_isr_tc 1 @@@@@@@@\n");  
  353. #ifdef HOOK_FOR_DRAG   
  354.       dn_start = jiffies; // add by gzliu   
  355. #endif   
  356.       start_ts_adc();  
  357.     }  
  358.     else  
  359.     {  
  360.       tsdev.penStatus = PEN_UP;  
  361. DPRINTK("@@@@@@@@ s3c2410_isr_tc 2 @@@@@@@@\n");  
  362. printk("@@@@@@@ PEN UP: x: %d, y: %d @@@@@@@\n", x, y);  
  363.       wait_down_int();  
  364.       tsEvent();  
  365.     }  
  366.     spin_unlock_irq(&(tsdev.lock));  
  367.   
  368.     return IRQ_HANDLED;  
  369. }  
  370.   
  371. #ifdef HOOK_FOR_DRAG   
  372. static void ts_timer_handler(unsigned long data)  
  373. {  
  374.     spin_lock_irq(&(tsdev.lock));  
  375.     if (tsdev.penStatus == PEN_DOWN)  
  376.     {  
  377.         start_ts_adc();  
  378.     }  
  379.     spin_unlock_irq(&(tsdev.lock));  
  380. }  
  381. #endif   
  382.   
  383. static int s3c2410_ts_open(struct inode *inode, struct file *filp)  
  384. {  
  385.     tsdev.head = tsdev.tail = 0;  
  386.     tsdev.penStatus = PEN_UP;  
  387. #ifdef HOOK_FOR_DRAG    
  388.     init_timer(&ts_timer);  
  389.     ts_timer.function = ts_timer_handler;  
  390. #endif   
  391.     tsEvent = tsEvent_raw;  
  392.     init_waitqueue_head(&(tsdev.wq));  
  393.   
  394.     //MOD_INC_USE_COUNT;   
  395.     return 0;  
  396. }  
  397.   
  398. static int s3c2410_ts_release(struct inode *inode, struct file *filp)  
  399. {  
  400. #ifdef HOOK_FOR_DRAG   
  401.     del_timer(&ts_timer);  
  402. #endif   
  403.     //MOD_DEC_USE_COUNT;   
  404.     return 0;  
  405. }  
  406.   
  407. static struct file_operations s3c2410_fops = {  
  408.     owner:  THIS_MODULE,  
  409.     open:   s3c2410_ts_open,  
  410.     read:   s3c2410_ts_read,      
  411.     release:    s3c2410_ts_release,  
  412. #ifdef USE_ASYNC   
  413.     fasync: s3c2410_ts_fasync,  
  414. #endif   
  415.     poll:   s3c2410_ts_poll,  
  416. };  
  417.   
  418. void tsEvent_dummy(void) {}  
  419. #ifdef CONFIG_PM   
  420. static int s3c2410_ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,   
  421.                                    void *data)   
  422. {  
  423.     switch (req) {  
  424.         case PM_SUSPEND:  
  425.             tsEvent = tsEvent_dummy;  
  426.             break;  
  427.         case PM_RESUME:  
  428.             tsEvent = tsEvent_raw;  
  429.             wait_down_int();  
  430.             break;  
  431.     }  
  432.     return 0;  
  433. }  
  434. #endif   
  435.   
  436.   
  437. static struct clk   *adc_clock;  
  438. static int __init s3c2410ts_probe(struct device *dev)  
  439. {  
  440.     int ret;  
  441.    
  442.     tsEvent = tsEvent_dummy;  
  443. DPRINTK("@@@@@@@@@@ s3c2410ts_probe @@@@@@@@@@\n");  
  444.     ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops);  
  445.     if (ret < 0) {  
  446.       printk(DEVICE_NAME " can't get major number\n");  
  447.       return ret;  
  448.     }  
  449.   
  450.     tsMajor = ret;  
  451.   
  452.     adc_clock = clk_get(NULL, "adc");  
  453.     if (!adc_clock) {  
  454.         printk(KERN_ERR "failed to get adc clock source\n");  
  455.         return -ENOENT;  
  456.     }  
  457.     clk_use(adc_clock);  
  458.     clk_enable(adc_clock);  
  459.       
  460.     base_addr = ioremap(S3C2410_PA_ADC, 0x20);  
  461.       
  462.     __raw_writel(WAIT4INT(0), S3C2410_ADCTSC);  
  463.   
  464.     __raw_writel(30000, S3C2410_ADCDLY);    // 30000--20000   
  465.   
  466.     ret = request_irq(IRQ_ADC, s3c2410_isr_adc, SA_INTERRUPT, DEVICE_NAME, s3c2410_isr_adc);  
  467.     if (ret)  
  468.         goto adc_failed;  
  469.     ret = request_irq(IRQ_TC, s3c2410_isr_tc, SA_INTERRUPT, DEVICE_NAME, s3c2410_isr_tc);  
  470.     if (ret)  
  471.         goto tc_failed;  
  472.   
  473.     /* Wait for touch screen interrupts */  
  474.     wait_down_int();  
  475.           
  476. #ifdef CONFIG_DEVFS_FS   
  477.     devfs_mk_dir("touchscreen");  
  478.     devfs_mk_cdev(MKDEV(tsMajor, TSRAW_MINOR), S_IFCHR|S_IRUGO|S_IWUSR, "touchscreen/%s""0raw");  
  479. #endif   
  480.   
  481. #ifdef CONFIG_PM   
  482.     tsdev.pm_dev = pm_register(PM_DEBUG_DEV, PM_USER_INPUT, s3c2410_ts_pm_callback);  
  483. #endif   
  484.   
  485.     return 0;  
  486.  tc_failed:  
  487.         {  
  488.             printk(KERN_ERR "tc failed!!!!!!!!!!!!!\n");  
  489.             free_irq(IRQ_ADC, s3c2410_isr_adc);  
  490.         }  
  491.  adc_failed:  
  492.         {  
  493.             printk(KERN_ERR "adc failed!!!!!!!!!!!!!\n");  
  494.             return ret;  
  495.         }  
  496. }  
  497.   
  498. static struct device_driver s3c2410ts_driver = {  
  499.     .name       = DEVICE_NAME,  
  500.     .bus        = &platform_bus_type,  
  501.     .probe      = s3c2410ts_probe,  
  502. #ifdef CONFIG_PM   
  503.     .suspend    = s3c2410ts_suspend,  
  504.     .resume     = s3c2410ts_resume,  
  505. #endif   
  506. };  
  507.   
  508. static int __init s3c2410ts_init(void)  
  509. {  
  510.     int ret;  
  511.   
  512.     printk("@@@@@@@@ s3c2410ts init() @@@@@@@\n");  
  513.     ret = driver_register(&s3c2410ts_driver);  
  514.     if(ret)  
  515.     {  
  516.             printk("register %s driver failed, return code is %d\n", DEVICE_NAME, ret);  
  517.         }  
  518.     else  
  519.     {  
  520.         printk("@@@@@@@ register %s driver success, return code is %d @@@@@@@@@@\n", DEVICE_NAME, ret);  
  521.     }  
  522.     return ret;  
  523. }  
  524.   
  525.   
  526. static void __exit s3c2410ts_exit(void)  
  527. {  
  528. #ifdef CONFIG_DEVFS_FS     
  529.     devfs_remove("touchscreen/%d", 0);  
  530.     devfs_remove("touchscreen");  
  531. #endif     
  532.     unregister_chrdev(tsMajor, DEVICE_NAME);  
  533. #ifdef CONFIG_PM   
  534.     pm_unregister(tsdev.pm_dev);  
  535. #endif   
  536.     free_irq(IRQ_ADC, s3c2410_isr_adc);  
  537.     free_irq(IRQ_TC, s3c2410_isr_tc);  
  538.     driver_unregister(&s3c2410ts_driver);  
  539. }  
  540.   
  541. module_init(s3c2410ts_init);  
  542. module_exit(s3c2410ts_exit);  

相关内容