diff --git a/drivers/can/can.c b/drivers/can/can.c index b7e6c3bd5d3..2ef300c9c46 100644 --- a/drivers/can/can.c +++ b/drivers/can/can.c @@ -332,7 +332,7 @@ static uint8_t can_bytes2dlc(FAR struct sam_can_s *priv, uint8_t nbytes) * * Description: * This function performs deferred processing from can_txready. See the - * description of can_txready below for additionla information. + * description of can_txready below for additional information. * ****************************************************************************/ @@ -407,11 +407,10 @@ static int can_open(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct can_dev_s *dev = inode->i_private; - uint8_t tmp; + irqstate_t flags; + int tmp; int ret; - caninfo("ocount: %d\n", dev->cd_ocount); - /* If the port is the middle of closing, wait until the close is finished */ ret = can_takesem(&dev->cd_closesem); @@ -420,63 +419,55 @@ static int can_open(FAR struct file *filep) return ret; } - /* Increment the count of references to the device. If this is the first - * time that the driver has been opened for this device, then initialize - * the device. + /* If this is the first time that the driver has been opened + * for this device, then perform hardware initialization. */ - tmp = dev->cd_ocount + 1; - if (tmp == 0) + if (list_is_empty(&dev->cd_readers)) { - /* More than 255 opens; uint8_t overflows to zero */ + caninfo("ocount: %d\n", 0); - ret = -EMFILE; + flags = enter_critical_section(); + ret = dev_setup(dev); + if (ret >= 0) + { + /* Mark the FIFOs empty */ + + dev->cd_xmit.tx_head = 0; + dev->cd_xmit.tx_queue = 0; + dev->cd_xmit.tx_tail = 0; + + /* Finally, Enable the CAN RX interrupt */ + + dev_rxint(dev, true); + } + + list_add_head(&dev->cd_readers, + (FAR struct list_node *)init_can_reader(filep)); + + leave_critical_section(flags); } else { - /* Check if this is the first time that the driver has been opened. */ + tmp = list_length(&dev->cd_readers); + caninfo("ocount: %d\n", tmp); - if (tmp == 1) + if (tmp >= 255) { - /* Yes.. perform one time hardware initialization. */ + /* Limit to no more than 255 opens */ - irqstate_t flags = enter_critical_section(); - ret = dev_setup(dev); - if (ret >= 0) - { - /* Mark the FIFOs empty */ - - dev->cd_xmit.tx_head = 0; - dev->cd_xmit.tx_queue = 0; - dev->cd_xmit.tx_tail = 0; - - /* Finally, Enable the CAN RX interrupt */ - - dev_rxint(dev, true); - - /* Save the new open count only on success */ - - dev->cd_ocount = 1; - - list_initialize(&dev->cd_readers); - } - - leave_critical_section(flags); - } - else - { - /* Save the incremented open count */ - - dev->cd_ocount = tmp; + ret = -EMFILE; + goto errout; } - irqstate_t flags = enter_critical_section(); - list_add_head(&dev->cd_readers, - (FAR struct list_node *)init_can_reader(filep)); + flags = enter_critical_section(); + list_add_head(&dev->cd_readers, + (FAR struct list_node *)init_can_reader(filep)); - leave_critical_section(flags); + leave_critical_section(flags); } +errout: can_givesem(&dev->cd_closesem); return ret; } @@ -499,7 +490,9 @@ static int can_close(FAR struct file *filep) FAR struct list_node *tmp; int ret; - caninfo("ocount: %d\n", dev->cd_ocount); +#ifdef CONFIG_DEBUG_CAN_INFO + caninfo("ocount: %d\n", list_length(&dev->cd_readers)); +#endif ret = can_takesem(&dev->cd_closesem); if (ret < 0) @@ -520,20 +513,13 @@ static int can_close(FAR struct file *filep) filep->f_priv = NULL; - /* Decrement the references to the driver. If the reference count will - * decrement to 0, then uninitialize the driver. - */ + /* Uninitialize the driver if there are no more readers */ - if (dev->cd_ocount > 1) + if (!list_is_empty(&dev->cd_readers)) { - dev->cd_ocount--; goto errout; } - /* There are no more references to the port */ - - dev->cd_ocount = 0; - /* Stop accepting input */ dev_rxint(dev, false); @@ -574,13 +560,15 @@ errout: static ssize_t can_read(FAR struct file *filep, FAR char *buffer, size_t buflen) { - FAR struct inode *inode = filep->f_inode; - FAR struct can_dev_s *dev = inode->i_private; FAR struct can_reader_s *reader = NULL; FAR struct can_rxfifo_s *fifo; size_t nread; irqstate_t flags; int ret = 0; +#ifdef CONFIG_CAN_ERRORS + FAR struct inode *inode = filep->f_inode; + FAR struct can_dev_s *dev = inode->i_private; +#endif caninfo("buflen: %d\n", buflen); @@ -649,10 +637,7 @@ static ssize_t can_read(FAR struct file *filep, FAR char *buffer, /* Wait for a message to be received */ - DEBUGASSERT(dev->cd_nrxwaiters < 255); - dev->cd_nrxwaiters++; ret = can_takesem(&fifo->rx_sem); - dev->cd_nrxwaiters--; if (ret < 0) { @@ -1123,14 +1108,11 @@ static int can_poll(FAR struct file *filep, FAR struct pollfd *fds, * should, but that would be a little awkward). */ - DEBUGASSERT(dev->cd_nrxwaiters < 255); - dev->cd_nrxwaiters++; do { ret = can_takesem(&reader->fifo.rx_sem); } while (ret < 0); - dev->cd_nrxwaiters--; if (reader->fifo.rx_head != reader->fifo.rx_tail) { @@ -1190,9 +1172,8 @@ int can_register(FAR const char *path, FAR struct can_dev_s *dev) /* Initialize the CAN device structure */ - dev->cd_ocount = 0; + list_initialize(&dev->cd_readers); dev->cd_ntxwaiters = 0; - dev->cd_nrxwaiters = 0; dev->cd_npendrtr = 0; #ifdef CONFIG_CAN_ERRORS dev->cd_error = 0; diff --git a/include/nuttx/can/can.h b/include/nuttx/can/can.h index d1cd37dffe9..09a685e1fa2 100644 --- a/include/nuttx/can/can.h +++ b/include/nuttx/can/can.h @@ -580,17 +580,14 @@ struct can_ops_s struct can_reader_s { struct list_node list; - sem_t read_sem; struct can_rxfifo_s fifo; /* Describes receive FIFO */ }; struct can_dev_s { - uint8_t cd_ocount; /* The number of times the device has been opened */ uint8_t cd_npendrtr; /* Number of pending RTR messages */ volatile uint8_t cd_ntxwaiters; /* Number of threads waiting to enqueue a message */ - volatile uint8_t cd_nrxwaiters; /* Number of threads waiting to receive a message */ - struct list_node cd_readers; /* Number of readers */ + struct list_node cd_readers; /* List of readers */ #ifdef CONFIG_CAN_ERRORS uint8_t cd_error; /* Flags to indicate internal device errors */ #endif @@ -644,7 +641,7 @@ struct canioc_bittiming_s struct canioc_connmodes_s { uint8_t bm_loopback : 1; /* Enable reception of messages sent - * by this node.*/ + * by this node. */ uint8_t bm_silent : 1; /* Disable transmission of messages. * The node still receives messages. */ };