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