[PATCH RFC 04/17] staging: dgap: Add in kernel firmware loading support
Mark Hounschell
markh at compro.net
Wed Feb 12 17:49:46 UTC 2014
Add in kernel firmware loading support
Signed-off-by: Mark Hounschell <markh at compro.net>
Cc: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
diff -urN linux-3.13.1-orig/drivers/staging/dgap/dgap_driver.c linux-3.13.1-new/drivers/staging/dgap/dgap_driver.c
--- linux-3.13.1-orig/drivers/staging/dgap/dgap_driver.c 2014-02-03 13:34:50.489287314 -0500
+++ linux-3.13.1-new/drivers/staging/dgap/dgap_driver.c 2014-02-03 14:12:20.059076489 -0500
@@ -18,6 +18,33 @@
*
*/
+/*
+ * In the original out of kernel Digi dgap driver, firmware
+ * loading was done via user land to driver handshaking.
+ *
+ * For cards that support a concentrator (port expander),
+ * I believe the concentrator its self told the card which
+ * concentrator is actually attached and then that info
+ * was used to tell user land which concentrator firmware
+ * image was to be downloaded. I think even the BIOS or
+ * FEP images required would change with the connection
+ * of a particular concentrator.
+ *
+ * Since I have no access to any of these cards or
+ * concentrators, I cannot put the correct concentrator
+ * firmware file names into the firmware_info structure
+ * as is now done for the BIOS and FEP images.
+ *
+ * I think, but am not certain, that the cards supporting
+ * concentrators will function without them. So support
+ * of these cards has been left in this driver.
+ *
+ * In order to fully support those cards, they would
+ * either have to be acquired for dissection or maybe
+ * Digi International could provide some assistance.
+ */
+#undef DIGI_CONCENTRATORS_SUPPORTED
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -26,6 +53,7 @@
#include <asm/uaccess.h> /* For copy_from_user/copy_to_user */
#include <linux/sched.h>
#include <linux/sched.h>
+#include <linux/firmware.h>
#include <linux/version.h>
#include <linux/tty.h>
@@ -72,10 +100,25 @@
static void dgap_mbuf(struct board_t *brd, const char *fmt, ...);
static int dgap_do_remap(struct board_t *brd);
static irqreturn_t dgap_intr(int irq, void *voidbrd);
-
+static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds);
+static int dgap_event(struct board_t *bd);
+static int dgap_firmware_load(struct pci_dev *pdev, int card_type);
+static void dgap_do_bios_load(struct board_t *brd, uchar *ubios, int len);
+static void dgap_do_fep_load(struct board_t *brd, uchar *ufep, int len);
+static void dgap_sysfs_create(struct board_t *brd);
+static void dgap_get_vpd(struct board_t *brd);
+static void dgap_do_reset_board(struct board_t *brd);
+static void dgap_do_wait_for_bios(struct board_t *brd);
+static void dgap_do_wait_for_fep(struct board_t *brd);
+static int dgap_after_config_loaded(int brd);
+static int dgap_finalize_board_init(struct board_t *brd);
static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds);
static int dgap_event(struct board_t *bd);
+#ifdef DIGI_CONCENTRATORS_SUPPORTED
+static void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len);
+#endif
+
/* Driver load/unload functions */
int dgap_init_module(void);
void dgap_cleanup_module(void);
@@ -110,9 +153,7 @@
*/
static int dgap_Major_Control_Registered = FALSE;
static uint dgap_driver_start = FALSE;
-
static uint dgap_count = 500;
-
static struct class * dgap_class;
/*
@@ -123,6 +164,24 @@
static uint dgap_poll_stop; /* Used to tell poller to stop */
static struct timer_list dgap_poll_timer;
+/*
+ SUPPORTED PRODUCTS
+
+ Card Model Number of Ports Interface
+ ----------------------------------------------------------------
+ Acceleport Xem 4 - 64 (EIA232 & EIA422)
+ Acceleport Xr 4 & 8 (EIA232)
+ Acceleport Xr 920 4 & 8 (EIA232)
+ Acceleport C/X 8 - 128 (EIA232)
+ Acceleport EPC/X 8 - 224 (EIA232)
+ Acceleport Xr/422 4 & 8 (EIA422)
+ Acceleport 2r/920 2 (EIA232)
+ Acceleport 4r/920 4 (EIA232)
+ Acceleport 8r/920 8 (EIA232)
+
+ IBM 8-Port Asynchronous PCI Adapter (EIA232)
+ IBM 128-Port Asynchronous PCI Adapter (EIA232 & EIA422)
+*/
static struct pci_device_id dgap_pci_tbl[] = {
{ DIGI_VID, PCI_DEVICE_XEM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
@@ -144,7 +203,6 @@
};
MODULE_DEVICE_TABLE(pci, dgap_pci_tbl);
-
/*
* A generic list of Product names, PCI Vendor ID, and PCI Device ID.
*/
@@ -182,6 +240,36 @@
.remove = dgap_remove_one,
};
+struct firmware_info {
+ uchar *conf_name; /* dgap.conf */
+ uchar *bios_name; /* BIOS filename */
+ uchar *fep_name; /* FEP filename */
+ uchar *con_name; /* Concentrator filename FIXME*/
+ int num; /* sequence number */
+};
+
+/*
+ * Firmware - BIOS, FEP, and CONC filenames
+ */
+#define _CONFIG_ "dgap/dgap.conf"
+static struct firmware_info fw_info[] = {
+ { _CONFIG_, "dgap/sxbios.bin", "dgap/sxfep.bin", 0, 0 }, /* XEM_DID */
+ { _CONFIG_, "dgap/cxpbios.bin", "dgap/cxpfep.bin", 0, 1 }, /* CX_DID */
+ { _CONFIG_, "dgap/cxpbios.bin", "dgap/cxpfep.bin", 0, 2 }, /* CX_IBM_DID */
+ { _CONFIG_, "dgap/pcibios.bin", "dgap/pcifep.bin", 0, 3 }, /* EPCJ_DID */
+ { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 4 }, /* 920_2_DID */
+ { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 5 }, /* 920_4_DID */
+ { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 6 }, /* 920_8_DID */
+ { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 7 }, /* XR_DID */
+ { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 8 }, /* XRJ_DID */
+ { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 9 }, /* XR_422_DID */
+ { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 10 }, /* XR_IBM_DID */
+ { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 11 }, /* XR_SAIP_DID */
+ { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 12 }, /* XR_BULL_DID */
+ { _CONFIG_, "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 13 }, /* 920_8_HP_DID */
+ { _CONFIG_, "dgap/sxbios.bin", "dgap/sxfep.bin", 0, 14 }, /* XEM_HP_DID */
+ {0,}
+};
char *dgap_state_text[] = {
"Board Failed",
@@ -214,8 +302,6 @@
"Driver Ready."
};
-
-
/************************************************************************
*
* Driver load/unload functions
@@ -233,14 +319,15 @@
APR(("%s, Digi International Part Number %s\n", DG_NAME, DG_PART));
+ dgap_driver_state = DRIVER_NEED_CONFIG_LOAD;
+
/*
* Initialize global stuff
*/
rc = dgap_start();
- if (rc < 0) {
+ if (rc < 0)
return(rc);
- }
/*
* Find and configure all the cards
@@ -258,16 +345,15 @@
printk("WARNING: dgap driver load failed. No DGAP boards found.\n");
dgap_cleanup_module();
- }
- else {
+ } else {
dgap_create_driver_sysfiles(&dgap_driver);
+ dgap_driver_state = DRIVER_READY;
}
DPR_INIT(("Finished init_module. Returning %d\n", rc));
return (rc);
}
-
/*
* Start of driver.
*/
@@ -306,9 +392,6 @@
device_create(dgap_class, NULL,
MKDEV(DIGI_DGAP_MAJOR, 0),
NULL, "dgap_mgmt");
- device_create(dgap_class, NULL,
- MKDEV(DIGI_DGAP_MAJOR, 1),
- NULL, "dgap_downld");
dgap_Major_Control_Registered = TRUE;
}
@@ -339,7 +422,6 @@
return (rc);
}
-
/*
* Register pci driver, and return how many boards we have.
*/
@@ -348,7 +430,6 @@
return pci_register_driver(&dgap_driver);
}
-
/* returns count (>= 0), or negative on error */
static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -364,24 +445,22 @@
if (rc == 0) {
dgap_NumBoards++;
DPR_INIT(("Incrementing numboards to %d\n", dgap_NumBoards));
+ rc = dgap_firmware_load(pdev, ent->driver_data);
}
}
return rc;
}
-
static int dgap_probe1(struct pci_dev *pdev, int card_type)
{
return dgap_found_board(pdev, card_type);
}
-
static void dgap_remove_one(struct pci_dev *dev)
{
/* Do Nothing */
}
-
/*
* dgap_cleanup_module()
*
@@ -397,7 +476,7 @@
DGAP_UNLOCK(dgap_poll_lock, lock_flags);
/* Turn off poller right away. */
- del_timer_sync( &dgap_poll_timer);
+ del_timer_sync(&dgap_poll_timer);
dgap_remove_driver_sysfiles(&dgap_driver);
@@ -427,7 +506,6 @@
pci_unregister_driver(&dgap_driver);
}
-
/*
* dgap_cleanup_board()
*
@@ -484,7 +562,6 @@
kfree(brd);
}
-
/*
* dgap_found_board()
*
@@ -538,9 +615,8 @@
brd->wait_for_bios = 0;
brd->wait_for_fep = 0;
- for (i = 0; i < MAXPORTS; i++) {
+ 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);
@@ -552,13 +628,12 @@
/* get the PCI Base Address Registers */
- /* Xr Jupiter and EPC use BAR 2 */
if (brd->device == PCI_DEVICE_XRJ_DID || brd->device == PCI_DEVICE_EPCJ_DID) {
+ /* Xr Jupiter and EPC use BAR 2 */
brd->membase = pci_resource_start(pdev, 2);
brd->membase_end = pci_resource_end(pdev, 2);
- }
- /* Everyone else uses BAR 0 */
- else {
+ } else {
+ /* Everyone else uses BAR 0 */
brd->membase = pci_resource_start(pdev, 0);
brd->membase_end = pci_resource_end(pdev, 0);
}
@@ -582,7 +657,6 @@
brd->port = brd->membase + PCI_IO_OFFSET;
brd->port_end = brd->port + PCI_IO_SIZE;
-
/*
* Special initialization for non-PLX boards
*/
@@ -625,10 +699,9 @@
else
brd->state = NEED_RESET;
- return(0);
+ return 0;
}
-
int dgap_finalize_board_init(struct board_t *brd) {
int rc;
@@ -653,16 +726,169 @@
dgap_mbuf(brd, DRVSTR": Failed to hook IRQ %d. Board will work in poll mode.\n",
brd->irq);
brd->intr_used = 0;
- }
- else
+ } else
brd->intr_used = 1;
- } else {
+ } else
brd->intr_used = 0;
- }
return(0);
}
+static int dgap_firmware_load(struct pci_dev *pdev, int card_type)
+{
+ struct board_t *brd = dgap_Board[dgap_NumBoards - 1];
+ const struct firmware *fw;
+ char *uaddr;
+ int ret;
+
+ dgap_get_vpd(brd);
+ dgap_do_reset_board(brd);
+
+ if ((fw_info[card_type].conf_name) &&
+ (dgap_driver_state == DRIVER_NEED_CONFIG_LOAD)) {
+ ret = request_firmware(&fw, fw_info[card_type].conf_name, &pdev->dev);
+ if (ret) {
+ printk(KERN_ERR "DGAP: request_firmware failed. Make sure "
+ "you've placed '%s' file into your firmware "
+ "loader directory (e.g. /lib/firmware)\n",
+ fw_info[card_type].conf_name);
+ return ret;
+ } else {
+ if (!dgap_config_buf) {
+ uaddr = dgap_config_buf = dgap_driver_kzmalloc(fw->size + 1, GFP_ATOMIC);
+ if (!dgap_config_buf) {
+ DPR_INIT(("DGAP: dgap_firmware_load - unable to allocate memory for config file\n"));
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+ }
+
+ memcpy(uaddr, fw->data, fw->size);
+ release_firmware(fw);
+ uaddr[fw->size + 1] = '\0'; // The config file is treated as a string
+
+ if (dgap_parsefile(&uaddr, TRUE) != 0)
+ return -EINVAL;
+
+ dgap_driver_state = -1;
+ }
+ }
+
+ ret = dgap_after_config_loaded(brd->boardnum);
+ if (ret != 0)
+ return ret;
+ /*
+ * Match this board to a config the user created for us.
+ */
+ brd->bd_config = dgap_find_config(brd->type, brd->pci_bus, brd->pci_slot);
+
+ /*
+ * Because the 4 port Xr products share the same PCI ID
+ * as the 8 port Xr products, if we receive a NULL config
+ * back, and this is a PAPORT8 board, retry with a
+ * PAPORT4 attempt as well.
+ */
+ if (brd->type == PAPORT8 && !brd->bd_config)
+ brd->bd_config = dgap_find_config(PAPORT4, brd->pci_bus, brd->pci_slot);
+
+ if (!brd->bd_config) {
+ printk(KERN_ERR "DGAP: dgap_firmware_load: No valid configuration found\n");
+ return -EINVAL;
+ }
+
+ dgap_tty_register(brd);
+ dgap_finalize_board_init(brd);
+
+ if (fw_info[card_type].bios_name) {
+ ret = request_firmware(&fw, fw_info[card_type].bios_name, &pdev->dev);
+ if (ret) {
+ printk(KERN_ERR "DGAP: request_firmware failed. Make sure "
+ "you've placed '%s' file into your firmware "
+ "loader directory (e.g. /lib/firmware)\n",
+ fw_info[card_type].bios_name);
+ return ret;
+ } else {
+ uaddr = (char *)fw->data;
+ dgap_do_bios_load(brd, uaddr, fw->size);
+ release_firmware(fw);
+
+ /* Wait for BIOS to test board... */
+ dgap_do_wait_for_bios(brd);
+
+ if (brd->state != FINISHED_BIOS_LOAD)
+ return -ENXIO;
+ }
+ }
+
+ if (fw_info[card_type].fep_name) {
+ ret = request_firmware(&fw, fw_info[card_type].fep_name, &pdev->dev);
+ if (ret) {
+ printk(KERN_ERR "DGAP: request_firmware failed. Make sure "
+ "you've placed '%s' file into your firmware "
+ "loader directory (e.g. /lib/firmware)\n",
+ fw_info[card_type].fep_name);
+ return ret;
+ } else {
+ uaddr = (char *)fw->data;
+ dgap_do_fep_load(brd, uaddr, fw->size);
+ release_firmware(fw);
+
+ /* Wait for FEP to load on board... */
+ dgap_do_wait_for_fep(brd);
+
+ if (brd->state != FINISHED_FEP_LOAD)
+ return -ENXIO;
+ }
+ }
+
+#ifdef DIGI_CONCENTRATORS_SUPPORTED
+ /*
+ * If this is a CX or EPCX, we need to see if the firmware
+ * is requesting a concentrator image from us.
+ */
+ if ((bd->type == PCX) || (bd->type == PEPC)) {
+ chk_addr = (u16 *) (vaddr + DOWNREQ);
+ /* Nonzero if FEP is requesting concentrator image. */
+ check = readw(chk_addr);
+ vaddr = brd->re_map_membase;
+ }
+
+ if (fw_info[card_type].con_name && check && vaddr) {
+ ret = request_firmware(&fw, fw_info[card_type].con_name, &pdev->dev);
+ if (ret) {
+ printk(KERN_ERR "DGAP: request_firmware failed. Make sure "
+ "you've placed '%s' file into your firmware "
+ "loader directory (e.g. /lib/firmware)\n",
+ fw_info[card_type].con_name);
+ return ret;
+ } else {
+ /* Put concentrator firmware loading code here */
+ offset = readw((u16 *) (vaddr + DOWNREQ));
+ memcpy_toio(offset, fw->data, fw->size);
+
+ uaddr = (char *)fw->data;
+ dgap_do_conc_load(brd, uaddr, fw->size)
+ release_firmware(fw);
+ }
+ }
+#endif
+ /*
+ * Do tty device initialization.
+ */
+ ret = dgap_tty_init(brd);
+ if (ret < 0) {
+ dgap_tty_uninit(brd);
+ printk("DGAP: dgap_firmware_load: Can't init tty devices (%d)\n", ret);
+ return -EIO;
+ }
+
+ dgap_sysfs_create(brd);
+
+ brd->state = BOARD_READY;
+ brd->dpastatus = BD_RUNNING;
+
+ return 0;
+}
/*
* Remap PCI memory.
@@ -707,7 +933,6 @@
return 0;
}
-
/*****************************************************************************
*
* Function:
@@ -739,59 +964,38 @@
int i;
struct board_t *brd;
unsigned long lock_flags;
- unsigned long lock_flags2;
- ulong new_time;
+ ulong new_time;
dgap_poll_counter++;
-
- /*
- * If driver needs the config file still,
- * keep trying to wake up the downloader to
- * send us the file.
- */
- if (dgap_driver_state == DRIVER_NEED_CONFIG_LOAD) {
- /*
- * Signal downloader, its got some work to do.
- */
- DGAP_LOCK(dgap_dl_lock, lock_flags2);
- if (dgap_dl_action != 1) {
- dgap_dl_action = 1;
- wake_up_interruptible(&dgap_dl_wait);
- }
- DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
- goto schedule_poller;
- }
/*
* Do not start the board state machine until
* driver tells us its up and running, and has
* everything it needs.
*/
- else if (dgap_driver_state != DRIVER_READY) {
+ if (dgap_driver_state != DRIVER_READY)
goto schedule_poller;
- }
-
+
/*
* If we have just 1 board, or the system is not SMP,
* then use the typical old style poller.
* Otherwise, use our new tasklet based poller, which should
* speed things up for multiple boards.
*/
- if ( (dgap_NumBoards == 1) || (num_online_cpus() <= 1) ) {
+ if ((dgap_NumBoards == 1) || (num_online_cpus() <= 1)) {
for (i = 0; i < dgap_NumBoards; i++) {
brd = dgap_Board[i];
- if (brd->state == BOARD_FAILED) {
+ if (brd->state == BOARD_FAILED)
continue;
- }
- if (!brd->intr_running) {
+
+ if (!brd->intr_running)
/* Call the real board poller directly */
dgap_poll_tasklet((unsigned long) brd);
- }
+
}
- }
- else {
+ } else {
/* Go thru each board, kicking off a tasklet for each if needed */
for (i = 0; i < dgap_NumBoards; i++) {
brd = dgap_Board[i];
@@ -803,9 +1007,8 @@
* Basically, I just really don't want to spin in here, because I want
* to kick off my tasklets as fast as I can, and then get out the poller.
*/
- if (!spin_trylock(&brd->bd_lock)) {
+ if (!spin_trylock(&brd->bd_lock))
continue;
- }
/* If board is in a failed state, don't bother scheduling a tasklet */
if (brd->state == BOARD_FAILED) {
@@ -814,9 +1017,8 @@
}
/* Schedule a poll helper task */
- if (!brd->intr_running) {
+ if (!brd->intr_running)
tasklet_schedule(&brd->helper_tasklet);
- }
/*
* Can't do DGAP_UNLOCK here, as we don't have
@@ -831,27 +1033,23 @@
/*
* Schedule ourself back at the nominal wakeup interval.
*/
- DGAP_LOCK(dgap_poll_lock, lock_flags );
+ DGAP_LOCK(dgap_poll_lock, lock_flags);
dgap_poll_time += dgap_jiffies_from_ms(dgap_poll_tick);
new_time = dgap_poll_time - jiffies;
- if ((ulong) new_time >= 2 * dgap_poll_tick) {
+ if ((ulong) new_time >= 2 * dgap_poll_tick)
dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick);
- }
dgap_poll_timer.function = dgap_poll_handler;
dgap_poll_timer.data = 0;
dgap_poll_timer.expires = dgap_poll_time;
- DGAP_UNLOCK(dgap_poll_lock, lock_flags );
+ DGAP_UNLOCK(dgap_poll_lock, lock_flags);
if (!dgap_poll_stop)
add_timer(&dgap_poll_timer);
}
-
-
-
/*
* dgap_intr()
*
@@ -883,7 +1081,6 @@
return IRQ_HANDLED;
}
-
/*
* dgap_init_globals()
*
@@ -899,24 +1096,21 @@
dgap_trcbuf_size = trcbuf_size;
dgap_debug = debug;
- for (i = 0; i < MAXBOARDS; i++) {
+ for (i = 0; i < MAXBOARDS; i++)
dgap_Board[i] = NULL;
- }
- init_timer( &dgap_poll_timer );
+ init_timer(&dgap_poll_timer);
init_waitqueue_head(&dgap_dl_wait);
dgap_dl_action = 0;
}
-
/************************************************************************
*
* Utility functions
*
************************************************************************/
-
/*
* dgap_driver_kzmalloc()
*
@@ -930,7 +1124,6 @@
return(p);
}
-
/*
* dgap_mbuf()
*
@@ -967,7 +1160,6 @@
DGAP_UNLOCK(dgap_global_lock, flags);
}
-
/*
* dgap_ms_sleep()
*
@@ -982,8 +1174,6 @@
return (signal_pending(current));
}
-
-
/*
* dgap_ioctl_name() : Returns a text version of each ioctl value.
*/
@@ -1060,7 +1250,7 @@
if (n > len)
n = len;
- if (copy_from_user((char *) &buf, from_addr, n) == -1 )
+ if (copy_from_user((char *) &buf, from_addr, n) == -1)
return;
/* Copy data from buffer to kernel memory */
@@ -1083,73 +1273,58 @@
return;
}
-
-int dgap_after_config_loaded(void)
+static int dgap_after_config_loaded(int board)
{
- int i = 0;
- int rc = 0;
+ int ret = 0;
/*
- * Register our ttys, now that we have the config loaded.
+ * Initialize KME waitqueues...
*/
- for (i = 0; i < dgap_NumBoards; ++i) {
+ init_waitqueue_head(&(dgap_Board[board]->kme_wait));
- /*
- * Initialize KME waitqueues...
- */
- init_waitqueue_head(&(dgap_Board[i]->kme_wait));
-
- /*
- * allocate flip buffer for board.
- */
- dgap_Board[i]->flipbuf = dgap_driver_kzmalloc(MYFLIPLEN, GFP_ATOMIC);
- dgap_Board[i]->flipflagbuf = dgap_driver_kzmalloc(MYFLIPLEN, GFP_ATOMIC);
+ /*
+ * allocate flip buffer for board.
+ */
+ dgap_Board[board]->flipbuf = dgap_driver_kzmalloc(MYFLIPLEN, GFP_ATOMIC);
+ if (!dgap_Board[board]->flipbuf) {
+ ret = -ENOMEM;
+ goto out;
}
+ dgap_Board[board]->flipflagbuf = dgap_driver_kzmalloc(MYFLIPLEN, GFP_ATOMIC);
+ if (!dgap_Board[board]->flipflagbuf)
+ ret = -ENOMEM;
- return rc;
+ out:
+ return ret;
}
-
-
-/*=======================================================================
- *
- * usertoboard - copy from user space to board space.
- *
- *=======================================================================*/
-static int dgap_usertoboard(struct board_t *brd, char *to_addr, char __user *from_addr, int len)
+/*
+ * Create pr and tty device entries
+ */
+static void dgap_sysfs_create(struct board_t *brd)
{
- char buf[U2BSIZE];
- int n = U2BSIZE;
-
- if (!brd || brd->magic != DGAP_BOARD_MAGIC)
- return -EFAULT;
-
- while (len) {
- if (n > len)
- n = len;
-
- if (copy_from_user((char *) &buf, from_addr, n) == -1 ) {
- return -EFAULT;
- }
-
- /* Copy data from buffer to card memory */
- memcpy_toio(to_addr, buf, n);
+ struct channel_t *ch;
+ int j = 0;
- /* increment counts */
- len -= n;
- to_addr += n;
- from_addr += n;
- n = U2BSIZE;
- }
- return 0;
+ ch = brd->channels[0];
+ for (j = 0; j < brd->nasync; j++, ch = brd->channels[j]) {
+ struct device *classp;
+ classp = tty_register_device(brd->SerialDriver, j, &(ch->ch_bd->pdev->dev));
+ ch->ch_tun.un_sysfs = classp;
+ dgap_create_tty_sysfs(&ch->ch_tun, classp);
+
+ classp = tty_register_device(brd->PrintDriver, j, &(ch->ch_bd->pdev->dev));
+ ch->ch_pun.un_sysfs = classp;
+ dgap_create_tty_sysfs(&ch->ch_pun, classp);
+ }
+ dgap_create_ports_sysfiles(brd);
}
-
/*
* Copies the BIOS code from the user to the board,
* and starts the BIOS running.
*/
-void dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len)
+static void dgap_do_bios_load(struct board_t *brd, uchar *ubios, int len)
{
uchar *addr;
uint offset;
@@ -1172,21 +1347,15 @@
* Download bios
*/
offset = 0x1000;
- if (dgap_usertoboard(brd, addr + offset, ubios, len) == -1 ) {
- brd->state = BOARD_FAILED;
- brd->dpastatus = BD_NOFEP;
- return;
- }
+ memcpy_toio(addr + offset, ubios, len);
writel(0x0bf00401, addr);
writel(0, (addr + 4));
/* Clear the reset, and change states. */
writeb(FEPCLR, brd->re_map_port);
- brd->state = WAIT_BIOS_LOAD;
}
-
/*
* Checks to see if the BIOS completed running on the card.
*/
@@ -1194,37 +1363,47 @@
{
uchar *addr;
u16 word;
+ u16 err1;
+ u16 err2;
if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
return;
-
+
addr = brd->re_map_membase;
word = readw(addr + POSTAREA);
- /* Check to see if BIOS thinks board is good. (GD). */
- if (word == *(u16 *) "GD") {
- DPR_INIT(("GOT GD in memory, moving states.\n"));
- brd->state = FINISHED_BIOS_LOAD;
- return;
+ /*
+ * It can take 5-6 seconds for a board to
+ * pass the bios self test and post results.
+ * Give it 10 seconds.
+ */
+ brd->wait_for_bios = 0;
+ while (brd->wait_for_bios < 1000) {
+ /* Check to see if BIOS thinks board is good. (GD). */
+ if (word == *(u16 *) "GD") {
+ DPR_INIT(("GOT GD in memory, moving states.\n"));
+ brd->state = FINISHED_BIOS_LOAD;
+ return;
+ }
+ msleep_interruptible(10);
+ brd->wait_for_bios++;
+ word = readw(addr + POSTAREA);
}
- /* Give up on board after too long of time taken */
- if (brd->wait_for_bios++ > 5000) {
- u16 err1 = readw(addr + SEQUENCE);
- u16 err2 = readw(addr + ERROR);
- APR(("***WARNING*** %s failed diagnostics. Error #(%x,%x).\n",
- brd->name, err1, err2));
- brd->state = BOARD_FAILED;
- brd->dpastatus = BD_NOFEP;
- }
+ /* Gave up on board after too long of time taken */
+ err1 = readw(addr + SEQUENCE);
+ err2 = readw(addr + ERROR);
+ APR(("***WARNING*** %s failed diagnostics. Error #(%x,%x).\n",
+ brd->name, err1, err2));
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOBIOS;
}
-
/*
* Copies the FEP code from the user to the board,
* and starts the FEP running.
*/
-void dgap_do_fep_load(struct board_t *brd, uchar __user *ufep, int len)
+static void dgap_do_fep_load(struct board_t *brd, uchar *ufep, int len)
{
uchar *addr;
uint offset;
@@ -1240,11 +1419,7 @@
* Download FEP
*/
offset = 0x1000;
- if (dgap_usertoboard(brd, addr + offset, ufep, len) == -1 ) {
- brd->state = BOARD_FAILED;
- brd->dpastatus = BD_NOFEP;
- return;
- }
+ memcpy_toio(addr + offset, ufep, len);
/*
* If board is a concentrator product, we need to give
@@ -1269,62 +1444,62 @@
writel(0xbfc01004, (addr + 0xc34));
writel(0x3, (addr + 0xc30));
- /* change states. */
- brd->state = WAIT_FEP_LOAD;
-
DPR_INIT(("dgap_do_fep_load() for board %s : finish\n", brd->name));
-
}
-
/*
* Waits for the FEP to report thats its ready for us to use.
*/
-static void dgap_do_wait_for_fep(struct board_t *brd)
+void dgap_do_wait_for_fep(struct board_t *brd)
{
uchar *addr;
u16 word;
+ u16 err1;
+ u16 err2;
if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
return;
addr = brd->re_map_membase;
-
- DPR_INIT(("dgap_do_wait_for_fep() for board %s : start. addr: %p\n", brd->name, addr));
-
word = readw(addr + FEPSTAT);
- /* Check to see if FEP is up and running now. */
- if (word == *(u16 *) "OS") {
- DPR_INIT(("GOT OS in memory for board %s, moving states.\n", brd->name));
- brd->state = FINISHED_FEP_LOAD;
+ /*
+ * It can take 2-3 seconds for the FEP to
+ * be up and running. Give it 5 secs.
+ */
+ brd->wait_for_fep = 0;
+ while (brd->wait_for_fep < 500) {
+ /* Check to see if FEP is up and running now. */
+ if (word == *(u16 *) "OS") {
+ DPR_INIT(("GOT OS in memory for board %s, moving states.\n", brd->name));
+ brd->state = FINISHED_FEP_LOAD;
+ /*
+ * Check to see if the board can support FEP5+ commands.
+ */
+ word = readw(addr + FEP5_PLUS);
+ if (word == *(u16 *) "5A") {
+ DPR_INIT(("GOT 5A in memory for board %s, board supports extended FEP5 commands.\n", brd->name));
+ brd->bd_flags |= BD_FEP5PLUS;
+ }
- /*
- * Check to see if the board can support FEP5+ commands.
- */
- word = readw(addr + FEP5_PLUS);
- if (word == *(u16 *) "5A") {
- DPR_INIT(("GOT 5A in memory for board %s, board supports extended FEP5 commands.\n", brd->name));
- brd->bd_flags |= BD_FEP5PLUS;
+ return;
}
-
- return;
+ msleep_interruptible(10);
+ brd->wait_for_fep++;
+ word = readw(addr + FEPSTAT);
}
- /* Give up on board after too long of time taken */
- if (brd->wait_for_fep++ > 5000) {
- u16 err1 = readw(addr + SEQUENCE);
- u16 err2 = readw(addr + ERROR);
- APR(("***WARNING*** FEPOS for %s not functioning. Error #(%x,%x).\n",
- brd->name, err1, err2));
- brd->state = BOARD_FAILED;
- brd->dpastatus = BD_NOFEP;
- }
+ /* Gave up on board after too long of time taken */
+ err1 = readw(addr + SEQUENCE);
+ err2 = readw(addr + ERROR);
+ APR(("***WARNING*** FEPOS for %s not functioning. Error #(%x,%x).\n",
+ brd->name, err1, err2));
+ brd->state = BOARD_FAILED;
+ brd->dpastatus = BD_NOFEP;
DPR_INIT(("dgap_do_wait_for_fep() for board %s : finish\n", brd->name));
}
-
/*
* Physically forces the FEP5 card to reset itself.
*/
@@ -1382,9 +1557,9 @@
DPR_INIT(("dgap_do_reset_board() finish\n"));
}
-
+#ifdef DIGI_CONCENTRATORS_SUPPORTED
/*
- * Sends a concentrator image into the FEP5 board.
+ * Sends a concentrator image into the FEP5 board. FIXME:
*/
void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len)
{
@@ -1399,19 +1574,12 @@
offset = readw((u16 *) (vaddr + DOWNREQ));
to_dp = (struct downld_t *) (vaddr + (int) offset);
-
- /*
- * The image was already read into kernel space,
- * we do NOT need a user space read here
- */
- memcpy_toio((char *) to_dp, uaddr, sizeof(struct downld_t));
+ memcpy_toio(to_dp, uaddr, len);
/* Tell card we have data for it */
writew(0, vaddr + (DOWNREQ));
-
- brd->conc_dl_status = NO_PENDING_CONCENTRATOR_REQUESTS;
}
-
+#endif
#define EXPANSION_ROM_SIZE (64 * 1024)
#define FEP5_ROM_MAGIC (0xFEFFFFFF)
@@ -1517,7 +1685,6 @@
pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
}
-
/*
* Our board poller function.
*/
@@ -1528,8 +1695,6 @@
ulong lock_flags2;
char *vaddr;
u16 head, tail;
- u16 *chk_addr;
- u16 check = 0;
if (!bd || (bd->magic != DGAP_BOARD_MAGIC)) {
APR(("dgap_poll_tasklet() - NULL or bad bd.\n"));
@@ -1563,30 +1728,6 @@
goto out;
}
- /*
- * If this is a CX or EPCX, we need to see if the firmware
- * is requesting a concentrator image from us.
- */
- if ((bd->type == PCX) || (bd->type == PEPC)) {
- chk_addr = (u16 *) (vaddr + DOWNREQ);
- check = readw(chk_addr);
- /* Nonzero if FEP is requesting concentrator image. */
- if (check) {
- if (bd->conc_dl_status == NO_PENDING_CONCENTRATOR_REQUESTS)
- bd->conc_dl_status = NEED_CONCENTRATOR;
- /*
- * Signal downloader, its got some work to do.
- */
- DGAP_LOCK(dgap_dl_lock, lock_flags2);
- if (dgap_dl_action != 1) {
- dgap_dl_action = 1;
- wake_up_interruptible(&dgap_dl_wait);
- }
- DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
-
- }
- }
-
eaddr = (struct ev_t *) (vaddr + EVBUF);
/* Get our head and tail */
@@ -1774,7 +1915,6 @@
DGAP_UNLOCK(bd->bd_lock, lock_flags);
}
-
/*=======================================================================
*
* dgap_cmdb - Sends a 2 byte command to the FEP.
@@ -1865,7 +2005,6 @@
}
}
-
/*=======================================================================
*
* dgap_cmdw - Sends a 1 word command to the FEP.
@@ -1953,8 +2092,6 @@
}
}
-
-
/*=======================================================================
*
* dgap_cmdw_ext - Sends a extended word command to the FEP.
@@ -2055,7 +2192,6 @@
}
}
-
/*=======================================================================
*
* dgap_wmove - Write data to FEP buffer.
@@ -2153,7 +2289,6 @@
return value;
}
-
/*
* Calls the firmware to reset this channel.
*/
@@ -2180,7 +2315,6 @@
ch->ch_hflow = 0;
}
-
/*=======================================================================
*
* dgap_param - Set Digi parameters.
@@ -2528,7 +2662,6 @@
return 0;
}
-
/*
* dgap_parity_scan()
*
@@ -2615,9 +2748,6 @@
DPR_PSCAN(("dgap_parity_scan finish\n"));
}
-
-
-
/*=======================================================================
*
* dgap_event - FEP to host event processing routine.
@@ -2693,19 +2823,16 @@
/*
* Make sure the interrupt is valid.
*/
- if ( port >= bd->nasync) {
+ if (port >= bd->nasync)
goto next;
- }
- if (!(reason & (IFMODEM | IFBREAK | IFTLW | IFTEM | IFDATA))) {
+ if (!(reason & (IFMODEM | IFBREAK | IFTLW | IFTEM | IFDATA)))
goto next;
- }
ch = bd->channels[port];
- if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) {
+ if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
goto next;
- }
/*
* If we have made it here, the event was valid.
diff -urN linux-3.13.1-orig/drivers/staging/dgap/dgap_driver.h linux-3.13.1-new/drivers/staging/dgap/dgap_driver.h
--- linux-3.13.1-orig/drivers/staging/dgap/dgap_driver.h 2014-02-03 13:34:50.489287314 -0500
+++ linux-3.13.1-new/drivers/staging/dgap/dgap_driver.h 2014-02-03 14:14:40.992545649 -0500
@@ -580,12 +580,6 @@
extern int dgap_ms_sleep(ulong ms);
extern void *dgap_driver_kzmalloc(size_t size, int priority);
extern char *dgap_ioctl_name(int cmd);
-extern void dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len);
-extern void dgap_do_fep_load(struct board_t *brd, uchar __user *ufep, int len);
-extern void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len);
-extern void dgap_do_config_load(uchar __user *uaddr, int len);
-extern int dgap_after_config_loaded(void);
-extern int dgap_finalize_board_init(struct board_t *brd);
/*
* Our Global Variables.
More information about the devel
mailing list