*/
PARM_INT(debug, 0x00, 0644, "Driver debugging level");
PARM_INT(rawreadok, 1, 0644, "Bypass flip buffers on input");
-PARM_INT(trcbuf_size, 0x100000, 0644, "Debugging trace buffer size.");
+PARM_INT(trcbuf_size, 0x100000, 0644, "Debugging trace buffer size.");
/**************************************************************************
*
static int dgnc_found_board(struct pci_dev *pdev, int id);
static void dgnc_cleanup_board(struct dgnc_board *brd);
static void dgnc_poll_handler(ulong dummy);
-static int dgnc_init_pci(void);
static int dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-static void dgnc_remove_one(struct pci_dev *dev);
-static int dgnc_probe1(struct pci_dev *pdev, int card_type);
static void dgnc_do_remap(struct dgnc_board *brd);
-/* Driver load/unload functions */
-int dgnc_init_module(void);
-void dgnc_cleanup_module(void);
-
-module_init(dgnc_init_module);
-module_exit(dgnc_cleanup_module);
-
-
/*
* File operations permitted on Control/Management major.
*/
static const struct file_operations dgnc_BoardFops = {
.owner = THIS_MODULE,
- .unlocked_ioctl = dgnc_mgmt_ioctl,
+ .unlocked_ioctl = dgnc_mgmt_ioctl,
.open = dgnc_mgmt_open,
.release = dgnc_mgmt_close
};
uint dgnc_NumBoards;
struct dgnc_board *dgnc_Board[MAXBOARDS];
DEFINE_SPINLOCK(dgnc_global_lock);
-int dgnc_driver_state = DRIVER_INITIALIZED;
-ulong dgnc_poll_counter;
uint dgnc_Major;
int dgnc_poll_tick = 20; /* Poll interval - 20 ms */
/*
* Static vars.
*/
-static uint dgnc_Major_Control_Registered = FALSE;
-static uint dgnc_driver_start = FALSE;
-
static struct class *dgnc_class;
/*
* Poller stuff
*/
-static DEFINE_SPINLOCK(dgnc_poll_lock); /* Poll scheduling lock */
+static DEFINE_SPINLOCK(dgnc_poll_lock); /* Poll scheduling lock */
static ulong dgnc_poll_time; /* Time of next poll */
static uint dgnc_poll_stop; /* Used to tell poller to stop */
static struct timer_list dgnc_poll_timer;
{ DIGI_VID, PCI_DEVICE_CLASSIC_4_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
{ DIGI_VID, PCI_DEVICE_CLASSIC_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
{ DIGI_VID, PCI_DEVICE_CLASSIC_8_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
- { DIGI_VID, PCI_DEVICE_NEO_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { DIGI_VID, PCI_DEVICE_NEO_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
- { DIGI_VID, PCI_DEVICE_NEO_2DB9_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
- { DIGI_VID, PCI_DEVICE_NEO_2DB9PRI_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 },
- { DIGI_VID, PCI_DEVICE_NEO_2RJ45_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { DIGI_VID, PCI_DEVICE_NEO_2RJ45PRI_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 },
- { DIGI_VID, PCI_DEVICE_NEO_1_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 },
- { DIGI_VID, PCI_DEVICE_NEO_1_422_485_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 },
- { DIGI_VID, PCI_DEVICE_NEO_2_422_485_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 },
- { DIGI_VID, PCI_DEVICE_NEO_EXPRESS_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
- { DIGI_VID, PCI_DEVICE_NEO_EXPRESS_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
- { DIGI_VID, PCI_DEVICE_NEO_EXPRESS_4RJ45_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 },
- { DIGI_VID, PCI_DEVICE_NEO_EXPRESS_8RJ45_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 },
{0,} /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, dgnc_pci_tbl);
struct board_id {
- uchar *name;
+ unsigned char *name;
uint maxports;
unsigned int is_pci_express;
};
.name = "dgnc",
.probe = dgnc_init_one,
.id_table = dgnc_pci_tbl,
- .remove = dgnc_remove_one,
};
"Board READY",
};
-char *dgnc_driver_state_text[] = {
- "Driver Initialized",
- "Driver Ready."
-};
-
-
/************************************************************************
*
*
************************************************************************/
+/*
+ * dgnc_cleanup_module()
+ *
+ * Module unload. This is where it all ends.
+ */
+static void dgnc_cleanup_module(void)
+{
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dgnc_poll_lock, flags);
+ dgnc_poll_stop = 1;
+ spin_unlock_irqrestore(&dgnc_poll_lock, flags);
+
+ /* Turn off poller right away. */
+ del_timer_sync(&dgnc_poll_timer);
+
+ dgnc_remove_driver_sysfiles(&dgnc_driver);
+
+ device_destroy(dgnc_class, MKDEV(dgnc_Major, 0));
+ class_destroy(dgnc_class);
+ unregister_chrdev(dgnc_Major, "dgnc");
+
+ for (i = 0; i < dgnc_NumBoards; ++i) {
+ dgnc_remove_ports_sysfiles(dgnc_Board[i]);
+ dgnc_tty_uninit(dgnc_Board[i]);
+ dgnc_cleanup_board(dgnc_Board[i]);
+ }
+
+ dgnc_tty_post_uninit();
+
+ if (dgnc_NumBoards)
+ pci_unregister_driver(&dgnc_driver);
+}
/*
* init_module()
*
* Module load. This is where it all starts.
*/
-int dgnc_init_module(void)
+static int __init dgnc_init_module(void)
{
int rc = 0;
/*
* Find and configure all the cards
*/
- rc = dgnc_init_pci();
+ rc = pci_register_driver(&dgnc_driver);
/*
* If something went wrong in the scan, bail out of driver.
dgnc_create_driver_sysfiles(&dgnc_driver);
}
- DPR_INIT(("Finished init_module. Returning %d\n", rc));
return rc;
}
+module_init(dgnc_init_module);
+module_exit(dgnc_cleanup_module);
/*
* Start of driver.
int rc = 0;
unsigned long flags;
- if (dgnc_driver_start == FALSE) {
-
- dgnc_driver_start = TRUE;
-
- /* make sure that the globals are init'd before we do anything else */
- dgnc_init_globals();
+ /* make sure that the globals are init'd before we do anything else */
+ dgnc_init_globals();
- dgnc_NumBoards = 0;
+ APR(("For the tools package or updated drivers please visit http://www.digi.com\n"));
- APR(("For the tools package or updated drivers please visit http://www.digi.com\n"));
-
- /*
- * Register our base character device into the kernel.
- * This allows the download daemon to connect to the downld device
- * before any of the boards are init'ed.
- */
- if (!dgnc_Major_Control_Registered) {
- /*
- * Register management/dpa devices
- */
- rc = register_chrdev(0, "dgnc", &dgnc_BoardFops);
- if (rc <= 0) {
- APR(("Can't register dgnc driver device (%d)\n", rc));
- rc = -ENXIO;
- return rc;
- }
- dgnc_Major = rc;
-
- dgnc_class = class_create(THIS_MODULE, "dgnc_mgmt");
- device_create(dgnc_class, NULL,
- MKDEV(dgnc_Major, 0),
- NULL, "dgnc_mgmt");
- dgnc_Major_Control_Registered = TRUE;
- }
+ /*
+ * Register our base character device into the kernel.
+ * This allows the download daemon to connect to the downld device
+ * before any of the boards are init'ed.
+ *
+ * Register management/dpa devices
+ */
+ rc = register_chrdev(0, "dgnc", &dgnc_BoardFops);
+ if (rc <= 0) {
+ APR(("Can't register dgnc driver device (%d)\n", rc));
+ return -ENXIO;
+ }
+ dgnc_Major = rc;
- /*
- * Init any global tty stuff.
- */
- rc = dgnc_tty_preinit();
+ dgnc_class = class_create(THIS_MODULE, "dgnc_mgmt");
+ device_create(dgnc_class, NULL,
+ MKDEV(dgnc_Major, 0),
+ NULL, "dgnc_mgmt");
- if (rc < 0) {
- APR(("tty preinit - not enough memory (%d)\n", rc));
- return rc;
- }
+ /*
+ * Init any global tty stuff.
+ */
+ rc = dgnc_tty_preinit();
- /* Start the poller */
- DGNC_LOCK(dgnc_poll_lock, flags);
- init_timer(&dgnc_poll_timer);
- dgnc_poll_timer.function = dgnc_poll_handler;
- dgnc_poll_timer.data = 0;
- dgnc_poll_time = jiffies + dgnc_jiffies_from_ms(dgnc_poll_tick);
- dgnc_poll_timer.expires = dgnc_poll_time;
- DGNC_UNLOCK(dgnc_poll_lock, flags);
+ if (rc < 0) {
+ APR(("tty preinit - not enough memory (%d)\n", rc));
+ return rc;
+ }
- add_timer(&dgnc_poll_timer);
+ /* Start the poller */
+ spin_lock_irqsave(&dgnc_poll_lock, flags);
+ init_timer(&dgnc_poll_timer);
+ dgnc_poll_timer.function = dgnc_poll_handler;
+ dgnc_poll_timer.data = 0;
+ dgnc_poll_time = jiffies + dgnc_jiffies_from_ms(dgnc_poll_tick);
+ dgnc_poll_timer.expires = dgnc_poll_time;
+ spin_unlock_irqrestore(&dgnc_poll_lock, flags);
- dgnc_driver_state = DRIVER_READY;
- }
+ add_timer(&dgnc_poll_timer);
return rc;
}
-/*
- * Register pci driver, and return how many boards we have.
- */
-static int dgnc_init_pci(void)
-{
- return pci_register_driver(&dgnc_driver);
-}
-
-
/* returns count (>= 0), or negative on error */
static int dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
if (rc < 0) {
rc = -EIO;
} else {
- rc = dgnc_probe1(pdev, ent->driver_data);
- if (rc == 0) {
+ rc = dgnc_found_board(pdev, ent->driver_data);
+ if (rc == 0)
dgnc_NumBoards++;
- DPR_INIT(("Incrementing numboards to %d\n", dgnc_NumBoards));
- }
}
return rc;
}
-static int dgnc_probe1(struct pci_dev *pdev, int card_type)
-{
- return dgnc_found_board(pdev, card_type);
-}
-
-
-static void dgnc_remove_one(struct pci_dev *dev)
-{
- /* Do Nothing */
-}
-
-/*
- * dgnc_cleanup_module()
- *
- * Module unload. This is where it all ends.
- */
-void dgnc_cleanup_module(void)
-{
- int i;
- ulong lock_flags;
-
- DGNC_LOCK(dgnc_poll_lock, lock_flags);
- dgnc_poll_stop = 1;
- DGNC_UNLOCK(dgnc_poll_lock, lock_flags);
-
- /* Turn off poller right away. */
- del_timer_sync(&dgnc_poll_timer);
-
- dgnc_remove_driver_sysfiles(&dgnc_driver);
-
- if (dgnc_Major_Control_Registered) {
- device_destroy(dgnc_class, MKDEV(dgnc_Major, 0));
- class_destroy(dgnc_class);
- unregister_chrdev(dgnc_Major, "dgnc");
- }
-
- for (i = 0; i < dgnc_NumBoards; ++i) {
- dgnc_remove_ports_sysfiles(dgnc_Board[i]);
- dgnc_tty_uninit(dgnc_Board[i]);
- dgnc_cleanup_board(dgnc_Board[i]);
- }
-
- dgnc_tty_post_uninit();
-
- if (dgnc_NumBoards)
- pci_unregister_driver(&dgnc_driver);
-}
-
-
/*
* dgnc_cleanup_board()
*
if (brd->msgbuf_head) {
unsigned long flags;
- DGNC_LOCK(dgnc_global_lock, flags);
+ spin_lock_irqsave(&dgnc_global_lock, flags);
brd->msgbuf = NULL;
printk("%s", brd->msgbuf_head);
kfree(brd->msgbuf_head);
brd->msgbuf_head = NULL;
- DGNC_UNLOCK(dgnc_global_lock, flags);
+ spin_unlock_irqrestore(&dgnc_global_lock, flags);
}
/* Free all allocated channels structs */
unsigned long flags;
/* get the board structure and prep it */
- brd = dgnc_Board[dgnc_NumBoards] =
- kzalloc(sizeof(*brd), GFP_KERNEL);
+ dgnc_Board[dgnc_NumBoards] = kzalloc(sizeof(*brd), GFP_KERNEL);
+ brd = dgnc_Board[dgnc_NumBoards];
+
if (!brd)
return -ENOMEM;
/* make a temporary message buffer for the boot messages */
- brd->msgbuf = brd->msgbuf_head =
- kzalloc(sizeof(u8) * 8192, GFP_KERNEL);
+ brd->msgbuf_head = kzalloc(sizeof(u8) * 8192, GFP_KERNEL);
+ brd->msgbuf = brd->msgbuf_head;
+
if (!brd->msgbuf) {
kfree(brd);
return -ENOMEM;
brd->dpastatus = BD_NOFEP;
init_waitqueue_head(&brd->state_wait);
- DGNC_SPINLOCK_INIT(brd->bd_lock);
- DGNC_SPINLOCK_INIT(brd->bd_intr_lock);
+ spin_lock_init(&brd->bd_lock);
+ spin_lock_init(&brd->bd_intr_lock);
brd->state = BOARD_FOUND;
brd->dpatype = T_CLASSIC | T_PCIBUS;
- DPR_INIT(("dgnc_found_board - Classic.\n"));
-
/*
* For PCI ClassicBoards
* PCI Local Address (i.e. "resource" number) space
else
brd->dpatype = T_NEO | T_PCIBUS;
- DPR_INIT(("dgnc_found_board - NEO.\n"));
-
/* get the PCI Base Address Registers */
brd->membase = pci_resource_start(pdev, 0);
brd->membase_end = pci_resource_end(pdev, 0);
/* init our poll helper tasklet */
tasklet_init(&brd->helper_tasklet, brd->bd_ops->tasklet, (unsigned long) brd);
- DPR_INIT(("dgnc_scan(%d) - printing out the msgbuf\n", i));
- DGNC_LOCK(dgnc_global_lock, flags);
+ spin_lock_irqsave(&dgnc_global_lock, flags);
brd->msgbuf = NULL;
printk("%s", brd->msgbuf_head);
kfree(brd->msgbuf_head);
brd->msgbuf_head = NULL;
- DGNC_UNLOCK(dgnc_global_lock, flags);
+ spin_unlock_irqrestore(&dgnc_global_lock, flags);
/*
* allocate flip buffer for board.
{
int rc = 0;
- DPR_INIT(("dgnc_finalize_board_init() - start\n"));
-
if (!brd || brd->magic != DGNC_BOARD_MAGIC)
return -ENODEV;
- DPR_INIT(("dgnc_finalize_board_init() - start #2\n"));
-
if (brd->irq) {
rc = request_irq(brd->irq, brd->bd_ops->intr,
IRQF_SHARED, "DGNC", brd);
brd->state = BOARD_FAILED;
brd->dpastatus = BD_NOFEP;
rc = -ENODEV;
- } else {
- DPR_INIT(("Requested and received usage of IRQ %d\n",
- brd->irq));
}
}
return rc;
return;
brd->re_map_membase = ioremap(brd->membase, 0x1000);
-
- DPR_INIT(("remapped mem: 0x%p\n", brd->re_map_membase));
}
static void dgnc_poll_handler(ulong dummy)
{
struct dgnc_board *brd;
- unsigned long lock_flags;
+ unsigned long flags;
int i;
unsigned long new_time;
- dgnc_poll_counter++;
-
- /*
- * Do not start the board state machine until
- * driver tells us its up and running, and has
- * everything it needs.
- */
- if (dgnc_driver_state != DRIVER_READY)
- goto schedule_poller;
-
/* Go thru each board, kicking off a tasklet for each if needed */
for (i = 0; i < dgnc_NumBoards; i++) {
brd = dgnc_Board[i];
- DGNC_LOCK(brd->bd_lock, lock_flags);
+ spin_lock_irqsave(&brd->bd_lock, flags);
/* If board is in a failed state, don't bother scheduling a tasklet */
if (brd->state == BOARD_FAILED) {
- DGNC_UNLOCK(brd->bd_lock, lock_flags);
+ spin_unlock_irqrestore(&brd->bd_lock, flags);
continue;
}
/* Schedule a poll helper task */
tasklet_schedule(&brd->helper_tasklet);
- DGNC_UNLOCK(brd->bd_lock, lock_flags);
+ spin_unlock_irqrestore(&brd->bd_lock, flags);
}
-schedule_poller:
-
/*
* Schedule ourself back at the nominal wakeup interval.
*/
- DGNC_LOCK(dgnc_poll_lock, lock_flags);
+ spin_lock_irqsave(&dgnc_poll_lock, flags);
dgnc_poll_time += dgnc_jiffies_from_ms(dgnc_poll_tick);
new_time = dgnc_poll_time - jiffies;
dgnc_poll_timer.function = dgnc_poll_handler;
dgnc_poll_timer.data = 0;
dgnc_poll_timer.expires = dgnc_poll_time;
- DGNC_UNLOCK(dgnc_poll_lock, lock_flags);
+ spin_unlock_irqrestore(&dgnc_poll_lock, flags);
if (!dgnc_poll_stop)
add_timer(&dgnc_poll_timer);
dgnc_rawreadok = rawreadok;
dgnc_trcbuf_size = trcbuf_size;
dgnc_debug = debug;
+ dgnc_NumBoards = 0;
for (i = 0; i < MAXBOARDS; i++)
dgnc_Board[i] = NULL;
init_timer(&dgnc_poll_timer);
}
-
-/************************************************************************
- *
- * Utility functions
- *
- ************************************************************************/
-
-/*
- * dgnc_ms_sleep()
- *
- * Put the driver to sleep for x ms's
- *
- * Returns 0 if timed out, !0 (showing signal) if interrupted by a signal.
- */
-int dgnc_ms_sleep(ulong ms)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout((ms * HZ) / 1000);
- return signal_pending(current);
-}
-
-
-
-/*
- * dgnc_ioctl_name() : Returns a text version of each ioctl value.
- */
-char *dgnc_ioctl_name(int cmd)
-{
- switch (cmd) {
-
- case TCGETA: return "TCGETA";
- case TCGETS: return "TCGETS";
- case TCSETA: return "TCSETA";
- case TCSETS: return "TCSETS";
- case TCSETAW: return "TCSETAW";
- case TCSETSW: return "TCSETSW";
- case TCSETAF: return "TCSETAF";
- case TCSETSF: return "TCSETSF";
- case TCSBRK: return "TCSBRK";
- case TCXONC: return "TCXONC";
- case TCFLSH: return "TCFLSH";
- case TIOCGSID: return "TIOCGSID";
-
- case TIOCGETD: return "TIOCGETD";
- case TIOCSETD: return "TIOCSETD";
- case TIOCGWINSZ: return "TIOCGWINSZ";
- case TIOCSWINSZ: return "TIOCSWINSZ";
-
- case TIOCMGET: return "TIOCMGET";
- case TIOCMSET: return "TIOCMSET";
- case TIOCMBIS: return "TIOCMBIS";
- case TIOCMBIC: return "TIOCMBIC";
-
- /* from digi.h */
- case DIGI_SETA: return "DIGI_SETA";
- case DIGI_SETAW: return "DIGI_SETAW";
- case DIGI_SETAF: return "DIGI_SETAF";
- case DIGI_SETFLOW: return "DIGI_SETFLOW";
- case DIGI_SETAFLOW: return "DIGI_SETAFLOW";
- case DIGI_GETFLOW: return "DIGI_GETFLOW";
- case DIGI_GETAFLOW: return "DIGI_GETAFLOW";
- case DIGI_GETA: return "DIGI_GETA";
- case DIGI_GEDELAY: return "DIGI_GEDELAY";
- case DIGI_SEDELAY: return "DIGI_SEDELAY";
- case DIGI_GETCUSTOMBAUD: return "DIGI_GETCUSTOMBAUD";
- case DIGI_SETCUSTOMBAUD: return "DIGI_SETCUSTOMBAUD";
- case TIOCMODG: return "TIOCMODG";
- case TIOCMODS: return "TIOCMODS";
- case TIOCSDTR: return "TIOCSDTR";
- case TIOCCDTR: return "TIOCCDTR";
-
- default: return "unknown";
- }
-}
#include <linux/nmi.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+ #include <linux/uaccess.h>
+ #include <linux/pm_runtime.h>
#ifdef CONFIG_SPARC
#include <linux/sunserialcore.h>
#endif
}
EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
+ static void serial8250_rpm_get(struct uart_8250_port *p)
+ {
+ if (!(p->capabilities & UART_CAP_RPM))
+ return;
+ pm_runtime_get_sync(p->port.dev);
+ }
+
+ static void serial8250_rpm_put(struct uart_8250_port *p)
+ {
+ if (!(p->capabilities & UART_CAP_RPM))
+ return;
+ pm_runtime_mark_last_busy(p->port.dev);
+ pm_runtime_put_autosuspend(p->port.dev);
+ }
+
+ /*
+ * This two wrapper ensure, that enable_runtime_pm_tx() can be called more than
+ * once and disable_runtime_pm_tx() will still disable RPM because the fifo is
+ * empty and the HW can idle again.
+ */
+ static void serial8250_rpm_get_tx(struct uart_8250_port *p)
+ {
+ unsigned char rpm_active;
+
+ if (!(p->capabilities & UART_CAP_RPM))
+ return;
+
+ rpm_active = xchg(&p->rpm_tx_active, 1);
+ if (rpm_active)
+ return;
+ pm_runtime_get_sync(p->port.dev);
+ }
+
+ static void serial8250_rpm_put_tx(struct uart_8250_port *p)
+ {
+ unsigned char rpm_active;
+
+ if (!(p->capabilities & UART_CAP_RPM))
+ return;
+
+ rpm_active = xchg(&p->rpm_tx_active, 0);
+ if (!rpm_active)
+ return;
+ pm_runtime_mark_last_busy(p->port.dev);
+ pm_runtime_put_autosuspend(p->port.dev);
+ }
+
/*
* IER sleep support. UARTs which have EFRs need the "extended
* capability" bit enabled. Note that on XR16C850s, we need to
* offset but the UART channel may only write to the corresponding
* bit.
*/
+ serial8250_rpm_get(p);
if ((p->port.type == PORT_XR17V35X) ||
(p->port.type == PORT_XR17D15X)) {
serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0);
- return;
+ goto out;
}
if (p->capabilities & UART_CAP_SLEEP) {
serial_out(p, UART_LCR, 0);
}
}
+ out:
+ serial8250_rpm_put(p);
}
#ifdef CONFIG_SERIAL_8250_RSA
if (p->ier & UART_IER_THRI) {
p->ier &= ~UART_IER_THRI;
serial_out(p, UART_IER, p->ier);
+ serial8250_rpm_put_tx(p);
}
}
{
struct uart_8250_port *up = up_to_u8250p(port);
+ serial8250_rpm_get(up);
__stop_tx(up);
/*
up->acr |= UART_ACR_TXDIS;
serial_icr_write(up, UART_ACR, up->acr);
}
+ serial8250_rpm_put(up);
}
static void serial8250_start_tx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
+ serial8250_rpm_get_tx(up);
if (up->dma && !serial8250_tx_dma(up)) {
return;
} else if (!(up->ier & UART_IER_THRI)) {
}
}
+ static void serial8250_throttle(struct uart_port *port)
+ {
+ port->throttle(port);
+ }
+
+ static void serial8250_unthrottle(struct uart_port *port)
+ {
+ port->unthrottle(port);
+ }
+
static void serial8250_stop_rx(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
- up->ier &= ~UART_IER_RLSI;
+ serial8250_rpm_get(up);
+
+ up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
up->port.read_status_mask &= ~UART_LSR_DR;
serial_port_out(port, UART_IER, up->ier);
+
+ serial8250_rpm_put(up);
}
static void serial8250_enable_ms(struct uart_port *port)
return;
up->ier |= UART_IER_MSI;
+
+ serial8250_rpm_get(up);
serial_port_out(port, UART_IER, up->ier);
+ serial8250_rpm_put(up);
}
/*
DEBUG_INTR("THRE...");
- if (uart_circ_empty(xmit))
+ /*
+ * With RPM enabled, we have to wait once the FIFO is empty before the
+ * HW can go idle. So we get here once again with empty FIFO and disable
+ * the interrupt and RPM in __stop_tx()
+ */
+ if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
__stop_tx(up);
}
EXPORT_SYMBOL_GPL(serial8250_tx_chars);
+ /* Caller holds uart port lock */
unsigned int serial8250_modem_status(struct uart_8250_port *up)
{
struct uart_port *port = &up->port;
static int serial8250_default_handle_irq(struct uart_port *port)
{
- unsigned int iir = serial_port_in(port, UART_IIR);
+ struct uart_8250_port *up = up_to_u8250p(port);
+ unsigned int iir;
+ int ret;
+
+ serial8250_rpm_get(up);
- return serial8250_handle_irq(port, iir);
+ iir = serial_port_in(port, UART_IIR);
+ ret = serial8250_handle_irq(port, iir);
+
+ serial8250_rpm_put(up);
+ return ret;
}
/*
unsigned long flags;
unsigned int lsr;
+ serial8250_rpm_get(up);
+
spin_lock_irqsave(&port->lock, flags);
lsr = serial_port_in(port, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
spin_unlock_irqrestore(&port->lock, flags);
+ serial8250_rpm_put(up);
+
return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;
}
unsigned int status;
unsigned int ret;
+ serial8250_rpm_get(up);
status = serial8250_modem_status(up);
+ serial8250_rpm_put(up);
ret = 0;
if (status & UART_MSR_DCD)
struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
+ serial8250_rpm_get(up);
spin_lock_irqsave(&port->lock, flags);
if (break_state == -1)
up->lcr |= UART_LCR_SBC;
up->lcr &= ~UART_LCR_SBC;
serial_port_out(port, UART_LCR, up->lcr);
spin_unlock_irqrestore(&port->lock, flags);
+ serial8250_rpm_put(up);
}
/*
static int serial8250_get_poll_char(struct uart_port *port)
{
- unsigned char lsr = serial_port_in(port, UART_LSR);
+ struct uart_8250_port *up = up_to_u8250p(port);
+ unsigned char lsr;
+ int status;
+
+ serial8250_rpm_get(up);
+
+ lsr = serial_port_in(port, UART_LSR);
- if (!(lsr & UART_LSR_DR))
- return NO_POLL_CHAR;
+ if (!(lsr & UART_LSR_DR)) {
+ status = NO_POLL_CHAR;
+ goto out;
+ }
- return serial_port_in(port, UART_RX);
+ status = serial_port_in(port, UART_RX);
+ out:
+ serial8250_rpm_put(up);
+ return status;
}
unsigned int ier;
struct uart_8250_port *up = up_to_u8250p(port);
+ serial8250_rpm_get(up);
/*
* First save the IER then disable the interrupts
*/
*/
wait_for_xmitr(up, BOTH_EMPTY);
serial_port_out(port, UART_IER, ier);
+ serial8250_rpm_put(up);
}
#endif /* CONFIG_CONSOLE_POLL */
- static int serial8250_startup(struct uart_port *port)
+ int serial8250_do_startup(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
if (port->iotype != up->cur_iotype)
set_io_from_upio(port);
+ serial8250_rpm_get(up);
if (port->type == PORT_16C950) {
/* Wake up and initialize UART */
up->acr = 0;
*/
enable_rsa(up);
#endif
-
/*
* Clear the FIFO buffers and disable them.
* (they will be reenabled in set_termios())
/*
* Clear the interrupt registers.
*/
- serial_port_in(port, UART_LSR);
- serial_port_in(port, UART_RX);
+ if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
+ serial_port_in(port, UART_RX);
serial_port_in(port, UART_IIR);
serial_port_in(port, UART_MSR);
(serial_port_in(port, UART_LSR) == 0xff)) {
printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n",
serial_index(port));
- return -ENODEV;
+ retval = -ENODEV;
+ goto out;
}
/*
} else {
retval = serial_link_irq_chain(up);
if (retval)
- return retval;
+ goto out;
}
/*
* saved flags to avoid getting false values from polling
* routines or the previous session.
*/
- serial_port_in(port, UART_LSR);
- serial_port_in(port, UART_RX);
+ if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
+ serial_port_in(port, UART_RX);
serial_port_in(port, UART_IIR);
serial_port_in(port, UART_MSR);
up->lsr_saved_flags = 0;
outb_p(0x80, icp);
inb_p(icp);
}
+ retval = 0;
+ out:
+ serial8250_rpm_put(up);
+ return retval;
+ }
+ EXPORT_SYMBOL_GPL(serial8250_do_startup);
- return 0;
+ static int serial8250_startup(struct uart_port *port)
+ {
+ if (port->startup)
+ return port->startup(port);
+ return serial8250_do_startup(port);
}
- static void serial8250_shutdown(struct uart_port *port)
+ void serial8250_do_shutdown(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned long flags;
+ serial8250_rpm_get(up);
/*
* Disable interrupts from this port
*/
* Read data port to reset things, and then unlink from
* the IRQ chain.
*/
- serial_port_in(port, UART_RX);
+ if (serial_port_in(port, UART_LSR) & UART_LSR_DR)
+ serial_port_in(port, UART_RX);
+ serial8250_rpm_put(up);
del_timer_sync(&up->timer);
up->timer.function = serial8250_timeout;
if (port->irq)
serial_unlink_irq_chain(up);
}
+ EXPORT_SYMBOL_GPL(serial8250_do_shutdown);
+
+ static void serial8250_shutdown(struct uart_port *port)
+ {
+ if (port->shutdown)
+ port->shutdown(port);
+ else
+ serial8250_do_shutdown(port);
+ }
static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
{
* the trigger, or the MCR RTS bit is cleared. In the case where
* the remote UART is not using CTS auto flow control, we must
* have sufficient FIFO entries for the latency of the remote
- * UART to respond. IOW, at least 32 bytes of FIFO. Also enable
- * AFE if hw flow control is supported
+ * UART to respond. IOW, at least 32 bytes of FIFO.
*/
- if ((up->capabilities & UART_CAP_AFE && (port->fifosize >= 32)) ||
- (port->flags & UPF_HARD_FLOW)) {
+ if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) {
up->mcr &= ~UART_MCR_AFE;
if (termios->c_cflag & CRTSCTS)
up->mcr |= UART_MCR_AFE;
* Ok, we're now changing the port state. Do it with
* interrupts disabled.
*/
+ serial8250_rpm_get(up);
spin_lock_irqsave(&port->lock, flags);
/*
}
serial8250_set_mctrl(port, port->mctrl);
spin_unlock_irqrestore(&port->lock, flags);
+ serial8250_rpm_put(up);
+
/* Don't rewrite B0 */
if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, baud, baud);
return 0;
}
+ static int serial8250_ioctl(struct uart_port *port, unsigned int cmd,
+ unsigned long arg)
+ {
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
+ int ret;
+ struct serial_rs485 rs485_config;
+
+ if (!up->rs485_config)
+ return -ENOIOCTLCMD;
+
+ switch (cmd) {
+ case TIOCSRS485:
+ if (copy_from_user(&rs485_config, (void __user *)arg,
+ sizeof(rs485_config)))
+ return -EFAULT;
+
+ ret = up->rs485_config(up, &rs485_config);
+ if (ret)
+ return ret;
+
+ memcpy(&up->rs485, &rs485_config, sizeof(rs485_config));
+
+ return 0;
+ case TIOCGRS485:
+ if (copy_to_user((void __user *)arg, &up->rs485,
+ sizeof(up->rs485)))
+ return -EFAULT;
+ return 0;
+ default:
+ break;
+ }
+
+ return -ENOIOCTLCMD;
+ }
+
static const char *
serial8250_type(struct uart_port *port)
{
.get_mctrl = serial8250_get_mctrl,
.stop_tx = serial8250_stop_tx,
.start_tx = serial8250_start_tx,
+ .throttle = serial8250_throttle,
+ .unthrottle = serial8250_unthrottle,
.stop_rx = serial8250_stop_rx,
.enable_ms = serial8250_enable_ms,
.break_ctl = serial8250_break_ctl,
.request_port = serial8250_request_port,
.config_port = serial8250_config_port,
.verify_port = serial8250_verify_port,
+ .ioctl = serial8250_ioctl,
#ifdef CONFIG_CONSOLE_POLL
.poll_get_char = serial8250_get_poll_char,
.poll_put_char = serial8250_put_poll_char,
static struct uart_8250_port serial8250_ports[UART_NR];
+ /**
+ * serial8250_get_port - retrieve struct uart_8250_port
+ * @line: serial line number
+ *
+ * This function retrieves struct uart_8250_port for the specific line.
+ * This struct *must* *not* be used to perform a 8250 or serial core operation
+ * which is not accessible otherwise. Its only purpose is to make the struct
+ * accessible to the runtime-pm callbacks for context suspend/restore.
+ * The lock assumption made here is none because runtime-pm suspend/resume
+ * callbacks should not be invoked if there is any operation performed on the
+ * port.
+ */
+ struct uart_8250_port *serial8250_get_port(int line)
+ {
+ return &serial8250_ports[line];
+ }
+ EXPORT_SYMBOL_GPL(serial8250_get_port);
+
static void (*serial8250_isa_config)(int port, struct uart_port *up,
unsigned short *capabilities);
touch_nmi_watchdog();
+ serial8250_rpm_get(up);
+
if (port->sysrq || oops_in_progress)
locked = spin_trylock_irqsave(&port->lock, flags);
else
if (locked)
spin_unlock_irqrestore(&port->lock, flags);
+ serial8250_rpm_put(up);
}
static int __init serial8250_console_setup(struct console *co, char *options)
if (uart_match_port(&serial8250_ports[i].port, port))
return &serial8250_ports[i];
+ /* try line number first if still available */
+ i = port->line;
+ if (i < nr_uarts && serial8250_ports[i].port.type == PORT_UNKNOWN &&
+ serial8250_ports[i].port.iobase == 0)
+ return &serial8250_ports[i];
/*
* We didn't find a matching entry, so look for the first
* free entry. We look for one which hasn't been previously
uart->port.fifosize = up->port.fifosize;
uart->tx_loadsz = up->tx_loadsz;
uart->capabilities = up->capabilities;
+ uart->rs485_config = up->rs485_config;
+ uart->rs485 = up->rs485;
+ uart->port.throttle = up->port.throttle;
+ uart->port.unthrottle = up->port.unthrottle;
/* Take tx_loadsz from fifosize if it wasn't set separately */
if (uart->port.fifosize && !uart->tx_loadsz)
/* Possibly override set_termios call */
if (up->port.set_termios)
uart->port.set_termios = up->port.set_termios;
+ if (up->port.startup)
+ uart->port.startup = up->port.startup;
+ if (up->port.shutdown)
+ uart->port.shutdown = up->port.shutdown;
if (up->port.pm)
uart->port.pm = up->port.pm;
if (up->port.handle_break)
#ifdef CONFIG_SERIAL_8250_RSA
__module_param_call(MODULE_PARAM_PREFIX, probe_rsa,
¶m_array_ops, .arr = &__param_arr_probe_rsa,
- 0444, -1);
+ 0444, -1, 0);
#endif
}
#else