newton: modify irda driver
authorlyx <lyx@rock-chips.com>
Fri, 26 Aug 2011 09:56:45 +0000 (02:56 -0700)
committerlyx <lyx@rock-chips.com>
Fri, 26 Aug 2011 10:00:00 +0000 (03:00 -0700)
1.add open mutex lock with cir
2.improve suspend and resume function
3.improve irda err handle

drivers/net/irda/ir_serial.c

index 09d9965eee5a7343fe4a8df96418076f087f0de4..29f9722910002577042430aba8d3d95d8be6f7d8 100755 (executable)
@@ -68,6 +68,7 @@ struct bu92747_port {
        struct work_struct work;\r
        /* set to 1 to make the workhandler exit as soon as possible */\r
        int  force_end_work;\r
+       int open_flag;\r
        /* need to know we are suspending to avoid deadlock on workqueue */\r
        int suspending;\r
 \r
@@ -89,13 +90,29 @@ static u8 g_receive_buf[BU92725GUW_FIFO_SIZE];
 #define BU92747_IRDA_DBG(x...)\r
 #endif\r
 \r
+\r
+/* race on startup&shutdown, mutex lock with CIR driver */\r
+static DEFINE_MUTEX(irda_cir_lock);\r
+int bu92747_try_lock(void)\r
+{\r
+       if (mutex_trylock(&irda_cir_lock))\r
+               return 1;       //ready\r
+       else\r
+               return 0;       //busy\r
+}\r
+\r
+void bu92747_unlock(void)\r
+{\r
+       return mutex_unlock(&irda_cir_lock);\r
+}\r
+\r
 static int add_frame_length(struct rev_frame_length *f, unsigned long length)\r
 {\r
        if (frame_write_full(f))\r
                return -1;\r
 \r
        f->frame_length[f->iWrite] = length;\r
-       printk("add one frame, length=%d\n", f->frame_length[f->iWrite]);\r
+       printk("add one frame, length=%ld\n", f->frame_length[f->iWrite]);\r
        f->iCount++;\r
        printk("now frame iCount=%d\n", f->iCount);\r
        f->iWrite = (f->iWrite+1) % MAX_FRAME_NUM;\r
@@ -111,7 +128,7 @@ static int get_frame_length(struct rev_frame_length *f, unsigned long *length)
                return -1;\r
 \r
        *length = f->frame_length[f->iRead];\r
-       printk("read one frame, length=%d\n", *length);\r
+       printk("read one frame, length=%ld\n", *length);\r
        f->iCount--;\r
        printk("now frame iCount=%d\n", f->iCount);\r
        f->iRead = (f->iRead+1) % MAX_FRAME_NUM;\r
@@ -149,10 +166,10 @@ static int bu92747_irda_do_rx(struct bu92747_port *s)
 \r
 static int bu92747_irda_do_tx(struct bu92747_port *s)\r
 {\r
-       int i;\r
+       //int i;\r
        struct circ_buf *xmit = &s->port.state->xmit;\r
        int len = uart_circ_chars_pending(xmit);\r
-       BU92747_IRDA_DBG("line %d, enter %s \n", __LINE__, __FUNCTION__);\r
+       printk("line %d, enter %s, sending %d data\n", __LINE__, __FUNCTION__, len);\r
        \r
        if (IS_FIR(s)) {\r
                //printk("fir sending.....\n");\r
@@ -163,11 +180,11 @@ static int bu92747_irda_do_tx(struct bu92747_port *s)
                irda_hw_tx_enable_irq(BU92725GUW_SIR);\r
        }\r
 \r
-       BU92747_IRDA_DBG("data:\n");\r
-       for (i=0; i<len; i++) {\r
-               BU92747_IRDA_DBG("%d ", xmit->buf[xmit->tail+i]);\r
-       }\r
-       BU92747_IRDA_DBG("\n");\r
+       //BU92747_IRDA_DBG("data:\n");\r
+       //for (i=0; i<len; i++) {\r
+               //BU92747_IRDA_DBG("%d ", xmit->buf[xmit->tail+i]);\r
+       //}\r
+       //BU92747_IRDA_DBG("\n");\r
        \r
        if (len>0) {            \r
                s->tx_empty = 0;\r
@@ -197,7 +214,7 @@ static void bu92747_irda_work(struct work_struct *w)
        struct circ_buf *xmit = &s->port.state->xmit;\r
 \r
        dev_dbg(s->dev, "%s\n", __func__);\r
-       BU92747_IRDA_DBG("line %d, enter %s \n", __LINE__, __FUNCTION__);\r
+       printk("line %d, enter %s \n", __LINE__, __FUNCTION__);\r
 \r
        if (!s->force_end_work && !freezing(current)) {\r
                //BU92725GUW_dump_register();\r
@@ -222,18 +239,6 @@ static irqreturn_t bu92747_irda_irq(int irqno, void *dev_id)
        BU92747_IRDA_DBG("line %d, enter %s \n", __LINE__, __FUNCTION__);\r
        irq_src = irda_hw_get_irqsrc();\r
        printk("[%s][%d], 0x%x\n",__FUNCTION__,__LINE__, irq_src);\r
-       /* error */\r
-       if (irq_src & (REG_INT_TO| REG_INT_CRC | REG_INT_OE | REG_INT_FE\r
-               | REG_INT_AC | REG_INT_DECE | REG_INT_RDOE | REG_INT_DEX)) {\r
-               BU92747_IRDA_DBG("[%s][%d]: do err\n", __FUNCTION__, __LINE__);\r
-               //BU92725GUW_dump_register();\r
-               BU92725GUW_clr_fifo();\r
-               BU92725GUW_reset();\r
-               if ((BU92725GUW_SEND==irda_hw_get_mode())\r
-                       || (BU92725GUW_MULTI_SEND==irda_hw_get_mode())) {\r
-                       s->tx_empty = 1;\r
-               }\r
-       }\r
        \r
        if (irq_src & (REG_INT_DRX | FRM_EVT_RX_EOFRX | FRM_EVT_RX_RDE)) {\r
                len = bu92747_irda_do_rx(s);\r
@@ -266,6 +271,19 @@ static irqreturn_t bu92747_irda_irq(int irqno, void *dev_id)
                s->tx_empty = 1;\r
                irda_hw_set_moderx();\r
        }\r
+\r
+       /* error */\r
+       if (irq_src & (REG_INT_TO| REG_INT_CRC | REG_INT_OE | REG_INT_FE\r
+               | REG_INT_AC | REG_INT_DECE | REG_INT_RDOE | REG_INT_DEX)) {\r
+               BU92747_IRDA_DBG("[%s][%d]: do err\n", __FUNCTION__, __LINE__);\r
+               //BU92725GUW_dump_register();\r
+               BU92725GUW_clr_fifo();\r
+               BU92725GUW_reset();\r
+               if ((BU92725GUW_SEND==irda_hw_get_mode())\r
+                       || (BU92725GUW_MULTI_SEND==irda_hw_get_mode())) {\r
+                       s->tx_empty = 1;\r
+               }\r
+       }\r
        \r
        return IRQ_HANDLED;\r
 }\r
@@ -294,10 +312,7 @@ static void bu92747_irda_start_tx(struct uart_port *port)
        if (IS_FIR(s))\r
                return  ;\r
 \r
-       if (s->tx_empty)\r
-               bu92747_irda_do_tx(s);\r
-       else \r
-               bu92747_irda_dowork(s);\r
+       bu92747_irda_dowork(s);\r
 }\r
 \r
 static void bu92747_irda_stop_rx(struct uart_port *port)\r
@@ -385,14 +400,15 @@ static void bu92747_irda_shutdown(struct uart_port *port)
        struct bu92747_port *s = container_of(port,\r
                                                  struct bu92747_port,\r
                                                  port);\r
+       struct rev_frame_length *f = &(s->rev_frames);\r
 \r
        BU92747_IRDA_DBG("line %d, enter %s \n", __LINE__, __FUNCTION__);\r
        dev_dbg(s->dev, "%s\n", __func__);\r
-       struct rev_frame_length *f = &(s->rev_frames);\r
 \r
        if (s->suspending)\r
                return;\r
 \r
+       s->open_flag = 0;\r
        s->force_end_work = 1;\r
 \r
        if (s->workqueue) {\r
@@ -412,8 +428,9 @@ static void bu92747_irda_shutdown(struct uart_port *port)
        \r
        irda_hw_shutdown();\r
        if (s->pdata->irda_pwr_ctl)\r
-               s->pdata->irda_pwr_ctl(0);\r
+               s->pdata->irda_pwr_ctl(0);      \r
 \r
+       bu92747_unlock();\r
 }\r
 \r
 static int bu92747_irda_startup(struct uart_port *port)\r
@@ -427,17 +444,23 @@ static int bu92747_irda_startup(struct uart_port *port)
        BU92747_IRDA_DBG("line %d, enter %s \n", __LINE__, __FUNCTION__);\r
        dev_dbg(s->dev, "%s\n", __func__);\r
 \r
-       s->baud = 9600;\r
        s->rx_enabled = 1;\r
        \r
+       if (s->suspending)\r
+               return 0;\r
+\r
+       if (!bu92747_try_lock()) {\r
+               printk("func %s, cannot get bu92747 lock, bu92747 in using\n", __func__);\r
+               return -EBUSY;\r
+       }\r
+       \r
+       s->baud = 9600;\r
+       \r
        spin_lock(&s->data_lock);\r
        frame_length_buf_clear(f);\r
        s->cur_frame_length = 0;\r
        spin_unlock(&s->data_lock);\r
 \r
-       if (s->suspending)\r
-               return 0;\r
-\r
        s->tx_empty = 1;\r
        s->force_end_work = 0;\r
 \r
@@ -445,6 +468,7 @@ static int bu92747_irda_startup(struct uart_port *port)
        s->workqueue = create_freezeable_workqueue(b);\r
        if (!s->workqueue) {\r
                dev_warn(s->dev, "cannot create workqueue\n");\r
+               bu92747_unlock();\r
                return -EBUSY;\r
        }\r
        INIT_WORK(&s->work, bu92747_irda_work);\r
@@ -457,6 +481,7 @@ static int bu92747_irda_startup(struct uart_port *port)
                s->irq = 0;\r
                destroy_workqueue(s->workqueue);\r
                s->workqueue = NULL;\r
+               bu92747_unlock();\r
                return -EBUSY;\r
        }\r
 \r
@@ -470,6 +495,8 @@ static int bu92747_irda_startup(struct uart_port *port)
 \r
        enable_irq(s->irq);\r
 \r
+       s->open_flag = 1;\r
+\r
        return 0;\r
 }\r
 \r
@@ -700,8 +727,9 @@ static int __devinit bu92747_irda_probe(struct platform_device *pdev)
                dev_warn(&pdev->dev,\r
                         "uart_add_one_port failed for line %d with error %d\n",\r
                         i, retval);\r
-\r
-       /* set shutdown mode to save power. Will be woken-up on open */\r
+       bu92747s[i]->open_flag = 0;\r
+       bu92747s[i]->suspending = 0;\r
+       /* set shutdown mode to save power. Will be woken-up on open */ \r
        if (bu92747s[i]->pdata->irda_pwr_ctl)\r
                bu92747s[i]->pdata->irda_pwr_ctl(0);\r
        \r
@@ -753,16 +781,18 @@ static int bu92747_irda_suspend(struct platform_device *pdev, pm_message_t state
 \r
        dev_dbg(s->dev, "%s\n", __func__);\r
 \r
-       BU92747_IRDA_DBG("line %d, enter %s \n", __LINE__, __FUNCTION__);\r
-       disable_irq(s->irq);\r
-\r
-       s->suspending = 1;\r
-       uart_suspend_port(&bu92747_irda_uart_driver, &s->port);\r
+       if (s->open_flag) {\r
+               printk("line %d, enter %s \n", __LINE__, __FUNCTION__);\r
+               disable_irq(s->irq);\r
 \r
-       //irda_hw_shutdown();\r
-       if (s->pdata->irda_pwr_ctl)\r
-               s->pdata->irda_pwr_ctl(0);\r
+               s->suspending = 1;\r
+               uart_suspend_port(&bu92747_irda_uart_driver, &s->port);\r
 \r
+               irda_hw_shutdown();\r
+               if (s->pdata->irda_pwr_ctl)\r
+                       s->pdata->irda_pwr_ctl(0);\r
+       }\r
+       \r
        return 0;\r
 }\r
 \r
@@ -771,22 +801,28 @@ static int bu92747_irda_resume(struct platform_device *pdev)
        struct bu92747_port *s = dev_get_drvdata(&pdev->dev);\r
 \r
        dev_dbg(s->dev, "%s\n", __func__);\r
-\r
-       BU92747_IRDA_DBG("line %d, enter %s \n", __LINE__, __FUNCTION__);\r
-       if (s->pdata->irda_pwr_ctl)\r
-               s->pdata->irda_pwr_ctl(1);\r
        \r
-       //irda_hw_startup();\r
-       irda_hw_set_speed(s->baud);\r
+       if (s->open_flag) {\r
+               printk("line %d, enter %s \n", __LINE__, __FUNCTION__);\r
+               if (s->pdata->irda_pwr_ctl)\r
+                       s->pdata->irda_pwr_ctl(1);\r
+               \r
+               irda_hw_startup();\r
+               irda_hw_set_speed(s->baud);\r
+               irda_hw_set_moderx();\r
 \r
-       uart_resume_port(&bu92747_irda_uart_driver, &s->port);\r
-       s->suspending = 0;\r
+               uart_resume_port(&bu92747_irda_uart_driver, &s->port);\r
+               s->suspending = 0;\r
 \r
-       enable_irq(s->irq);\r
-       \r
-       if (s->workqueue)\r
-               bu92747_irda_dowork(s);\r
+               enable_irq(s->irq);\r
 \r
+               if (!s->tx_empty)\r
+                       s->tx_empty = 1;\r
+               \r
+               if (s->workqueue && !IS_FIR(s))\r
+                       bu92747_irda_dowork(s);\r
+       }\r
+       \r
        return 0;\r
 }\r
 #else\r