aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/dgnc/dgnc_driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/dgnc/dgnc_driver.c')
-rw-r--r--drivers/staging/dgnc/dgnc_driver.c226
1 files changed, 109 insertions, 117 deletions
diff --git a/drivers/staging/dgnc/dgnc_driver.c b/drivers/staging/dgnc/dgnc_driver.c
index af2e835efa1b..fd372d3afa46 100644
--- a/drivers/staging/dgnc/dgnc_driver.c
+++ b/drivers/staging/dgnc/dgnc_driver.c
@@ -37,13 +37,14 @@ MODULE_SUPPORTED_DEVICE("dgnc");
*
*/
static int dgnc_start(void);
-static int dgnc_finalize_board_init(struct dgnc_board *brd);
-static int dgnc_found_board(struct pci_dev *pdev, int id);
+static int dgnc_request_irq(struct dgnc_board *brd);
+static void dgnc_free_irq(struct dgnc_board *brd);
+static struct dgnc_board *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_one(struct pci_dev *pdev,
const struct pci_device_id *ent);
-static void dgnc_do_remap(struct dgnc_board *brd);
+static int dgnc_do_remap(struct dgnc_board *brd);
/*
* File operations permitted on Control/Management major.
@@ -146,7 +147,7 @@ static void cleanup(bool sysfiles)
for (i = 0; i < dgnc_num_boards; ++i) {
dgnc_remove_ports_sysfiles(dgnc_board[i]);
- dgnc_tty_uninit(dgnc_board[i]);
+ dgnc_cleanup_tty(dgnc_board[i]);
dgnc_cleanup_board(dgnc_board[i]);
}
@@ -158,7 +159,7 @@ static void cleanup(bool sysfiles)
*
* Module unload. This is where it all ends.
*/
-static void dgnc_cleanup_module(void)
+static void __exit dgnc_cleanup_module(void)
{
cleanup(true);
pci_unregister_driver(&dgnc_driver);
@@ -274,6 +275,7 @@ failed_class:
static int dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int rc;
+ struct dgnc_board *brd;
/* wake up and enable device */
rc = pci_enable_device(pdev);
@@ -281,9 +283,48 @@ static int dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return -EIO;
- rc = dgnc_found_board(pdev, ent->driver_data);
- if (rc == 0)
- dgnc_num_boards++;
+ brd = dgnc_found_board(pdev, ent->driver_data);
+ if (IS_ERR(brd))
+ return PTR_ERR(brd);
+
+ /*
+ * Do tty device initialization.
+ */
+
+ rc = dgnc_tty_register(brd);
+ if (rc < 0) {
+ pr_err(DRVSTR ": Can't register tty devices (%d)\n", rc);
+ goto failed;
+ }
+
+ rc = dgnc_request_irq(brd);
+ if (rc < 0) {
+ pr_err(DRVSTR ": Can't finalize board init (%d)\n", rc);
+ goto unregister_tty;
+ }
+
+ rc = dgnc_tty_init(brd);
+ if (rc < 0) {
+ pr_err(DRVSTR ": Can't init tty devices (%d)\n", rc);
+ goto free_irq;
+ }
+
+ brd->state = BOARD_READY;
+ brd->dpastatus = BD_RUNNING;
+
+ dgnc_create_ports_sysfiles(brd);
+
+ dgnc_board[dgnc_num_boards++] = brd;
+
+ return 0;
+
+free_irq:
+ dgnc_free_irq(brd);
+unregister_tty:
+ dgnc_tty_unregister(brd);
+
+failed:
+ kfree(brd);
return rc;
}
@@ -324,17 +365,6 @@ static void dgnc_cleanup_board(struct dgnc_board *brd)
brd->re_map_membase = NULL;
}
- if (brd->msgbuf_head) {
- unsigned long flags;
-
- spin_lock_irqsave(&dgnc_global_lock, flags);
- brd->msgbuf = NULL;
- dev_dbg(&brd->pdev->dev, "%s\n", brd->msgbuf_head);
- kfree(brd->msgbuf_head);
- brd->msgbuf_head = NULL;
- spin_unlock_irqrestore(&dgnc_global_lock, flags);
- }
-
/* Free all allocated channels structs */
for (i = 0; i < MAXPORTS ; i++) {
if (brd->channels[i]) {
@@ -356,29 +386,17 @@ static void dgnc_cleanup_board(struct dgnc_board *brd)
*
* A board has been found, init it.
*/
-static int dgnc_found_board(struct pci_dev *pdev, int id)
+static struct dgnc_board *dgnc_found_board(struct pci_dev *pdev, int id)
{
struct dgnc_board *brd;
unsigned int pci_irq;
int i = 0;
int rc = 0;
- unsigned long flags;
/* get the board structure and prep it */
- dgnc_board[dgnc_num_boards] = kzalloc(sizeof(*brd), GFP_KERNEL);
- brd = dgnc_board[dgnc_num_boards];
-
+ brd = kzalloc(sizeof(*brd), GFP_KERNEL);
if (!brd)
- return -ENOMEM;
-
- /* make a temporary message buffer for the boot messages */
- brd->msgbuf_head = kcalloc(8192, sizeof(u8), GFP_KERNEL);
- brd->msgbuf = brd->msgbuf_head;
-
- if (!brd->msgbuf) {
- kfree(brd);
- return -ENOMEM;
- }
+ return ERR_PTR(-ENOMEM);
/* store the info for the board we've found */
brd->magic = DGNC_BOARD_MAGIC;
@@ -400,9 +418,6 @@ static int dgnc_found_board(struct pci_dev *pdev, int id)
brd->state = BOARD_FOUND;
- for (i = 0; i < MAXPORTS; i++)
- brd->channels[i] = NULL;
-
/* store which card & revision we have */
pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &brd->subvendor);
pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &brd->subdevice);
@@ -435,7 +450,8 @@ static int dgnc_found_board(struct pci_dev *pdev, int id)
if (!brd->membase) {
dev_err(&brd->pdev->dev,
"Card has no PCI IO resources, failing.\n");
- return -ENODEV;
+ rc = -ENODEV;
+ goto failed;
}
brd->membase_end = pci_resource_end(pdev, 4);
@@ -455,7 +471,10 @@ static int dgnc_found_board(struct pci_dev *pdev, int id)
brd->bd_uart_offset = 0x8;
brd->bd_dividend = 921600;
- dgnc_do_remap(brd);
+ rc = dgnc_do_remap(brd);
+
+ if (rc < 0)
+ goto failed;
/* Get and store the board VPD, if it exists */
brd->bd_ops->vpd(brd);
@@ -507,81 +526,45 @@ static int dgnc_found_board(struct pci_dev *pdev, int id)
brd->bd_uart_offset = 0x200;
brd->bd_dividend = 921600;
- dgnc_do_remap(brd);
+ rc = dgnc_do_remap(brd);
- if (brd->re_map_membase) {
- /* Read and store the dvid after remapping */
- brd->dvid = readb(brd->re_map_membase + 0x8D);
+ if (rc < 0)
+ goto failed;
+
+ /* Read and store the dvid after remapping */
+ brd->dvid = readb(brd->re_map_membase + 0x8D);
+
+ /* Get and store the board VPD, if it exists */
+ brd->bd_ops->vpd(brd);
- /* Get and store the board VPD, if it exists */
- brd->bd_ops->vpd(brd);
- }
break;
default:
dev_err(&brd->pdev->dev,
"Didn't find any compatible Neo/Classic PCI boards.\n");
- return -ENXIO;
- }
-
- /*
- * Do tty device initialization.
- */
-
- rc = dgnc_tty_register(brd);
- if (rc < 0) {
- pr_err(DRVSTR ": Can't register tty devices (%d)\n", rc);
- goto failed;
- }
-
- rc = dgnc_finalize_board_init(brd);
- if (rc < 0) {
- pr_err(DRVSTR ": Can't finalize board init (%d)\n", rc);
- goto failed;
- }
-
- rc = dgnc_tty_init(brd);
- if (rc < 0) {
- pr_err(DRVSTR ": Can't init tty devices (%d)\n", rc);
+ rc = -ENXIO;
goto failed;
}
- brd->state = BOARD_READY;
- brd->dpastatus = BD_RUNNING;
-
- dgnc_create_ports_sysfiles(brd);
-
/* init our poll helper tasklet */
tasklet_init(&brd->helper_tasklet,
brd->bd_ops->tasklet,
(unsigned long)brd);
- spin_lock_irqsave(&dgnc_global_lock, flags);
- brd->msgbuf = NULL;
- dev_dbg(&brd->pdev->dev, "%s\n", brd->msgbuf_head);
- kfree(brd->msgbuf_head);
- brd->msgbuf_head = NULL;
- spin_unlock_irqrestore(&dgnc_global_lock, flags);
-
wake_up_interruptible(&brd->state_wait);
- return 0;
+ return brd;
failed:
- dgnc_tty_uninit(brd);
- brd->state = BOARD_FAILED;
- brd->dpastatus = BD_NOFEP;
+ kfree(brd);
- return -ENXIO;
+ return ERR_PTR(rc);
}
-static int dgnc_finalize_board_init(struct dgnc_board *brd)
+static int dgnc_request_irq(struct dgnc_board *brd)
{
int rc = 0;
- if (!brd || brd->magic != DGNC_BOARD_MAGIC)
- return -ENODEV;
-
if (brd->irq) {
rc = request_irq(brd->irq, brd->bd_ops->intr,
IRQF_SHARED, "DGNC", brd);
@@ -597,42 +580,51 @@ static int dgnc_finalize_board_init(struct dgnc_board *brd)
return rc;
}
+static void dgnc_free_irq(struct dgnc_board *brd)
+{
+ if (brd->irq)
+ free_irq(brd->irq, brd);
+}
+
/*
* Remap PCI memory.
*/
-static void dgnc_do_remap(struct dgnc_board *brd)
+static int dgnc_do_remap(struct dgnc_board *brd)
{
- if (!brd || brd->magic != DGNC_BOARD_MAGIC)
- return;
+ int rc = 0;
brd->re_map_membase = ioremap(brd->membase, 0x1000);
+ if (!brd->re_map_membase)
+ rc = -ENOMEM;
+
+ return rc;
}
-/*****************************************************************************
-*
-* Function:
-*
-* dgnc_poll_handler
-*
-* Author:
-*
-* Scott H Kilau
-*
-* Parameters:
-*
-* dummy -- ignored
-*
-* Return Values:
-*
-* none
-*
-* Description:
-*
-* As each timer expires, it determines (a) whether the "transmit"
-* waiter needs to be woken up, and (b) whether the poller needs to
-* be rescheduled.
-*
-******************************************************************************/
+/*
+ *
+ * Function:
+ *
+ * dgnc_poll_handler
+ *
+ * Author:
+ *
+ * Scott H Kilau
+ *
+ * Parameters:
+ *
+ * dummy -- ignored
+ *
+ * Return Values:
+ *
+ * none
+ *
+ * Description:
+ *
+ * As each timer expires, it determines (a) whether the "transmit"
+ * waiter needs to be woken up, and (b) whether the poller needs to
+ * be rescheduled.
+ *
+ */
static void dgnc_poll_handler(ulong dummy)
{