Linux Serial subsystem development
 help / color / mirror / Atom feed
* Re: [PATCH v2] serial: sh-sci: fix memory region release in error path
From: Greg KH @ 2026-04-21  6:43 UTC (permalink / raw)
  To: Hongling Zeng
  Cc: jirislaby, geert+renesas, biju.das.jz, wsa+renesas,
	thierry.bultel.yh, prabhakar.mahadev-lad.rj, linux-kernel,
	linux-serial, zhongling0719, kernel test robot, Dan Carpenter
In-Reply-To: <20260421063819.715295-1-zenghongling@kylinos.cn>

On Tue, Apr 21, 2026 at 02:38:19PM +0800, Hongling Zeng wrote:
> From: zenghongling <zenghongling@kylinos.cn>

This needs to match the name you used in your signed-off-by: line.

thanks,

greg k-h

^ permalink raw reply

* [PATCH v2] serial: sh-sci: fix memory region release in error path
From: Hongling Zeng @ 2026-04-21  6:38 UTC (permalink / raw)
  To: gregkh, jirislaby, geert+renesas, biju.das.jz, wsa+renesas,
	thierry.bultel.yh, prabhakar.mahadev-lad.rj
  Cc: linux-kernel, linux-serial, zhongling0719, zenghongling,
	kernel test robot, Dan Carpenter

From: zenghongling <zenghongling@kylinos.cn>

The sci_request_port() function uses request_mem_region() to reserve
I/O memory, but in the error path when sci_remap_port() fails, it
incorrectly calls release_resource() instead of release_mem_region().

This mismatch can cause resource accounting issues. Fix it by using
the correct release function, consistent with sci_release_port().

Fixes: e2651647080930a1 ("serial: sh-sci: Handle port memory region reservations.")
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <error27@gmail.com>
Closes: https://lore.kernel.org/r/202604032356.SzEjYkBC-lkp@intel.com/
Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

---
Change in v2:
  - Per review, fix the commit message
---
---
 drivers/tty/serial/sh-sci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 6c819b6b2425..54db019a5bfc 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -3025,7 +3025,7 @@ int sci_request_port(struct uart_port *port)
 
 	ret = sci_remap_port(port);
 	if (unlikely(ret != 0)) {
-		release_resource(res);
+		release_mem_region(port->mapbase, sport->reg_size);
 		return ret;
 	}
 
-- 
2.25.1


^ permalink raw reply related

* [PATCH v3 2/2] serial: 8250_dw: Use a fixed CPR value for UltraRISC DP1000 UART
From: Jia Wang @ 2026-04-21  5:58 UTC (permalink / raw)
  To: Ilpo Järvinen, Andy Shevchenko, Greg Kroah-Hartman,
	Jiri Slaby, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-kernel, linux-serial, linux-riscv, devicetree, Jia Wang
In-Reply-To: <20260421-ultrarisc-serial-v3-0-3d7f09c2420e@ultrarisc.com>

The UltraRISC DP1000 UART does not provide the standard CPR register used
by 8250_dw to discover port capabilities.

Provide a fixed CPR value for the DP1000-specific compatible so the
driver can configure the port correctly.

Signed-off-by: Jia Wang <wangjia@ultrarisc.com>
---
 drivers/tty/serial/8250/8250_dw.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 94beadb4024d..ca6dbdf75918 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -962,6 +962,12 @@ static const struct dw8250_platform_data dw8250_intc10ee = {
 	.quirks = DW_UART_QUIRK_IER_KICK,
 };
 
+static const struct dw8250_platform_data dw8250_ultrarisc_dp1000_data = {
+	.usr_reg = DW_UART_USR,
+	.cpr_value = 0x00022022,
+	.quirks = DW_UART_QUIRK_CPR_VALUE,
+};
+
 static const struct of_device_id dw8250_of_match[] = {
 	{ .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb },
 	{ .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data },
@@ -969,6 +975,7 @@ static const struct of_device_id dw8250_of_match[] = {
 	{ .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data },
 	{ .compatible = "sophgo,sg2044-uart", .data = &dw8250_skip_set_rate_data },
 	{ .compatible = "starfive,jh7100-uart", .data = &dw8250_skip_set_rate_data },
+	{ .compatible = "ultrarisc,dp1000-uart", .data = &dw8250_ultrarisc_dp1000_data },
 	{ /* Sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, dw8250_of_match);

-- 
2.34.1


^ permalink raw reply related

* [PATCH v3 1/2] dt-bindings: serial: snps-dw-apb-uart: Add UltraRISC DP1000 UART
From: Jia Wang @ 2026-04-21  5:58 UTC (permalink / raw)
  To: Ilpo Järvinen, Andy Shevchenko, Greg Kroah-Hartman,
	Jiri Slaby, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-kernel, linux-serial, linux-riscv, devicetree, Jia Wang
In-Reply-To: <20260421-ultrarisc-serial-v3-0-3d7f09c2420e@ultrarisc.com>

UltraRISC DP1000 integrates a Synopsys DesignWare APB UART, but it does
not provide the standard CPR and UCV registers.

Signed-off-by: Jia Wang <wangjia@ultrarisc.com>
---
 Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
index 6efe43089a74..f84600f66df8 100644
--- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
+++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
@@ -77,6 +77,7 @@ properties:
               - starfive,jh7100-hsuart
               - starfive,jh7100-uart
               - starfive,jh7110-uart
+              - ultrarisc,dp1000-uart
           - const: snps,dw-apb-uart
       - const: snps,dw-apb-uart
 

-- 
2.34.1


^ permalink raw reply related

* [PATCH v3 0/2] serial: 8250_dw: Add support for UltraRISC DP1000 uart
From: Jia Wang @ 2026-04-21  5:58 UTC (permalink / raw)
  To: Ilpo Järvinen, Andy Shevchenko, Greg Kroah-Hartman,
	Jiri Slaby, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-kernel, linux-serial, linux-riscv, devicetree, Jia Wang

This patch series adds support for the UltraRISC DP1000 UART controller.

The series includes two patches:
1. Document the DP1000-specific compatible string for this UART variant.
2. Update 8250_dw to use a fixed CPR value for the DP1000 UART.

The patches have been tested on Ultrarisc DP1000 development board with
Linux v7.0-rc7, verifying basic UART functionality.

Signed-off-by: Jia Wang <wangjia@ultrarisc.com>
---
Changes in v3:
- Rebased on Linux v7.0-rc7.
- Patch 1:
   * Removed separate `items` entry for DP1000, merging it into the
     existing `enum` to comply with the schema.
   * Updated commit message to describe DP1000 UART hardware differences.
- Patch 2:
   * Drop the custom quirk for missing CPR register.
   * Switch to using DW_UART_QUIRK_CPR_VALUE to provide a fixed CPR value.
- Link to v2: https://patch.msgid.link/20260316-ultrarisc-serial-v2-0-6ab3e7fa891c@ultrarisc.com

Changes in v2:
- Rebased on Linux v7.0-rc4 (previously on v7.0-rc2).
- Reordered patch series: DT binding patch comes before driver changes.
- Updated commit message for DT binding patch.
- Link to v1: https://patch.msgid.link/20260316-ultrarisc-serial-v1-0-c464f3e933a5@ultrarisc.com

---
Jia Wang (2):
      dt-bindings: serial: snps-dw-apb-uart: Add UltraRISC DP1000 UART
      serial: 8250_dw: Use a fixed CPR value for UltraRISC DP1000 UART

 Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml | 1 +
 drivers/tty/serial/8250/8250_dw.c                              | 7 +++++++
 2 files changed, 8 insertions(+)
---
base-commit: e774d5f1bc27a85f858bce7688509e866f8e8a4e
change-id: 20260309-ultrarisc-serial-64ff637edf26

Best regards,
--  
Jia Wang <wangjia@ultrarisc.com>


^ permalink raw reply

* Re: [PATCH] serial: fsl_lpuart: fix rx buffer and DMA map leaks in start_rx_dma
From: Frank Li @ 2026-04-21  2:33 UTC (permalink / raw)
  To: Shitalkumar Gandhi
  Cc: gregkh, jirislaby, bhuvanchandra.dv, peng.fan, sherry.sun,
	linux-serial, imx, linux-arm-kernel, linux-kernel, stable,
	Shitalkumar Gandhi
In-Reply-To: <20260420135903.2062024-1-shitalkumar.gandhi@cambiumnetworks.com>

On Mon, Apr 20, 2026 at 07:29:03PM +0530, Shitalkumar Gandhi wrote:
> lpuart_start_rx_dma() allocates sport->rx_ring.buf with kzalloc() and
> then maps a scatterlist via dma_map_sg().  On three subsequent error
> paths the function returns directly without releasing those resources:
>
>   - when dma_map_sg() returns 0 (-EINVAL):
>       ring->buf is leaked.
>   - when dmaengine_slave_config() fails:
>       ring->buf and the DMA mapping are leaked.
>   - when dmaengine_prep_dma_cyclic() returns NULL:
>       ring->buf and the DMA mapping are leaked.
>
> The sole cleanup path, lpuart_dma_rx_free(), is only reached when
> lpuart_dma_rx_use is set, and the caller lpuart_rx_dma_startup() clears
> that flag on failure of lpuart_start_rx_dma().  So these resources are
> permanently leaked on every failure in this function.  Repeated port
> open/close or termios changes under error conditions will slowly consume
> memory and leave stale streaming DMA mappings behind.
>
> Fix it by introducing two error labels that unmap the scatterlist and
> free the ring buffer as appropriate.  While here, replace the misleading
> -EFAULT (bad userspace pointer) returned when dmaengine_prep_dma_cyclic()
> fails with the more accurate -ENOMEM, matching how other dmaengine users
> in the tree treat this failure.
>
> No functional change on the success path.
>
> Fixes: 5887ad43ee02 ("tty: serial: fsl_lpuart: Use cyclic DMA for Rx")
> Cc: stable@vger.kernel.org
>
> Signed-off-by: Shitalkumar Gandhi <shitalkumar.gandhi@cambiumnetworks.com>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/tty/serial/fsl_lpuart.c | 15 ++++++++++++---
>  1 file changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
> index f36d50fe056f..296a096be351 100644
> --- a/drivers/tty/serial/fsl_lpuart.c
> +++ b/drivers/tty/serial/fsl_lpuart.c
> @@ -1376,7 +1376,8 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
>
>  	if (!nent) {
>  		dev_err(sport->port.dev, "DMA Rx mapping error\n");
> -		return -EINVAL;
> +		ret = -EINVAL;
> +		goto err_free_buf;
>  	}
>
>  	dma_rx_sconfig.src_addr = lpuart_dma_datareg_addr(sport);
> @@ -1388,7 +1389,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
>  	if (ret < 0) {
>  		dev_err(sport->port.dev,
>  				"DMA Rx slave config failed, err = %d\n", ret);
> -		return ret;
> +		goto err_unmap_sg;
>  	}
>
>  	sport->dma_rx_desc = dmaengine_prep_dma_cyclic(chan,
> @@ -1399,7 +1400,8 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
>  				 DMA_PREP_INTERRUPT);
>  	if (!sport->dma_rx_desc) {
>  		dev_err(sport->port.dev, "Cannot prepare cyclic DMA\n");
> -		return -EFAULT;
> +		ret = -ENOMEM;
> +		goto err_unmap_sg;
>  	}
>
>  	sport->dma_rx_desc->callback = lpuart_dma_rx_complete;
> @@ -1423,6 +1425,13 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
>  	}
>
>  	return 0;
> +
> +err_unmap_sg:
> +	dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
> +err_free_buf:
> +	kfree(ring->buf);
> +	ring->buf = NULL;
> +	return ret;
>  }
>
>  static void lpuart_dma_rx_free(struct uart_port *port)
> --
> 2.25.1
>

^ permalink raw reply

* [PATCH v5 4/4] samples: rust: add Rust serial device bus sample device driver
From: Markus Probst @ 2026-04-20 20:07 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Jiri Slaby, Miguel Ojeda,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Kari Argillander,
	Rafael J. Wysocki, Viresh Kumar, Boqun Feng, David Airlie,
	Simona Vetter, Boqun Feng
  Cc: linux-serial, linux-kernel, rust-for-linux, linux-pm, driver-core,
	dri-devel, Markus Probst
In-Reply-To: <20260420-rust_serdev-v5-0-57e8ba0519f3@posteo.de>

Add a sample Rust serial device bus device driver illustrating the usage
of the serial device bus abstractions.

This drivers probes through either a match of device / driver name or a
match within the OF ID table.

Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
 samples/rust/Kconfig               | 11 +++++
 samples/rust/Makefile              |  1 +
 samples/rust/rust_driver_serdev.rs | 86 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 98 insertions(+)

diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
index c49ab9106345..31d62533ef25 100644
--- a/samples/rust/Kconfig
+++ b/samples/rust/Kconfig
@@ -161,6 +161,17 @@ config SAMPLE_RUST_DRIVER_AUXILIARY
 
 	  If unsure, say N.
 
+config SAMPLE_RUST_DRIVER_SERDEV
+	tristate "Serial Device Bus Device Driver"
+	select RUST_SERIAL_DEV_BUS_ABSTRACTIONS
+	help
+	  This option builds the Rust serial device bus driver sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_driver_serdev.
+
+	  If unsure, say N.
+
 config SAMPLE_RUST_SOC
 	tristate "SoC Driver"
 	select SOC_BUS
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
index 6c0aaa58cccc..b986b681cde5 100644
--- a/samples/rust/Makefile
+++ b/samples/rust/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM)	+= rust_driver_platform.o
 obj-$(CONFIG_SAMPLE_RUST_DRIVER_USB)		+= rust_driver_usb.o
 obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX)		+= rust_driver_faux.o
 obj-$(CONFIG_SAMPLE_RUST_DRIVER_AUXILIARY)	+= rust_driver_auxiliary.o
+obj-$(CONFIG_SAMPLE_RUST_DRIVER_SERDEV)		+= rust_driver_serdev.o
 obj-$(CONFIG_SAMPLE_RUST_CONFIGFS)		+= rust_configfs.o
 obj-$(CONFIG_SAMPLE_RUST_SOC)			+= rust_soc.o
 
diff --git a/samples/rust/rust_driver_serdev.rs b/samples/rust/rust_driver_serdev.rs
new file mode 100644
index 000000000000..8cf3fb451b22
--- /dev/null
+++ b/samples/rust/rust_driver_serdev.rs
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust Serial device bus device driver sample.
+
+use kernel::{
+    acpi,
+    device::{
+        Bound,
+        Core, //
+    },
+    of,
+    prelude::*,
+    serdev,
+    sync::aref::ARef, //
+};
+
+struct SampleDriver {
+    sdev: ARef<serdev::Device>,
+}
+
+kernel::of_device_table!(
+    OF_TABLE,
+    MODULE_OF_TABLE,
+    <SampleDriver as serdev::Driver>::IdInfo,
+    [(of::DeviceId::new(c"test,rust_driver_serdev"), ())]
+);
+
+kernel::acpi_device_table!(
+    ACPI_TABLE,
+    MODULE_ACPI_TABLE,
+    <SampleDriver as serdev::Driver>::IdInfo,
+    [(acpi::DeviceId::new(c"LNUXBEEF"), ())]
+);
+
+#[vtable]
+impl serdev::Driver for SampleDriver {
+    type IdInfo = ();
+    const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
+    const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE);
+
+    fn probe(
+        sdev: &serdev::Device<Core>,
+        _info: Option<&Self::IdInfo>,
+    ) -> impl PinInit<Self, Error> {
+        let dev = sdev.as_ref();
+
+        dev_dbg!(dev, "Probe Rust Serial device bus device driver sample.\n");
+
+        if sdev
+            .set_baudrate(
+                dev.fwnode()
+                    .and_then(|fwnode| fwnode.property_read(c"baudrate").optional())
+                    .unwrap_or(115200),
+            )
+            .is_err()
+        {
+            return Err(EINVAL);
+        }
+        sdev.set_flow_control(false);
+        sdev.set_parity(serdev::Parity::None)?;
+
+        Ok(Self { sdev: sdev.into() })
+    }
+
+    fn receive(sdev: &serdev::Device<Bound>, _this: Pin<&Self>, data: &[u8]) -> usize {
+        let _ = sdev.write_all(data, serdev::Timeout::Max);
+        data.len()
+    }
+}
+
+impl Drop for SampleDriver {
+    fn drop(&mut self) {
+        dev_dbg!(
+            self.sdev.as_ref(),
+            "Remove Rust Serial device bus device driver sample.\n"
+        );
+    }
+}
+
+kernel::module_serdev_device_driver! {
+    type: SampleDriver,
+    name: "rust_driver_serdev",
+    authors: ["Markus Probst"],
+    description: "Rust Serial device bus device driver",
+    license: "GPL v2",
+}

-- 
2.52.0


^ permalink raw reply related

* [PATCH v5 3/4] rust: add basic serial device bus abstractions
From: Markus Probst @ 2026-04-20 20:07 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Jiri Slaby, Miguel Ojeda,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Kari Argillander,
	Rafael J. Wysocki, Viresh Kumar, Boqun Feng, David Airlie,
	Simona Vetter, Boqun Feng
  Cc: linux-serial, linux-kernel, rust-for-linux, linux-pm, driver-core,
	dri-devel, Markus Probst
In-Reply-To: <20260420-rust_serdev-v5-0-57e8ba0519f3@posteo.de>

Implement the basic serial device bus abstractions required to write a
serial device bus device driver with or without the need for initial device
data. This includes the following data structures:

The `serdev::Driver` trait represents the interface to the driver.

The `serdev::Device` abstraction represents a `struct serdev_device`.

In order to provide the Serdev specific parts to a generic
`driver::Registration` the `driver::RegistrationOps` trait is
implemented by `serdev::Adapter`.

Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
 drivers/tty/serdev/Kconfig      |   7 +
 rust/bindings/bindings_helper.h |   1 +
 rust/helpers/helpers.c          |   1 +
 rust/helpers/serdev.c           |  22 ++
 rust/kernel/lib.rs              |   2 +
 rust/kernel/serdev.rs           | 536 ++++++++++++++++++++++++++++++++++++++++
 6 files changed, 569 insertions(+)

diff --git a/drivers/tty/serdev/Kconfig b/drivers/tty/serdev/Kconfig
index 46ae732bfc68..e6dfe949ad01 100644
--- a/drivers/tty/serdev/Kconfig
+++ b/drivers/tty/serdev/Kconfig
@@ -9,6 +9,13 @@ menuconfig SERIAL_DEV_BUS
 
 	  Note that you typically also want to enable TTY port controller support.
 
+config RUST_SERIAL_DEV_BUS_ABSTRACTIONS
+	bool "Rust Serial device bus abstractions"
+	depends on RUST
+	select SERIAL_DEV_BUS
+	help
+	  This enables the Rust abstraction for the serial device bus API.
+
 if SERIAL_DEV_BUS
 
 config SERIAL_DEV_CTRL_TTYPORT
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 083cc44aa952..ab521ba42673 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -80,6 +80,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/sched.h>
 #include <linux/security.h>
+#include <linux/serdev.h>
 #include <linux/slab.h>
 #include <linux/sys_soc.h>
 #include <linux/task_work.h>
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index a3c42e51f00a..9b87e9591cfd 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -53,6 +53,7 @@
 #include "regulator.c"
 #include "scatterlist.c"
 #include "security.c"
+#include "serdev.c"
 #include "signal.c"
 #include "slab.c"
 #include "spinlock.c"
diff --git a/rust/helpers/serdev.c b/rust/helpers/serdev.c
new file mode 100644
index 000000000000..c52b78ca3fc7
--- /dev/null
+++ b/rust/helpers/serdev.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/serdev.h>
+
+__rust_helper
+void rust_helper_serdev_device_driver_unregister(struct serdev_device_driver *sdrv)
+{
+	serdev_device_driver_unregister(sdrv);
+}
+
+__rust_helper
+void rust_helper_serdev_device_put(struct serdev_device *serdev)
+{
+	serdev_device_put(serdev);
+}
+
+__rust_helper
+void rust_helper_serdev_device_set_client_ops(struct serdev_device *serdev,
+					      const struct serdev_device_ops *ops)
+{
+	serdev_device_set_client_ops(serdev, ops);
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index d93292d47420..5107c9c1be07 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -144,6 +144,8 @@
 pub mod scatterlist;
 pub mod security;
 pub mod seq_file;
+#[cfg(CONFIG_RUST_SERIAL_DEV_BUS_ABSTRACTIONS)]
+pub mod serdev;
 pub mod sizes;
 pub mod slice;
 #[cfg(CONFIG_SOC_BUS)]
diff --git a/rust/kernel/serdev.rs b/rust/kernel/serdev.rs
new file mode 100644
index 000000000000..f1464e6a3fd6
--- /dev/null
+++ b/rust/kernel/serdev.rs
@@ -0,0 +1,536 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Abstractions for the serial device bus.
+//!
+//! C header: [`include/linux/serdev.h`](srctree/include/linux/serdev.h)
+
+use crate::{
+    acpi,
+    device,
+    devres,
+    driver,
+    error::{
+        from_result,
+        to_result,
+        VTABLE_DEFAULT_ERROR, //
+    },
+    of,
+    prelude::*,
+    sync::Completion,
+    time::{
+        msecs_to_jiffies,
+        Jiffies,
+        Msecs, //
+    },
+    types::{
+        AlwaysRefCounted,
+        Opaque, //
+    }, //
+};
+
+use core::{
+    cell::UnsafeCell,
+    marker::PhantomData,
+    mem::offset_of,
+    num::NonZero,
+    ptr::NonNull, //
+};
+
+/// Parity bit to use with a serial device.
+#[repr(u32)]
+pub enum Parity {
+    /// No parity bit.
+    None = bindings::serdev_parity_SERDEV_PARITY_NONE,
+    /// Even partiy.
+    Even = bindings::serdev_parity_SERDEV_PARITY_EVEN,
+    /// Odd parity.
+    Odd = bindings::serdev_parity_SERDEV_PARITY_ODD,
+}
+
+/// Timeout in Jiffies.
+pub enum Timeout {
+    /// Wait for a specific amount of [`Jiffies`].
+    Jiffies(NonZero<Jiffies>),
+    /// Wait for a specific amount of [`Msecs`].
+    Milliseconds(NonZero<Msecs>),
+    /// Wait as long as possible.
+    ///
+    /// This is equivalent to [`kernel::task::MAX_SCHEDULE_TIMEOUT`].
+    Max,
+}
+
+impl Timeout {
+    fn into_jiffies(self) -> isize {
+        match self {
+            Self::Jiffies(value) => value.get().try_into().unwrap_or_default(),
+            Self::Milliseconds(value) => {
+                msecs_to_jiffies(value.get()).try_into().unwrap_or_default()
+            }
+            Self::Max => 0,
+        }
+    }
+}
+
+/// An adapter for the registration of serial device bus device drivers.
+pub struct Adapter<T: Driver>(T);
+
+// SAFETY:
+// - `bindings::serdev_device_driver` is a C type declared as `repr(C)`.
+// - `Drvdata<T>` is the type of the driver's device private data.
+// - `struct serdev_device_driver` embeds a `struct device_driver`.
+// - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `struct device_driver`.
+unsafe impl<T: Driver + 'static> driver::DriverLayout for Adapter<T> {
+    type DriverType = bindings::serdev_device_driver;
+    type DriverData = T;
+    const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver);
+}
+
+// SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if
+// a preceding call to `register` has been successful.
+unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
+    unsafe fn register(
+        sdrv: &Opaque<Self::DriverType>,
+        name: &'static CStr,
+        module: &'static ThisModule,
+    ) -> Result {
+        let of_table = match T::OF_ID_TABLE {
+            Some(table) => table.as_ptr(),
+            None => core::ptr::null(),
+        };
+
+        let acpi_table = match T::ACPI_ID_TABLE {
+            Some(table) => table.as_ptr(),
+            None => core::ptr::null(),
+        };
+
+        // SAFETY: It's safe to set the fields of `struct serdev_device_driver` on initialization.
+        unsafe {
+            (*sdrv.get()).driver.name = name.as_char_ptr();
+            (*sdrv.get()).probe = Some(Self::probe_callback);
+            (*sdrv.get()).remove = Some(Self::remove_callback);
+            (*sdrv.get()).driver.of_match_table = of_table;
+            (*sdrv.get()).driver.acpi_match_table = acpi_table;
+        }
+
+        // SAFETY: `sdrv` is guaranteed to be a valid `DriverType`.
+        to_result(unsafe { bindings::__serdev_device_driver_register(sdrv.get(), module.0) })
+    }
+
+    unsafe fn unregister(sdrv: &Opaque<Self::DriverType>) {
+        // SAFETY: `sdrv` is guaranteed to be a valid `DriverType`.
+        unsafe { bindings::serdev_device_driver_unregister(sdrv.get()) };
+    }
+}
+
+#[pin_data]
+struct PrivateData {
+    #[pin]
+    probe_complete: Completion,
+    error: UnsafeCell<bool>,
+}
+
+impl<T: Driver + 'static> Adapter<T> {
+    const OPS: &'static bindings::serdev_device_ops = &bindings::serdev_device_ops {
+        receive_buf: if T::HAS_RECEIVE {
+            Some(Self::receive_buf_callback)
+        } else {
+            None
+        },
+        write_wakeup: Some(bindings::serdev_device_write_wakeup),
+    };
+
+    extern "C" fn probe_callback(sdev: *mut bindings::serdev_device) -> kernel::ffi::c_int {
+        // SAFETY: The serial device bus only ever calls the probe callback with a valid pointer to
+        // a `struct serdev_device`.
+        //
+        // INVARIANT: `sdev` is valid for the duration of `probe_callback()`.
+        let sdev = unsafe { &*sdev.cast::<Device<device::CoreInternal>>() };
+        let id_info = <Self as driver::Adapter>::id_info(sdev.as_ref());
+
+        from_result(|| {
+            let private_data = devres::register(
+                sdev.as_ref(),
+                try_pin_init!(PrivateData {
+                    probe_complete <- Completion::new(),
+                    error: false.into(),
+                }),
+                GFP_KERNEL,
+            )?;
+
+            // SAFETY: `sdev.as_raw()` is guaranteed to be a valid pointer to `serdev_device`.
+            unsafe {
+                (*sdev.as_raw()).rust_private_data =
+                    (&raw const *private_data).cast::<c_void>().cast_mut()
+            };
+
+            // SAFETY: `sdev.as_raw()` is guaranteed to be a valid pointer to `serdev_device`.
+            unsafe { bindings::serdev_device_set_client_ops(sdev.as_raw(), Self::OPS) };
+
+            // SAFETY: The serial device bus only ever calls the probe callback with a valid pointer
+            // to a `serdev_device`.
+            to_result(unsafe {
+                bindings::devm_serdev_device_open(sdev.as_ref().as_raw(), sdev.as_raw())
+            })?;
+
+            let data = T::probe(sdev, id_info);
+            let result = sdev.as_ref().set_drvdata(data);
+
+            // SAFETY: We have exclusive access to `private_data.error`.
+            unsafe { *private_data.error.get() = result.is_err() };
+
+            private_data.probe_complete.complete_all();
+
+            result.map(|()| 0)
+        })
+    }
+
+    extern "C" fn remove_callback(sdev: *mut bindings::serdev_device) {
+        // SAFETY: The serial device bus only ever calls the remove callback with a valid pointer
+        // to a `struct serdev_device`.
+        //
+        // INVARIANT: `sdev` is valid for the duration of `remove_callback()`.
+        let sdev = unsafe { &*sdev.cast::<Device<device::CoreInternal>>() };
+
+        // SAFETY: `remove_callback` is only ever called after a successful call to
+        // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called
+        // and stored a `Pin<KBox<T>>`.
+        let data = unsafe { sdev.as_ref().drvdata_borrow::<T>() };
+
+        T::unbind(sdev, data);
+    }
+
+    extern "C" fn receive_buf_callback(
+        sdev: *mut bindings::serdev_device,
+        buf: *const u8,
+        length: usize,
+    ) -> usize {
+        // SAFETY: The serial device bus only ever calls the receive buf callback with a valid
+        // pointer to a `struct serdev_device`.
+        //
+        // INVARIANT: `sdev` is valid for the duration of `receive_buf_callback()`.
+        let sdev = unsafe { &*sdev.cast::<Device<device::CoreInternal>>() };
+
+        // SAFETY:
+        // - The serial device bus only ever calls the receive buf callback with a valid pointer to
+        //   a `struct serdev_device`.
+        // - `receive_buf_callback` is only ever called after a successful call to
+        //   `probe_callback`, hence it's guaranteed that `sdev.private_data` is a pointer
+        //   to a valid `PrivateData`.
+        let private_data = unsafe { &*(*sdev.as_raw()).rust_private_data.cast::<PrivateData>() };
+
+        private_data.probe_complete.wait_for_completion();
+
+        // SAFETY: No one has exclusive access to `private_data.error`.
+        if unsafe { *private_data.error.get() } {
+            return length;
+        }
+
+        // SAFETY: `receive_buf_callback` is only ever called after a successful call to
+        // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called
+        // and stored a `Pin<KBox<T>>`.
+        let data = unsafe { sdev.as_ref().drvdata_borrow::<T>() };
+
+        // SAFETY: `buf` is guaranteed to be non-null and has the size of `length`.
+        let buf = unsafe { core::slice::from_raw_parts(buf, length) };
+
+        T::receive(sdev, data, buf)
+    }
+}
+
+impl<T: Driver + 'static> driver::Adapter for Adapter<T> {
+    type IdInfo = T::IdInfo;
+
+    fn of_id_table() -> Option<of::IdTable<Self::IdInfo>> {
+        T::OF_ID_TABLE
+    }
+
+    fn acpi_id_table() -> Option<acpi::IdTable<Self::IdInfo>> {
+        T::ACPI_ID_TABLE
+    }
+}
+
+/// Declares a kernel module that exposes a single serial device bus device driver.
+///
+/// # Examples
+///
+/// ```ignore
+/// kernel::module_serdev_device_driver! {
+///     type: MyDriver,
+///     name: "Module name",
+///     authors: ["Author name"],
+///     description: "Description",
+///     license: "GPL v2",
+/// }
+/// ```
+#[macro_export]
+macro_rules! module_serdev_device_driver {
+    ($($f:tt)*) => {
+        $crate::module_driver!(<T>, $crate::serdev::Adapter<T>, { $($f)* });
+    };
+}
+
+/// The serial device bus device driver trait.
+///
+/// Drivers must implement this trait in order to get a serial device bus device driver registered.
+///
+/// # Examples
+///
+///```
+/// # use kernel::{
+///     acpi,
+///     bindings,
+///     device::{
+///         Bound,
+///         Core, //
+///     },
+///     of,
+///     serdev, //
+/// };
+///
+/// struct MyDriver;
+///
+/// kernel::of_device_table!(
+///     OF_TABLE,
+///     MODULE_OF_TABLE,
+///     <MyDriver as serdev::Driver>::IdInfo,
+///     [
+///         (of::DeviceId::new(c"test,device"), ())
+///     ]
+/// );
+///
+/// kernel::acpi_device_table!(
+///     ACPI_TABLE,
+///     MODULE_ACPI_TABLE,
+///     <MyDriver as serdev::Driver>::IdInfo,
+///     [
+///         (acpi::DeviceId::new(c"LNUXBEEF"), ())
+///     ]
+/// );
+///
+/// #[vtable]
+/// impl serdev::Driver for MyDriver {
+///     type IdInfo = ();
+///     const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
+///     const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = Some(&ACPI_TABLE);
+///
+///     fn probe(
+///         sdev: &serdev::Device<Core>,
+///         _id_info: Option<&Self::IdInfo>,
+///     ) -> impl PinInit<Self, Error> {
+///         sdev.set_baudrate(115200);
+///         sdev.write_all(b"Hello\n", serdev::Timeout::Max)?;
+///         Ok(MyDriver)
+///     }
+/// }
+///```
+#[vtable]
+pub trait Driver: Send {
+    /// The type holding driver private data about each device id supported by the driver.
+    // TODO: Use associated_type_defaults once stabilized:
+    //
+    // ```
+    // type IdInfo: 'static = ();
+    // ```
+    type IdInfo: 'static;
+
+    /// The table of OF device ids supported by the driver.
+    const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = None;
+
+    /// The table of ACPI device ids supported by the driver.
+    const ACPI_ID_TABLE: Option<acpi::IdTable<Self::IdInfo>> = None;
+
+    /// Serial device bus device driver probe.
+    ///
+    /// Called when a new serial device bus device is added or discovered.
+    /// Implementers should attempt to initialize the device here.
+    fn probe(
+        sdev: &Device<device::Core>,
+        id_info: Option<&Self::IdInfo>,
+    ) -> impl PinInit<Self, Error>;
+
+    /// Serial device bus device driver unbind.
+    ///
+    /// Called when a [`Device`] is unbound from its bound [`Driver`]. Implementing this callback
+    /// is optional.
+    ///
+    /// This callback serves as a place for drivers to perform teardown operations that require a
+    /// `&Device<Core>` or `&Device<Bound>` reference. For instance.
+    ///
+    /// Otherwise, release operations for driver resources should be performed in `Self::drop`.
+    fn unbind(sdev: &Device<device::Core>, this: Pin<&Self>) {
+        let _ = (sdev, this);
+    }
+
+    /// Serial device bus device data receive callback.
+    ///
+    /// Called when data got received from device.
+    ///
+    /// Returns the number of bytes accepted.
+    fn receive(sdev: &Device<device::Bound>, this: Pin<&Self>, data: &[u8]) -> usize {
+        let _ = (sdev, this, data);
+        build_error!(VTABLE_DEFAULT_ERROR)
+    }
+}
+
+/// The serial device bus device representation.
+///
+/// This structure represents the Rust abstraction for a C `struct serdev_device`. The
+/// implementation abstracts the usage of an already existing C `struct serdev_device` within Rust
+/// code that we get passed from the C side.
+///
+/// # Invariants
+///
+/// A [`Device`] instance represents a valid `struct serdev_device` created by the C portion of
+/// the kernel.
+#[repr(transparent)]
+pub struct Device<Ctx: device::DeviceContext = device::Normal>(
+    Opaque<bindings::serdev_device>,
+    PhantomData<Ctx>,
+);
+
+impl<Ctx: device::DeviceContext> Device<Ctx> {
+    fn as_raw(&self) -> *mut bindings::serdev_device {
+        self.0.get()
+    }
+}
+
+impl Device<device::Bound> {
+    /// Set the baudrate in bits per second.
+    ///
+    /// Common baudrates are 115200, 9600, 19200, 57600, 4800.
+    ///
+    /// Use [`Device::write_flush`] before calling this if you have written data prior to this call.
+    pub fn set_baudrate(&self, speed: u32) -> Result<(), u32> {
+        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `serdev_device`.
+        let ret = unsafe { bindings::serdev_device_set_baudrate(self.as_raw(), speed) };
+        if ret == speed {
+            Ok(())
+        } else {
+            Err(ret)
+        }
+    }
+
+    /// Set if flow control should be enabled.
+    ///
+    /// Use [`Device::write_flush`] before calling this if you have written data prior to this call.
+    pub fn set_flow_control(&self, enable: bool) {
+        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `serdev_device`.
+        unsafe { bindings::serdev_device_set_flow_control(self.as_raw(), enable) };
+    }
+
+    /// Set parity to use.
+    ///
+    /// Use [`Device::write_flush`] before calling this if you have written data prior to this call.
+    pub fn set_parity(&self, parity: Parity) -> Result {
+        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `serdev_device`.
+        to_result(unsafe { bindings::serdev_device_set_parity(self.as_raw(), parity as u32) })
+    }
+
+    /// Write data to the serial device until the controller has accepted all the data or has
+    /// been interrupted by a timeout or signal.
+    ///
+    /// Note that any accepted data has only been buffered by the controller. Use
+    /// [`Device::wait_until_sent`] to make sure the controller write buffer has actually been
+    /// emptied.
+    ///
+    /// Returns the number of bytes written (less than `data.len()` if interrupted).
+    /// [`kernel::error::code::ETIMEDOUT`] or [`kernel::error::code::ERESTARTSYS`] if interrupted
+    /// before any bytes were written.
+    pub fn write_all(&self, data: &[u8], timeout: Timeout) -> Result<usize> {
+        // SAFETY:
+        // - `self.as_raw()` is guaranteed to be a pointer to a valid `serdev_device`.
+        // - `data.as_ptr()` is guaranteed to be a valid array pointer with the size of
+        //   `data.len()`.
+        let ret = unsafe {
+            bindings::serdev_device_write(
+                self.as_raw(),
+                data.as_ptr(),
+                data.len(),
+                timeout.into_jiffies(),
+            )
+        };
+        // CAST: negative return values are guaranteed to be between `-MAX_ERRNO` and `-1`,
+        // which always fit into a `i32`.
+        to_result(ret as i32).map(|()| ret.unsigned_abs())
+    }
+
+    /// Write data to the serial device.
+    ///
+    /// If you want to write until the controller has accepted all the data, use
+    /// [`Device::write_all`].
+    ///
+    /// Note that any accepted data has only been buffered by the controller. Use
+    /// [ Device::wait_until_sent`] to make sure the controller write buffer has actually been
+    /// emptied.
+    ///
+    /// Returns the number of bytes written (less than `data.len()` if not enough room in the
+    /// write buffer).
+    pub fn write(&self, data: &[u8]) -> Result<u32> {
+        // SAFETY:
+        // - `self.as_raw()` is guaranteed to be a pointer to a valid `serdev_device`.
+        // - `data.as_ptr()` is guaranteed to be a valid array pointer with the size of
+        //   `data.len()`.
+        let ret =
+            unsafe { bindings::serdev_device_write_buf(self.as_raw(), data.as_ptr(), data.len()) };
+
+        to_result(ret as i32).map(|()| ret.unsigned_abs())
+    }
+
+    /// Send data to the serial device immediately.
+    ///
+    /// Note that this doesn't guarantee that the data has been transmitted.
+    /// Use [`Device::wait_until_sent`] for this purpose.
+    pub fn write_flush(&self) {
+        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `serdev_device`.
+        unsafe { bindings::serdev_device_write_flush(self.as_raw()) };
+    }
+
+    /// Wait for the data to be sent.
+    ///
+    /// After this function, the write buffer of the controller should be empty.
+    pub fn wait_until_sent(&self, timeout: Timeout) {
+        // SAFETY: `self.as_raw()` is guaranteed to be a pointer to a valid `serdev_device`.
+        unsafe { bindings::serdev_device_wait_until_sent(self.as_raw(), timeout.into_jiffies()) };
+    }
+}
+
+// SAFETY: `serdev::Device` is a transparent wrapper of `struct serdev_device`.
+// The offset is guaranteed to point to a valid device field inside `serdev::Device`.
+unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Device<Ctx> {
+    const OFFSET: usize = offset_of!(bindings::serdev_device, dev);
+}
+
+// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
+// argument.
+kernel::impl_device_context_deref!(unsafe { Device });
+kernel::impl_device_context_into_aref!(Device);
+
+// SAFETY: Instances of `Device` are always reference-counted.
+unsafe impl AlwaysRefCounted for Device {
+    fn inc_ref(&self) {
+        self.as_ref().inc_ref();
+    }
+
+    unsafe fn dec_ref(obj: NonNull<Self>) {
+        // SAFETY: The safety requirements guarantee that the refcount is non-zero.
+        unsafe { bindings::serdev_device_put(obj.cast().as_ptr()) }
+    }
+}
+
+impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
+    fn as_ref(&self) -> &device::Device<Ctx> {
+        // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
+        // `struct serdev_device`.
+        let dev = unsafe { &raw mut (*self.as_raw()).dev };
+
+        // SAFETY: `dev` points to a valid `struct device`.
+        unsafe { device::Device::from_raw(dev) }
+    }
+}
+
+// SAFETY: A `Device` is always reference-counted and can be released from any thread.
+unsafe impl Send for Device {}
+
+// SAFETY: `Device` can be shared among threads because all methods of `Device`
+// (i.e. `Device<Normal>) are thread safe.
+unsafe impl Sync for Device {}

-- 
2.52.0


^ permalink raw reply related

* [PATCH v5 2/4] serdev: add rust private data to serdev_device
From: Markus Probst @ 2026-04-20 20:07 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Jiri Slaby, Miguel Ojeda,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Kari Argillander,
	Rafael J. Wysocki, Viresh Kumar, Boqun Feng, David Airlie,
	Simona Vetter, Boqun Feng
  Cc: linux-serial, linux-kernel, rust-for-linux, linux-pm, driver-core,
	dri-devel, Markus Probst
In-Reply-To: <20260420-rust_serdev-v5-0-57e8ba0519f3@posteo.de>

Add rust private data to `struct serdev_device`, as it is required by the
rust abstraction added in the following commit
(rust: add basic serial device bus abstractions).

Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
 include/linux/serdev.h | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/include/linux/serdev.h b/include/linux/serdev.h
index 5654c58eb73c..c74c345d60ae 100644
--- a/include/linux/serdev.h
+++ b/include/linux/serdev.h
@@ -33,12 +33,14 @@ struct serdev_device_ops {
 
 /**
  * struct serdev_device - Basic representation of an serdev device
- * @dev:	Driver model representation of the device.
- * @nr:		Device number on serdev bus.
- * @ctrl:	serdev controller managing this device.
- * @ops:	Device operations.
- * @write_comp	Completion used by serdev_device_write() internally
- * @write_lock	Lock to serialize access when writing data
+ * @dev:	       Driver model representation of the device.
+ * @nr:		       Device number on serdev bus.
+ * @ctrl:	       serdev controller managing this device.
+ * @ops:	       Device operations.
+ * @write_comp:	       Completion used by serdev_device_write() internally
+ * @write_lock:	       Lock to serialize access when writing data
+ * @rust_private_data: Private data for the rust abstraction. This should
+ *		       not be used by the C drivers.
  */
 struct serdev_device {
 	struct device dev;
@@ -47,6 +49,7 @@ struct serdev_device {
 	const struct serdev_device_ops *ops;
 	struct completion write_comp;
 	struct mutex write_lock;
+	void *rust_private_data;
 };
 
 static inline struct serdev_device *to_serdev_device(struct device *d)

-- 
2.52.0


^ permalink raw reply related

* [PATCH v5 1/4] rust: devres: return reference in `devres::register`
From: Markus Probst @ 2026-04-20 20:07 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Jiri Slaby, Miguel Ojeda,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Kari Argillander,
	Rafael J. Wysocki, Viresh Kumar, Boqun Feng, David Airlie,
	Simona Vetter, Boqun Feng
  Cc: linux-serial, linux-kernel, rust-for-linux, linux-pm, driver-core,
	dri-devel, Markus Probst
In-Reply-To: <20260420-rust_serdev-v5-0-57e8ba0519f3@posteo.de>

Return the reference to the initialized data in the `devres::register`
function.

This is needed in a following commit (rust: add basic serial device bus
abstractions).

Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
 rust/kernel/cpufreq.rs    |  3 ++-
 rust/kernel/devres.rs     | 15 +++++++++++++--
 rust/kernel/drm/driver.rs |  3 ++-
 3 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs
index f5adee48d40c..31bf7e685097 100644
--- a/rust/kernel/cpufreq.rs
+++ b/rust/kernel/cpufreq.rs
@@ -1052,7 +1052,8 @@ pub fn new_foreign_owned(dev: &Device<Bound>) -> Result
     where
         T: 'static,
     {
-        devres::register(dev, Self::new()?, GFP_KERNEL)
+        devres::register(dev, Self::new()?, GFP_KERNEL)?;
+        Ok(())
     }
 }
 
diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
index 6afe196be42c..f882bace8601 100644
--- a/rust/kernel/devres.rs
+++ b/rust/kernel/devres.rs
@@ -326,15 +326,26 @@ fn register_foreign<P>(dev: &Device<Bound>, data: P) -> Result
 /// }
 ///
 /// fn from_bound_context(dev: &Device<Bound>) -> Result {
-///     devres::register(dev, Registration::new(), GFP_KERNEL)
+///     devres::register(dev, Registration::new(), GFP_KERNEL)?;
+///     Ok(())
 /// }
 /// ```
-pub fn register<T, E>(dev: &Device<Bound>, data: impl PinInit<T, E>, flags: Flags) -> Result
+pub fn register<'a, T, E>(
+    dev: &'a Device<Bound>,
+    data: impl PinInit<T, E>,
+    flags: Flags,
+) -> Result<&'a T>
 where
     T: Send + 'static,
     Error: From<E>,
 {
     let data = KBox::pin_init(data, flags)?;
 
+    let data_ptr = &raw const *data;
+
     register_foreign(dev, data)
+        // SAFETY: `dev` is valid for the lifetime of 'a. As long as there is a reference to
+        // `Device<Bound>`, it is guaranteed that the device is not unbound and data has not been
+        // dropped. Thus `data_ptr` is also valid for the lifetime of 'a.
+        .map(|()| unsafe { &*data_ptr })
 }
diff --git a/rust/kernel/drm/driver.rs b/rust/kernel/drm/driver.rs
index e09f977b5b51..51e0c7e30cc2 100644
--- a/rust/kernel/drm/driver.rs
+++ b/rust/kernel/drm/driver.rs
@@ -145,7 +145,8 @@ pub fn new_foreign_owned(
 
         let reg = Registration::<T>::new(drm, flags)?;
 
-        devres::register(dev, reg, GFP_KERNEL)
+        devres::register(dev, reg, GFP_KERNEL)?;
+        Ok(())
     }
 
     /// Returns a reference to the `Device` instance for this registration.

-- 
2.52.0


^ permalink raw reply related

* [PATCH v5 0/4] rust: add basic serial device bus abstractions
From: Markus Probst @ 2026-04-20 20:07 UTC (permalink / raw)
  To: Rob Herring, Greg Kroah-Hartman, Jiri Slaby, Miguel Ojeda,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Kari Argillander,
	Rafael J. Wysocki, Viresh Kumar, Boqun Feng, David Airlie,
	Simona Vetter, Boqun Feng
  Cc: linux-serial, linux-kernel, rust-for-linux, linux-pm, driver-core,
	dri-devel, Markus Probst

This patch series adds the serdev device bus rust abstraction into the
kernel.

This abstraction will be used by a driver,
which targets the MCU devices in Synology devices.

Kari Argillander also messaged me, stating that he wants to write a
watchdog driver with this abstraction (needing initial device data).

@Rob: Are you willing to maintain these rust abstractions yourself,
as you are the expert on this subsystem, otherwise I would take care of
it with a "SERIAL DEVICE BUS [RUST]" section in the MAINTAINERS file. In
the second case, I assume you are going to pick those patches as-is into
your tree, after they have been reviewed?

Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
Changes in v5:
- fix typo in documentation
- Link to v4: https://lore.kernel.org/r/20260411-rust_serdev-v4-0-845e960c6627@posteo.de

Changes in v4:
- fixed not selecting rust serdev abstraction in sample
- Link to v3: https://lore.kernel.org/r/20260313-rust_serdev-v3-0-c9a3af214f7f@posteo.de

Changes in v3:
- fix vertical import style
- add Kconfig entry for the rust abstraction
- fix documentation in include/linux/serdev.h
- rename private_data to rust_private_data
- fix `complete_all` <-> `wait_for_completion` typo
- move drvdata_borrow call after the completion
- Link to v2: https://lore.kernel.org/r/20260306-rust_serdev-v2-0-e9b23b42b255@posteo.de

Changes in v2:
- fix documentation in `serdev::Driver::write` and
  `serdev::Driver::write_all`
- remove use of `dev_info` in probe from the sample
- remove `properties_parse` from the sample
- add optional `baudrate` property to the sample
- remove 1. patch
- remove `TryFrom<&device::Device<Ctx>> for &serdev::Device<Ctx>`
  implementation
- fix import style
- add patch to return reference in `devres::register` to fix safety
  issue
- add patch to add private data to serdev_device, to fix
  `Device.drvdata()` from failing
- simplify abstraction by removing ability to receive the initial
  transmission. It may be added later in a separate patch series if
  needed.
- Link to v1: https://lore.kernel.org/r/20251220-rust_serdev-v1-0-e44645767621@posteo.de

---
Markus Probst (4):
      rust: devres: return reference in `devres::register`
      serdev: add rust private data to serdev_device
      rust: add basic serial device bus abstractions
      samples: rust: add Rust serial device bus sample device driver

 drivers/tty/serdev/Kconfig         |   7 +
 include/linux/serdev.h             |  15 +-
 rust/bindings/bindings_helper.h    |   1 +
 rust/helpers/helpers.c             |   1 +
 rust/helpers/serdev.c              |  22 ++
 rust/kernel/cpufreq.rs             |   3 +-
 rust/kernel/devres.rs              |  15 +-
 rust/kernel/drm/driver.rs          |   3 +-
 rust/kernel/lib.rs                 |   2 +
 rust/kernel/serdev.rs              | 536 +++++++++++++++++++++++++++++++++++++
 samples/rust/Kconfig               |  11 +
 samples/rust/Makefile              |   1 +
 samples/rust/rust_driver_serdev.rs |  86 ++++++
 13 files changed, 693 insertions(+), 10 deletions(-)
---
base-commit: 3131ff5a117498bb4b9db3a238bb311cbf8383ce
change-id: 20251217-rust_serdev-ee5481e9085c


^ permalink raw reply

* Re: [PATCH] serial: 8250_pci: Consistently define pci_device_ids using named initializers
From: Andy Shevchenko @ 2026-04-20 18:32 UTC (permalink / raw)
  To: Uwe Kleine-König (The Capable Hub)
  Cc: Greg Kroah-Hartman, Jiri Slaby, Markus Schneider-Pargmann,
	linux-serial
In-Reply-To: <20260420175648.1709935-2-u.kleine-koenig@baylibre.com>

On Mon, Apr 20, 2026 at 07:56:48PM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> ... and PCI device helpers.
> 
> The various struct pci_device_id were defined using a mixture of
> initialization by position and by name. Some use the PCI device helpers
> (like PCI_DEVICE and PCI_DEVICE_SUB) and others don't.
> 
> Consistently use named initializers, drop assignments of 0 by position
> for .class and .class_mask and use the PCI device helpers. Also use
> consistent line-breaks and positioning for opening and closing curly
> braces.
> 
> The secret plan is to make struct pci_device_id::driver_data an
> anonymous union (similar to
> https://lore.kernel.org/all/cover.1776579304.git.u.kleine-koenig@baylibre.com/)
> and that requires named initializers. But it's also a nice cleanup on
> its own.

Can we rather switch to PCI_DEVICE_DATA() and perhaps you would like to have
PCI_DEVICE_SUB_DATA() implemented in the similar way.

This will shorten a lot the lines, the

		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232),
		.driver_data = pbn_b1_8_1382400,

to, for example,

		PCI_DEVICE_SUB_DATA(V3, V960, CONNECT_TECH, BH8_232, pbn_b1_8_1382400),

(Yes, in some cases, I guess blacklist mostly, it might require to have a
 common definition in pci_ids.h for both or more drivers. Or something like
 8250_pci_ids.h in the drivers/tty/serial/8250/ if the global one seems too
 much.)

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply

* [PATCH] serial: 8250_pci: Consistently define pci_device_ids using named initializers
From: Uwe Kleine-König (The Capable Hub) @ 2026-04-20 17:56 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby
  Cc: Andy Shevchenko, Markus Schneider-Pargmann, linux-serial

... and PCI device helpers.

The various struct pci_device_id were defined using a mixture of
initialization by position and by name. Some use the PCI device helpers
(like PCI_DEVICE and PCI_DEVICE_SUB) and others don't.

Consistently use named initializers, drop assignments of 0 by position
for .class and .class_mask and use the PCI device helpers. Also use
consistent line-breaks and positioning for opening and closing curly
braces.

The secret plan is to make struct pci_device_id::driver_data an
anonymous union (similar to
https://lore.kernel.org/all/cover.1776579304.git.u.kleine-koenig@baylibre.com/)
and that requires named initializers. But it's also a nice cleanup on
its own.

This patch doesn't change the compiled result; this was verified using
an amd64 allmodconfig with all debugging disabled.

Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
---
Hello,

I started to do what I did in the patch linked above for firewire also
for pci. The 8250_pci driver needs quite some massaging for that. As I
wouldn't be surprised if this commit creates some discussion (e.g.
because I failed at being really consistent here, or my consistency
doesn't match the desired consistency by others), I sent this patch out
early to have this discussion separate from the union change.

Best regards
Uwe

 drivers/tty/serial/8250/8250_pci.c | 2990 ++++++++++++++--------------
 1 file changed, 1549 insertions(+), 1441 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 6cfd1b2af5b7..303769643643 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -3992,42 +3992,42 @@ static const struct pci_device_id blacklist[] = {
 
 	/* multi-io cards handled by parport_serial */
 	/* WCH CH353 2S1P */
-	{ PCI_VDEVICE(WCHCN, 0x7053), REPORT_CONFIG(PARPORT_SERIAL), },
+	{ PCI_VDEVICE(WCHCN, 0x7053), .driver_data = REPORT_CONFIG(PARPORT_SERIAL), },
 	/* WCH CH353 1S1P */
-	{ PCI_VDEVICE(WCHCN, 0x5053), REPORT_CONFIG(PARPORT_SERIAL), },
+	{ PCI_VDEVICE(WCHCN, 0x5053), .driver_data = REPORT_CONFIG(PARPORT_SERIAL), },
 	/* WCH CH382 2S1P */
-	{ PCI_VDEVICE(WCHIC, 0x3250), REPORT_CONFIG(PARPORT_SERIAL), },
+	{ PCI_VDEVICE(WCHIC, 0x3250), .driver_data = REPORT_CONFIG(PARPORT_SERIAL), },
 
 	/* Intel platforms with MID UART */
-	{ PCI_VDEVICE(INTEL, 0x081b), REPORT_8250_CONFIG(MID), },
-	{ PCI_VDEVICE(INTEL, 0x081c), REPORT_8250_CONFIG(MID), },
-	{ PCI_VDEVICE(INTEL, 0x081d), REPORT_8250_CONFIG(MID), },
-	{ PCI_VDEVICE(INTEL, 0x1191), REPORT_8250_CONFIG(MID), },
-	{ PCI_VDEVICE(INTEL, 0x18d8), REPORT_8250_CONFIG(MID), },
-	{ PCI_VDEVICE(INTEL, 0x19d8), REPORT_8250_CONFIG(MID), },
+	{ PCI_VDEVICE(INTEL, 0x081b), .driver_data = REPORT_8250_CONFIG(MID), },
+	{ PCI_VDEVICE(INTEL, 0x081c), .driver_data = REPORT_8250_CONFIG(MID), },
+	{ PCI_VDEVICE(INTEL, 0x081d), .driver_data = REPORT_8250_CONFIG(MID), },
+	{ PCI_VDEVICE(INTEL, 0x1191), .driver_data = REPORT_8250_CONFIG(MID), },
+	{ PCI_VDEVICE(INTEL, 0x18d8), .driver_data = REPORT_8250_CONFIG(MID), },
+	{ PCI_VDEVICE(INTEL, 0x19d8), .driver_data = REPORT_8250_CONFIG(MID), },
 
 	/* Intel platforms with DesignWare UART */
-	{ PCI_VDEVICE(INTEL, 0x0936), REPORT_8250_CONFIG(LPSS), },
-	{ PCI_VDEVICE(INTEL, 0x0f0a), REPORT_8250_CONFIG(LPSS), },
-	{ PCI_VDEVICE(INTEL, 0x0f0c), REPORT_8250_CONFIG(LPSS), },
-	{ PCI_VDEVICE(INTEL, 0x228a), REPORT_8250_CONFIG(LPSS), },
-	{ PCI_VDEVICE(INTEL, 0x228c), REPORT_8250_CONFIG(LPSS), },
-	{ PCI_VDEVICE(INTEL, 0x4b96), REPORT_8250_CONFIG(LPSS), },
-	{ PCI_VDEVICE(INTEL, 0x4b97), REPORT_8250_CONFIG(LPSS), },
-	{ PCI_VDEVICE(INTEL, 0x4b98), REPORT_8250_CONFIG(LPSS), },
-	{ PCI_VDEVICE(INTEL, 0x4b99), REPORT_8250_CONFIG(LPSS), },
-	{ PCI_VDEVICE(INTEL, 0x4b9a), REPORT_8250_CONFIG(LPSS), },
-	{ PCI_VDEVICE(INTEL, 0x4b9b), REPORT_8250_CONFIG(LPSS), },
-	{ PCI_VDEVICE(INTEL, 0x9ce3), REPORT_8250_CONFIG(LPSS), },
-	{ PCI_VDEVICE(INTEL, 0x9ce4), REPORT_8250_CONFIG(LPSS), },
+	{ PCI_VDEVICE(INTEL, 0x0936), .driver_data = REPORT_8250_CONFIG(LPSS), },
+	{ PCI_VDEVICE(INTEL, 0x0f0a), .driver_data = REPORT_8250_CONFIG(LPSS), },
+	{ PCI_VDEVICE(INTEL, 0x0f0c), .driver_data = REPORT_8250_CONFIG(LPSS), },
+	{ PCI_VDEVICE(INTEL, 0x228a), .driver_data = REPORT_8250_CONFIG(LPSS), },
+	{ PCI_VDEVICE(INTEL, 0x228c), .driver_data = REPORT_8250_CONFIG(LPSS), },
+	{ PCI_VDEVICE(INTEL, 0x4b96), .driver_data = REPORT_8250_CONFIG(LPSS), },
+	{ PCI_VDEVICE(INTEL, 0x4b97), .driver_data = REPORT_8250_CONFIG(LPSS), },
+	{ PCI_VDEVICE(INTEL, 0x4b98), .driver_data = REPORT_8250_CONFIG(LPSS), },
+	{ PCI_VDEVICE(INTEL, 0x4b99), .driver_data = REPORT_8250_CONFIG(LPSS), },
+	{ PCI_VDEVICE(INTEL, 0x4b9a), .driver_data = REPORT_8250_CONFIG(LPSS), },
+	{ PCI_VDEVICE(INTEL, 0x4b9b), .driver_data = REPORT_8250_CONFIG(LPSS), },
+	{ PCI_VDEVICE(INTEL, 0x9ce3), .driver_data = REPORT_8250_CONFIG(LPSS), },
+	{ PCI_VDEVICE(INTEL, 0x9ce4), .driver_data = REPORT_8250_CONFIG(LPSS), },
 
 	/* Exar devices */
-	{ PCI_VDEVICE(EXAR, PCI_ANY_ID), REPORT_8250_CONFIG(EXAR), },
-	{ PCI_VDEVICE(COMMTECH, PCI_ANY_ID), REPORT_8250_CONFIG(EXAR), },
+	{ PCI_VDEVICE(EXAR, PCI_ANY_ID), .driver_data = REPORT_8250_CONFIG(EXAR), },
+	{ PCI_VDEVICE(COMMTECH, PCI_ANY_ID), .driver_data = REPORT_8250_CONFIG(EXAR), },
 
 	/* Pericom devices */
-	{ PCI_VDEVICE(PERICOM, PCI_ANY_ID), REPORT_8250_CONFIG(PERICOM), },
-	{ PCI_VDEVICE(ACCESSIO, PCI_ANY_ID), REPORT_8250_CONFIG(PERICOM), },
+	{ PCI_VDEVICE(PERICOM, PCI_ANY_ID), .driver_data = REPORT_8250_CONFIG(PERICOM), },
+	{ PCI_VDEVICE(ACCESSIO, PCI_ANY_ID), .driver_data = REPORT_8250_CONFIG(PERICOM), },
 
 	/* End of the black list */
 	{ }
@@ -4400,713 +4400,753 @@ static SIMPLE_DEV_PM_OPS(pciserial_pm_ops, pciserial_suspend_one,
 			 pciserial_resume_one);
 
 static const struct pci_device_id serial_pci_tbl[] = {
-	{	PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1600,
-		PCI_DEVICE_ID_ADVANTECH_PCI1600_1611, PCI_ANY_ID, 0, 0,
-		pbn_b0_4_921600 },
-	/* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */
-	{	PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,
-		PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0,
-		pbn_b2_8_921600 },
-	/* Advantech also use 0x3618 and 0xf618 */
-	{	PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3618,
-		PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0,
-		pbn_b0_4_921600 },
-	{	PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCIf618,
-		PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID, 0, 0,
-		pbn_b0_4_921600 },
-	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
-		pbn_b1_8_1382400 },
-	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
-		pbn_b1_4_1382400 },
-	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
-		pbn_b1_2_1382400 },
-	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
-		pbn_b1_8_1382400 },
-	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
-		pbn_b1_4_1382400 },
-	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
-		pbn_b1_2_1382400 },
-	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
-		pbn_b1_8_921600 },
-	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
-		pbn_b1_8_921600 },
-	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
-		pbn_b1_4_921600 },
-	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
-		pbn_b1_4_921600 },
-	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
-		pbn_b1_2_921600 },
-	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
-		pbn_b1_8_921600 },
-	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
-		pbn_b1_8_921600 },
-	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
-		pbn_b1_4_921600 },
-	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ, 0, 0,
-		pbn_b1_2_1250000 },
-	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2, 0, 0,
-		pbn_b0_2_1843200 },
-	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-		PCI_SUBVENDOR_ID_CONNECT_TECH,
-		PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4, 0, 0,
-		pbn_b0_4_1843200 },
-	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-		PCI_VENDOR_ID_AFAVLAB,
-		PCI_SUBDEVICE_ID_AFAVLAB_P061, 0, 0,
-		pbn_b0_4_1152000 },
-	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_bt_1_115200 },
-	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_bt_2_115200 },
-	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_bt_4_115200 },
-	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_bt_2_115200 },
-	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_bt_4_115200 },
-	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_8_115200 },
-	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_8_460800 },
-	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_8_115200 },
+	{
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI1600,
+			       PCI_DEVICE_ID_ADVANTECH_PCI1600_1611, PCI_ANY_ID),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		/* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620,
+			       PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001),
+		.driver_data = pbn_b2_8_921600,
+	}, {
+		/* Advantech also use 0x3618 and 0xf618 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3618,
+			       PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCIf618,
+			       PCI_DEVICE_ID_ADVANTECH_PCI3618, PCI_ANY_ID),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232),
+		.driver_data = pbn_b1_8_1382400,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232),
+		.driver_data = pbn_b1_4_1382400,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232),
+		.driver_data = pbn_b1_2_1382400,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232),
+		.driver_data = pbn_b1_8_1382400,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232),
+		.driver_data = pbn_b1_4_1382400,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232),
+		.driver_data = pbn_b1_2_1382400,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485),
+		.driver_data = pbn_b1_8_921600,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4),
+		.driver_data = pbn_b1_8_921600,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485),
+		.driver_data = pbn_b1_4_921600,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2),
+		.driver_data = pbn_b1_4_921600,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485),
+		.driver_data = pbn_b1_2_921600,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6),
+		.driver_data = pbn_b1_8_921600,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1),
+		.driver_data = pbn_b1_8_921600,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1),
+		.driver_data = pbn_b1_4_921600,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ),
+		.driver_data = pbn_b1_2_1250000,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2),
+		.driver_data = pbn_b0_2_1843200,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+			       PCI_SUBVENDOR_ID_CONNECT_TECH, PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4),
+		.driver_data = pbn_b0_4_1843200,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+			       PCI_VENDOR_ID_AFAVLAB, PCI_SUBDEVICE_ID_AFAVLAB_P061),
+		.driver_data = pbn_b0_4_1152000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530),
+		.driver_data = pbn_b2_bt_1_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2),
+		.driver_data = pbn_b2_bt_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422),
+		.driver_data = pbn_b2_bt_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232),
+		.driver_data = pbn_b2_bt_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4),
+		.driver_data = pbn_b2_bt_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8),
+		.driver_data = pbn_b2_8_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803),
+		.driver_data = pbn_b2_8_460800,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8),
+		.driver_data = pbn_b2_8_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2),
+		.driver_data = pbn_b2_bt_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200),
+		.driver_data = pbn_b2_bt_2_921600,
+	}, {
+		/* VScom SPCOM800, from sl@s.pl */
+		PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800),
+		.driver_data = pbn_b2_8_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077),
+		.driver_data = pbn_b2_4_921600,
+	}, {
+		/* Unknown card - subdevice 0x1584 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+			       PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_UNKNOWN_0x1584),
+		.driver_data = pbn_b2_4_115200,
+	}, {
+		/* Unknown card - subdevice 0x1588 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+			       PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_UNKNOWN_0x1588),
+		.driver_data = pbn_b2_8_115200,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+			       PCI_SUBVENDOR_ID_KEYSPAN, PCI_SUBDEVICE_ID_KEYSPAN_SX2),
+		.driver_data = pbn_panacom,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM),
+		.driver_data = pbn_panacom4,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM),
+		.driver_data = pbn_panacom2,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+			       PCI_VENDOR_ID_ESDGMBH, PCI_DEVICE_ID_ESDGMBH_CPCIASIO4),
+		.driver_data = pbn_b2_4_115200,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+			       PCI_SUBVENDOR_ID_CHASE_PCIFAST, PCI_SUBDEVICE_ID_CHASE_PCIFAST4),
+		.driver_data = pbn_b2_4_460800,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+			       PCI_SUBVENDOR_ID_CHASE_PCIFAST, PCI_SUBDEVICE_ID_CHASE_PCIFAST8),
+		.driver_data = pbn_b2_8_460800,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+			       PCI_SUBVENDOR_ID_CHASE_PCIFAST, PCI_SUBDEVICE_ID_CHASE_PCIFAST16),
+		.driver_data = pbn_b2_16_460800,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+			       PCI_SUBVENDOR_ID_CHASE_PCIFAST, PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC),
+		.driver_data = pbn_b2_16_460800,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+			       PCI_SUBVENDOR_ID_CHASE_PCIRAS, PCI_SUBDEVICE_ID_CHASE_PCIRAS4),
+		.driver_data = pbn_b2_4_460800,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+			       PCI_SUBVENDOR_ID_CHASE_PCIRAS, PCI_SUBDEVICE_ID_CHASE_PCIRAS8),
+		.driver_data = pbn_b2_8_460800,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+			       PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4055),
+		.driver_data = pbn_b2_4_115200,
+	}, {
+		/*
+		 * Megawolf Romulus PCI Serial Card, from Mike Hudson
+		 * (Exoray@isys.ca)
+		 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
+			       0x10b5, 0x106a),
+		.driver_data = pbn_plx_romulus,
+	},
 
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_bt_2_115200 },
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_bt_2_921600 },
-	/*
-	 * VScom SPCOM800, from sl@s.pl
-	 */
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_8_921600 },
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_4_921600 },
-	/* Unknown card - subdevice 0x1584 */
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-		PCI_VENDOR_ID_PLX,
-		PCI_SUBDEVICE_ID_UNKNOWN_0x1584, 0, 0,
-		pbn_b2_4_115200 },
-	/* Unknown card - subdevice 0x1588 */
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-		PCI_VENDOR_ID_PLX,
-		PCI_SUBDEVICE_ID_UNKNOWN_0x1588, 0, 0,
-		pbn_b2_8_115200 },
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-		PCI_SUBVENDOR_ID_KEYSPAN,
-		PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
-		pbn_panacom },
-	{	PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_panacom4 },
-	{	PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_panacom2 },
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
-		PCI_VENDOR_ID_ESDGMBH,
-		PCI_DEVICE_ID_ESDGMBH_CPCIASIO4, 0, 0,
-		pbn_b2_4_115200 },
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-		PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0,
-		pbn_b2_4_460800 },
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-		PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0,
-		pbn_b2_8_460800 },
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-		PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0,
-		pbn_b2_16_460800 },
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
-		PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0,
-		pbn_b2_16_460800 },
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-		PCI_SUBVENDOR_ID_CHASE_PCIRAS,
-		PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0,
-		pbn_b2_4_460800 },
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-		PCI_SUBVENDOR_ID_CHASE_PCIRAS,
-		PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0,
-		pbn_b2_8_460800 },
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
-		PCI_SUBVENDOR_ID_EXSYS,
-		PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0,
-		pbn_b2_4_115200 },
-	/*
-	 * Megawolf Romulus PCI Serial Card, from Mike Hudson
-	 * (Exoray@isys.ca)
-	 */
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
-		0x10b5, 0x106a, 0, 0,
-		pbn_plx_romulus },
 	/*
 	 * Quatech cards. These actually have configurable clocks but for
 	 * now we just use the default.
 	 *
 	 * 100 series are RS232, 200 series RS422,
 	 */
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_4_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_2_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100E,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_2_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200E,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC200,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_4_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_8_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_8_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP100,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_4_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP100,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_2_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP200,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_4_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP200,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_2_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP100,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_4_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP100,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP100,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_1_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP200,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_4_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP200,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP200,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_1_115200 },
-	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESCLP100,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_8_115200 },
-
-	{	PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
-		PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4,
-		0, 0,
-		pbn_b0_4_921600 },
-	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-		PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL,
-		0, 0,
-		pbn_b0_4_1152000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0x9505,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_2_921600 },
-
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100),
+		.driver_data = pbn_b1_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100),
+		.driver_data = pbn_b1_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100E),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200),
+		.driver_data = pbn_b1_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200E),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC200),
+		.driver_data = pbn_b1_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D),
+		.driver_data = pbn_b1_8_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M),
+		.driver_data = pbn_b1_8_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP100),
+		.driver_data = pbn_b1_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP100),
+		.driver_data = pbn_b1_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP200),
+		.driver_data = pbn_b1_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP200),
+		.driver_data = pbn_b1_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP100),
+		.driver_data = pbn_b2_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP100),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP100),
+		.driver_data = pbn_b2_1_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP200),
+		.driver_data = pbn_b2_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP200),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP200),
+		.driver_data = pbn_b2_1_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESCLP100),
+		.driver_data = pbn_b0_8_115200,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
+			       PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+			       PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL),
+		.driver_data = pbn_b0_4_1152000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0x9505),
+		.driver_data = pbn_b0_bt_2_921600,
+	}, {
 		/*
 		 * The below card is a little controversial since it is the
 		 * subject of a PCI vendor/device ID clash.  (See
 		 * www.ussg.iu.edu/hypermail/linux/kernel/0303.1/0516.html).
 		 * For now just used the hex ID 0x950a.
 		 */
-	{	PCI_VENDOR_ID_OXSEMI, 0x950a,
-		PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_00,
-		0, 0, pbn_b0_2_115200 },
-	{	PCI_VENDOR_ID_OXSEMI, 0x950a,
-		PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_30,
-		0, 0, pbn_b0_2_115200 },
-	{	PCI_VENDOR_ID_OXSEMI, 0x950a,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_2_1130000 },
-	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950,
-		PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0,
-		pbn_b0_1_921600 },
-	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_4_115200 },
-	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_2_921600 },
-	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_8_1152000 },
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_OXSEMI, 0x950a,
+			       PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_00),
+		.driver_data = pbn_b0_2_115200,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_OXSEMI, 0x950a,
+			       PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_30),
+		.driver_data = pbn_b0_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0x950a),
+		.driver_data = pbn_b0_2_1130000,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950,
+			       PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950),
+		.driver_data = pbn_b0_1_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954),
+		.driver_data = pbn_b0_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952),
+		.driver_data = pbn_b0_bt_2_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958),
+		.driver_data = pbn_b2_8_1152000,
+	},
 
 	/*
 	 * Oxford Semiconductor Inc. Tornado PCI express device range.
 	 */
-	{	PCI_VENDOR_ID_OXSEMI, 0xc101,    /* OXPCIe952 1 Legacy UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc105,    /* OXPCIe952 1 Legacy UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc11b,    /* OXPCIe952 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc11f,    /* OXPCIe952 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc120,    /* OXPCIe952 1 Legacy UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc124,    /* OXPCIe952 1 Legacy UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc138,    /* OXPCIe952 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc13d,    /* OXPCIe952 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc140,    /* OXPCIe952 1 Legacy UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc141,    /* OXPCIe952 1 Legacy UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc144,    /* OXPCIe952 1 Legacy UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc145,    /* OXPCIe952 1 Legacy UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc158,    /* OXPCIe952 2 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_2_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc15d,    /* OXPCIe952 2 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_2_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc208,    /* OXPCIe954 4 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_4_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc20d,    /* OXPCIe954 4 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_4_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc308,    /* OXPCIe958 8 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_8_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc30d,    /* OXPCIe958 8 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_8_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc40b,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc40f,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc41b,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc41f,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc42b,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc42f,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc43b,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc43f,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc44b,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc44f,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc45b,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc45f,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc46b,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc46f,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc47b,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc47f,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc48b,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc48f,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc49b,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc49f,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc4ab,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc4af,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc4bb,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc4bf,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc4cb,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_OXSEMI, 0xc4cf,    /* OXPCIe200 1 Native UART */
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_1_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc101),    /* OXPCIe952 1 Legacy UART */
+		.driver_data = pbn_b0_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc105),    /* OXPCIe952 1 Legacy UART */
+		.driver_data = pbn_b0_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc11b),    /* OXPCIe952 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc11f),    /* OXPCIe952 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc120),    /* OXPCIe952 1 Legacy UART */
+		.driver_data = pbn_b0_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc124),    /* OXPCIe952 1 Legacy UART */
+		.driver_data = pbn_b0_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc138),    /* OXPCIe952 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc13d),    /* OXPCIe952 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc140),    /* OXPCIe952 1 Legacy UART */
+		.driver_data = pbn_b0_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc141),    /* OXPCIe952 1 Legacy UART */
+		.driver_data = pbn_b0_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc144),    /* OXPCIe952 1 Legacy UART */
+		.driver_data = pbn_b0_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc145),    /* OXPCIe952 1 Legacy UART */
+		.driver_data = pbn_b0_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc158),    /* OXPCIe952 2 Native UART */
+		.driver_data = pbn_oxsemi_2_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc15d),    /* OXPCIe952 2 Native UART */
+		.driver_data = pbn_oxsemi_2_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc208),    /* OXPCIe954 4 Native UART */
+		.driver_data = pbn_oxsemi_4_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc20d),    /* OXPCIe954 4 Native UART */
+		.driver_data = pbn_oxsemi_4_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc308),    /* OXPCIe958 8 Native UART */
+		.driver_data = pbn_oxsemi_8_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc30d),    /* OXPCIe958 8 Native UART */
+		.driver_data = pbn_oxsemi_8_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc40b),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc40f),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc41b),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc41f),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc42b),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc42f),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc43b),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc43f),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc44b),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc44f),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc45b),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc45f),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc46b),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc46f),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc47b),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc47f),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc48b),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc48f),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc49b),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc49f),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc4ab),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc4af),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc4bb),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc4bf),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc4cb),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, 0xc4cf),    /* OXPCIe200 1 Native UART */
+		.driver_data = pbn_oxsemi_1_15625000,
+	},
 	/*
 	 * Mainpine Inc. IQ Express "Rev3" utilizing OxSemi Tornado
 	 */
-	{	PCI_VENDOR_ID_MAINPINE, 0x4000,	/* IQ Express 1 Port V.34 Super-G3 Fax */
-		PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0,
-		pbn_oxsemi_1_15625000 },
-	{	PCI_VENDOR_ID_MAINPINE, 0x4000,	/* IQ Express 2 Port V.34 Super-G3 Fax */
-		PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0,
-		pbn_oxsemi_2_15625000 },
-	{	PCI_VENDOR_ID_MAINPINE, 0x4000,	/* IQ Express 4 Port V.34 Super-G3 Fax */
-		PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0,
-		pbn_oxsemi_4_15625000 },
-	{	PCI_VENDOR_ID_MAINPINE, 0x4000,	/* IQ Express 8 Port V.34 Super-G3 Fax */
-		PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0,
-		pbn_oxsemi_8_15625000 },
+	{
+		/* IQ Express 1 Port V.34 Super-G3 Fax */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, 0x4000,
+			       PCI_VENDOR_ID_MAINPINE, 0x4001),
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		/* IQ Express 2 Port V.34 Super-G3 Fax */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, 0x4000,
+			       PCI_VENDOR_ID_MAINPINE, 0x4002),
+		.driver_data = pbn_oxsemi_2_15625000,
+	}, {
+		/* IQ Express 4 Port V.34 Super-G3 Fax */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, 0x4000,
+			       PCI_VENDOR_ID_MAINPINE, 0x4004),
+		.driver_data = pbn_oxsemi_4_15625000,
+	}, {
+		/* IQ Express 8 Port V.34 Super-G3 Fax */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, 0x4000,
+			       PCI_VENDOR_ID_MAINPINE, 0x4008),
+		.driver_data = pbn_oxsemi_8_15625000,
+	},
 
 	/*
 	 * Digi/IBM PCIe 2-port Async EIA-232 Adapter utilizing OxSemi Tornado
 	 */
-	{	PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_2_OX_IBM,
-		PCI_SUBVENDOR_ID_IBM, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_2_15625000 },
+	{
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_2_OX_IBM,
+			       PCI_SUBVENDOR_ID_IBM, PCI_ANY_ID),
+		.driver_data = pbn_oxsemi_2_15625000,
+	},
+
 	/*
 	 * EndRun Technologies. PCI express device range.
 	 * EndRun PTP/1588 has 2 Native UARTs utilizing OxSemi 952.
 	 */
-	{	PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi_2_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588),
+		.driver_data = pbn_oxsemi_2_15625000,
+	},
 
 	/*
 	 * SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards,
 	 * from skokodyn@yahoo.com
 	 */
-	{	PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
-		PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO232, 0, 0,
-		pbn_sbsxrsio },
-	{	PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
-		PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO422, 0, 0,
-		pbn_sbsxrsio },
-	{	PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
-		PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL232, 0, 0,
-		pbn_sbsxrsio },
-	{	PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
-		PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL422, 0, 0,
-		pbn_sbsxrsio },
+	{
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+			       PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO232),
+		.driver_data = pbn_sbsxrsio,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+			       PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_OCTPRO422),
+		.driver_data = pbn_sbsxrsio,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+			       PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL232),
+		.driver_data = pbn_sbsxrsio,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_SBSMODULARIO, PCI_DEVICE_ID_OCTPRO,
+			       PCI_SUBVENDOR_ID_SBSMODULARIO, PCI_SUBDEVICE_ID_POCTAL422),
+		.driver_data = pbn_sbsxrsio,
+	},
 
 	/*
 	 * Digitan DS560-558, from jimd@esoft.com
 	 */
-	{	PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_1_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM),
+		.driver_data = pbn_b1_1_115200,
+	},
 
 	/*
 	 * Titan Electronic cards
 	 *  The 400L and 800L have a custom setup quirk.
 	 */
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_1_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_2_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_4_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_4_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_1_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_bt_2_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_4_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_8_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200I,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b4_bt_2_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400I,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b4_bt_4_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800I,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b4_bt_8_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400EH,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_4_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EH,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_4_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EHB,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_4_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_titan_1_4000000 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_titan_2_4000000 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_titan_4_4000000 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_titan_8_4000000 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_titan_2_4000000 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_titan_2_4000000 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200V3,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_2_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400V3,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_4_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_410V3,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_4_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800V3,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_4_921600 },
-	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800V3B,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_4_921600 },
-
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_1_460800 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_1_460800 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_1_460800 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_bt_2_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_bt_2_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_bt_2_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_bt_4_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_bt_4_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_bt_4_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_1_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_1_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_1_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_2_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_2_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_2_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_4_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_4_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_4_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_550,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_8_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_650,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_8_921600 },
-	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_850,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_8_921600 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100),
+		.driver_data = pbn_b0_1_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200),
+		.driver_data = pbn_b0_2_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L),
+		.driver_data = pbn_b1_1_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L),
+		.driver_data = pbn_b1_bt_2_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L),
+		.driver_data = pbn_b0_bt_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L),
+		.driver_data = pbn_b0_bt_8_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200I),
+		.driver_data = pbn_b4_bt_2_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400I),
+		.driver_data = pbn_b4_bt_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800I),
+		.driver_data = pbn_b4_bt_8_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400EH),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EH),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EHB),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E),
+		.driver_data = pbn_titan_1_4000000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E),
+		.driver_data = pbn_titan_2_4000000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E),
+		.driver_data = pbn_titan_4_4000000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E),
+		.driver_data = pbn_titan_8_4000000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI),
+		.driver_data = pbn_titan_2_4000000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI),
+		.driver_data = pbn_titan_2_4000000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200V3),
+		.driver_data = pbn_b0_bt_2_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400V3),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_410V3),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800V3),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800V3B),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550),
+		.driver_data = pbn_b2_1_460800,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650),
+		.driver_data = pbn_b2_1_460800,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850),
+		.driver_data = pbn_b2_1_460800,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550),
+		.driver_data = pbn_b2_bt_2_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650),
+		.driver_data = pbn_b2_bt_2_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850),
+		.driver_data = pbn_b2_bt_2_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550),
+		.driver_data = pbn_b2_bt_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650),
+		.driver_data = pbn_b2_bt_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850),
+		.driver_data = pbn_b2_bt_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550),
+		.driver_data = pbn_b0_1_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650),
+		.driver_data = pbn_b0_1_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850),
+		.driver_data = pbn_b0_1_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550),
+		.driver_data = pbn_b0_bt_2_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650),
+		.driver_data = pbn_b0_bt_2_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850),
+		.driver_data = pbn_b0_bt_2_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550),
+		.driver_data = pbn_b0_bt_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650),
+		.driver_data = pbn_b0_bt_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850),
+		.driver_data = pbn_b0_bt_4_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_550),
+		.driver_data = pbn_b0_bt_8_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_650),
+		.driver_data = pbn_b0_bt_8_921600,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_850),
+		.driver_data = pbn_b0_bt_8_921600,
+	},
 
 	/*
 	 * Computone devices submitted by Doug McNash dmcnash@computone.com
 	 */
-	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
-		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
-		0, 0, pbn_computone_4 },
-	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
-		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
-		0, 0, pbn_computone_8 },
-	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
-		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
-		0, 0, pbn_computone_6 },
+	{
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+			       PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4),
+		.driver_data = pbn_computone_4,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+			       PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8),
+		.driver_data = pbn_computone_8,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+			       PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6),
+		.driver_data = pbn_computone_6,
+	},
 
-	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_oxsemi },
-	{	PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
-		PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_1_921600 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N),
+		.driver_data = pbn_oxsemi,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
+			       PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID),
+		.driver_data = pbn_b0_bt_1_921600,
+	},
 
 	/*
 	 * Sunix PCI serial boards
 	 */
-	{	PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
-		PCI_VENDOR_ID_SUNIX, 0x0001, 0, 0,
-		pbn_sunix_pci_1s },
-	{	PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
-		PCI_VENDOR_ID_SUNIX, 0x0002, 0, 0,
-		pbn_sunix_pci_2s },
-	{	PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
-		PCI_VENDOR_ID_SUNIX, 0x0004, 0, 0,
-		pbn_sunix_pci_4s },
-	{	PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
-		PCI_VENDOR_ID_SUNIX, 0x0084, 0, 0,
-		pbn_sunix_pci_4s },
-	{	PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
-		PCI_VENDOR_ID_SUNIX, 0x0008, 0, 0,
-		pbn_sunix_pci_8s },
-	{	PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
-		PCI_VENDOR_ID_SUNIX, 0x0088, 0, 0,
-		pbn_sunix_pci_8s },
-	{	PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
-		PCI_VENDOR_ID_SUNIX, 0x0010, 0, 0,
-		pbn_sunix_pci_16s },
+	{
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+			       PCI_VENDOR_ID_SUNIX, 0x0001),
+		.driver_data = pbn_sunix_pci_1s,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+			       PCI_VENDOR_ID_SUNIX, 0x0002),
+		.driver_data = pbn_sunix_pci_2s,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+			       PCI_VENDOR_ID_SUNIX, 0x0004),
+		.driver_data = pbn_sunix_pci_4s,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+			       PCI_VENDOR_ID_SUNIX, 0x0084),
+		.driver_data = pbn_sunix_pci_4s,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+			       PCI_VENDOR_ID_SUNIX, 0x0008),
+		.driver_data = pbn_sunix_pci_8s,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+			       PCI_VENDOR_ID_SUNIX, 0x0088),
+		.driver_data = pbn_sunix_pci_8s,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
+			       PCI_VENDOR_ID_SUNIX, 0x0010),
+		.driver_data = pbn_sunix_pci_16s,
+	},
 
 	/*
 	 * AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org>
 	 */
-	{	PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_8_115200 },
-	{	PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P030,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_8_115200 },
-
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_2_115200 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_2_115200 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_2_115200 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_4_460800 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_4_460800 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_2_460800 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_2_460800 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_2_460800 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_1_115200 },
-	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_bt_1_460800 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028),
+		.driver_data = pbn_b0_bt_8_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P030),
+		.driver_data = pbn_b0_bt_8_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL),
+		.driver_data = pbn_b0_bt_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A),
+		.driver_data = pbn_b0_bt_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B),
+		.driver_data = pbn_b0_bt_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A),
+		.driver_data = pbn_b0_bt_4_460800,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B),
+		.driver_data = pbn_b0_bt_4_460800,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS),
+		.driver_data = pbn_b0_bt_2_460800,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A),
+		.driver_data = pbn_b0_bt_2_460800,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B),
+		.driver_data = pbn_b0_bt_2_460800,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL),
+		.driver_data = pbn_b0_bt_1_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650),
+		.driver_data = pbn_b0_bt_1_460800,
+	},
 
 	/*
 	 * Korenix Jetcard F0/F1 cards (JC1204, JC1208, JC1404, JC1408).
@@ -5116,560 +5156,532 @@ static const struct pci_device_id serial_pci_tbl[] = {
 	 * Note that JC140x are RS422/485 cards which require ox950
 	 * ACR = 0x10, and as such are not currently fully supported.
 	 */
-	{	PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
-		0x1204, 0x0004, 0, 0,
-		pbn_b0_4_921600 },
-	{	PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
-		0x1208, 0x0004, 0, 0,
-		pbn_b0_4_921600 },
-/*	{	PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
-		0x1402, 0x0002, 0, 0,
-		pbn_b0_2_921600 }, */
-/*	{	PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
-		0x1404, 0x0004, 0, 0,
-		pbn_b0_4_921600 }, */
-	{	PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF1,
-		0x1208, 0x0004, 0, 0,
-		pbn_b0_4_921600 },
-
-	{	PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
-		0x1204, 0x0004, 0, 0,
-		pbn_b0_4_921600 },
-	{	PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
-		0x1208, 0x0004, 0, 0,
-		pbn_b0_4_921600 },
-	{	PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF3,
-		0x1208, 0x0004, 0, 0,
-		pbn_b0_4_921600 },
+	{
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+			       0x1204, 0x0004),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+			       0x1208, 0x0004),
+		.driver_data = pbn_b0_4_921600,
+	},
+/*	{
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+			       0x1402, 0x0002),
+		.driver_data = pbn_b0_2_921600,
+	}, */
+/*	{
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF0,
+			       0x1404, 0x0004),
+		.driver_data = pbn_b0_4_921600,
+	}, */
+	{
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF1,
+			       0x1208, 0x0004),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
+			       0x1204, 0x0004),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF2,
+			       0x1208, 0x0004),
+		.driver_data = pbn_b0_4_921600,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_KORENIX, PCI_DEVICE_ID_KORENIX_JETCARDF3,
+			       0x1208, 0x0004),
+		.driver_data = pbn_b0_4_921600,
+	},
 	/*
 	 * Dell Remote Access Card 4 - Tim_T_Murphy@Dell.com
 	 */
-	{	PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RAC4,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_1_1382400 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RAC4),
+		.driver_data = pbn_b1_1_1382400,
+	},
 
 	/*
 	 * Dell Remote Access Card III - Tim_T_Murphy@Dell.com
 	 */
-	{	PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RACIII,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_1_1382400 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_RACIII),
+		.driver_data = pbn_b1_1_1382400,
+	},
 
 	/*
 	 * RAStel 2 port modem, gerg@moreton.com.au
 	 */
-	{	PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_bt_2_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT),
+		.driver_data = pbn_b2_bt_2_115200,
+	},
 
 	/*
 	 * EKF addition for i960 Boards form EKF with serial port
 	 */
-	{	PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80960_RP,
-		0xE4BF, PCI_ANY_ID, 0, 0,
-		pbn_intel_i960 },
+	{
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80960_RP,
+			       0xE4BF, PCI_ANY_ID),
+		.driver_data = pbn_intel_i960,
+	},
 
 	/*
 	 * Xircom Cardbus/Ethernet combos
 	 */
-	{	PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_1_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM),
+		.driver_data = pbn_b0_1_115200,
+	},
 	/*
 	 * Xircom RBM56G cardbus modem - Dirk Arnold (temp entry)
 	 */
-	{	PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_RBM56G,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_1_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_RBM56G),
+		.driver_data = pbn_b0_1_115200,
+	},
 
 	/*
 	 * Untested PCI modems, sent in from various folks...
 	 */
 
-	/*
-	 * Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de>
-	 */
-	{	PCI_VENDOR_ID_ROCKWELL, 0x1004,
-		0x1048, 0x1500, 0, 0,
-		pbn_b1_1_115200 },
-
-	{	PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
-		0xFF00, 0, 0, 0,
-		pbn_sgi_ioc3 },
+	{
+		/* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_ROCKWELL, 0x1004, 0x1048, 0x1500),
+		.driver_data = pbn_b1_1_115200,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, 0xFF00, 0),
+		.driver_data = pbn_sgi_ioc3,
+	},
 
 	/*
 	 * HP Diva card
 	 */
-	{	PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
-		PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_RMP3, 0, 0,
-		pbn_b1_1_115200 },
-	{	PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_5_115200 },
-	{	PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_1_115200 },
-	/* HPE PCI serial device */
-	{	PCI_VENDOR_ID_HP_3PAR, PCI_DEVICE_ID_HPE_PCI_SERIAL,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_1_115200 },
-
-	{	PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM2,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b3_2_115200 },
-	{	PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b3_4_115200 },
-	{	PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b3_8_115200 },
-	/*
-	 * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
-	 */
-	{	PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b0_1_115200 },
-	/*
-	 * ITE
-	 */
-	{	PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8872,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b1_bt_1_115200 },
-
-	/*
-	 * IntaShield IS-100
-	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0D60,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b2_1_115200 },
-	/*
-	 * IntaShield IS-200
-	 */
-	{	PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,	/* 135a.0d80 */
-		pbn_b2_2_115200 },
-	/*
-	 * IntaShield IS-400
-	 */
-	{	PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,    /* 135a.0dc0 */
-		pbn_b2_4_115200 },
-	/*
-	 * IntaShield IX-100
-	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4027,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_1_15625000 },
-	/*
-	 * IntaShield IX-200
-	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4028,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_2_15625000 },
-	/*
-	 * IntaShield IX-400
-	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4029,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_4_15625000 },
+	{
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
+			       PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_RMP3),
+		.driver_data = pbn_b1_1_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA),
+		.driver_data = pbn_b0_5_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX),
+		.driver_data = pbn_b2_1_115200,
+	}, {
+		/* HPE PCI serial device */
+		PCI_DEVICE(PCI_VENDOR_ID_HP_3PAR, PCI_DEVICE_ID_HPE_PCI_SERIAL),
+		.driver_data = pbn_b1_1_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM2),
+		.driver_data = pbn_b3_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4),
+		.driver_data = pbn_b3_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8),
+		.driver_data = pbn_b3_8_115200,
+	}, {
+		/* Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) */
+		PCI_DEVICE(PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560),
+		.driver_data = pbn_b0_1_115200,
+	}, {
+		/* ITE */
+		PCI_DEVICE(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8872),
+		.driver_data = pbn_b1_bt_1_115200,
+	}, {
+		/* IntaShield IS-100 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0D60),
+		.driver_data = pbn_b2_1_115200,
+	}, {
+		/* IntaShield IS-200; 135a.0d80 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		/* IntaShield IS-400; 135a.0dc0 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400),
+		.driver_data = pbn_b2_4_115200,
+	}, {
+		/* IntaShield IX-100 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4027),
+		.driver_data = pbn_oxsemi_1_15625000,
+	}, {
+		/* IntaShield IX-200 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4028),
+		.driver_data = pbn_oxsemi_2_15625000,
+	}, {
+		/* IntaShield IX-400 */
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4029),
+		.driver_data = pbn_oxsemi_4_15625000,
+	},
 	/* Brainboxes Devices */
 	/*
 	* Brainboxes UC-101
 	*/
-	{       PCI_VENDOR_ID_INTASHIELD, 0x0BA1,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{       PCI_VENDOR_ID_INTASHIELD, 0x0BA2,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{       PCI_VENDOR_ID_INTASHIELD, 0x0BA3,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0BA1),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0BA2),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0BA3),
+		.driver_data = pbn_b2_2_115200,
+	},
 	/*
 	 * Brainboxes UC-235/246
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0AA1,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_1_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0AA2,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_1_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0AA1),
+		.driver_data = pbn_b2_1_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0AA2),
+		.driver_data = pbn_b2_1_115200,
+	},
 	/*
 	 * Brainboxes UC-253/UC-734
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0CA1,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0CA1),
+		.driver_data = pbn_b2_2_115200,
+	},
 	/*
 	 * Brainboxes UC-260/271/701/756
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0D21,
-		PCI_ANY_ID, PCI_ANY_ID,
-		PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
-		pbn_b2_4_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0E34,
-		PCI_ANY_ID, PCI_ANY_ID,
-		PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
-		pbn_b2_4_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0D21),
+		.class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
+		.class_mask = 0xffff00,
+		.driver_data = pbn_b2_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0E34),
+		.class = PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
+		.class_mask = 0xffff00,
+		.driver_data = pbn_b2_4_115200,
+	},
 	/*
 	 * Brainboxes UC-268
 	 */
-	{       PCI_VENDOR_ID_INTASHIELD, 0x0841,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_4_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0841),
+		.driver_data = pbn_b2_4_115200,
+	},
 	/*
 	 * Brainboxes UC-275/279
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0881,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_8_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0881),
+		.driver_data = pbn_b2_8_115200,
+	},
 	/*
 	 * Brainboxes UC-302
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x08E1,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x08E2,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x08E3,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x08E1),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x08E2),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x08E3),
+		.driver_data = pbn_b2_2_115200,
+	},
 	/*
 	 * Brainboxes UC-310
 	 */
-	{       PCI_VENDOR_ID_INTASHIELD, 0x08C1,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x08C1),
+		.driver_data = pbn_b2_2_115200,
+	},
 	/*
 	 * Brainboxes UC-313
 	 */
-	{       PCI_VENDOR_ID_INTASHIELD, 0x08A1,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{       PCI_VENDOR_ID_INTASHIELD, 0x08A2,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{       PCI_VENDOR_ID_INTASHIELD, 0x08A3,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x08A1),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x08A2),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x08A3),
+		.driver_data = pbn_b2_2_115200,
+	},
 	/*
 	 * Brainboxes UC-320/324
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0A61,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_1_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0A61),
+		.driver_data = pbn_b2_1_115200,
+	},
 	/*
 	 * Brainboxes UC-346
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0B01,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_4_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0B02,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_4_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0B01),
+		.driver_data = pbn_b2_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0B02),
+		.driver_data = pbn_b2_4_115200,
+	},
 	/*
 	 * Brainboxes UC-357
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0A81,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0A82,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0A83,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0A81),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0A82),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0A83),
+		.driver_data = pbn_b2_2_115200,
+	},
 	/*
 	 * Brainboxes UC-368
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0C41,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_4_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0C42,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_4_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0C43,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_4_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0C41),
+		.driver_data = pbn_b2_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0C42),
+		.driver_data = pbn_b2_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0C43),
+		.driver_data = pbn_b2_4_115200,
+	},
 	/*
 	 * Brainboxes UC-420
 	 */
-	{       PCI_VENDOR_ID_INTASHIELD, 0x0921,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_4_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0921),
+		.driver_data = pbn_b2_4_115200,
+	},
 	/*
 	 * Brainboxes UC-607
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x09A1,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x09A2,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x09A3,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x09A1),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x09A2),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x09A3),
+		.driver_data = pbn_b2_2_115200,
+	},
 	/*
 	 * Brainboxes UC-836
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0D41,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_4_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0D41),
+		.driver_data = pbn_b2_4_115200,
+	},
 	/*
 	 * Brainboxes UP-189
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0AC1,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0AC2,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0AC3,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0AC1),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0AC2),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0AC3),
+		.driver_data = pbn_b2_2_115200,
+	},
 	/*
 	 * Brainboxes UP-200
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0B21,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0B22,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0B23,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0B21),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0B22),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0B23),
+		.driver_data = pbn_b2_2_115200,
+	},
 	/*
 	 * Brainboxes UP-869
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0C01,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0C02,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0C03,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0C01),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0C02),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0C03),
+		.driver_data = pbn_b2_2_115200,
+	},
 	/*
 	 * Brainboxes UP-880
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0C21,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0C22,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0C23,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_2_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0C21),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0C22),
+		.driver_data = pbn_b2_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0C23),
+		.driver_data = pbn_b2_2_115200,
+	},
 	/*
 	 * Brainboxes PX-101
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4005,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b0_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4019,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_2_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4005),
+		.driver_data = pbn_b0_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4019),
+		.driver_data = pbn_oxsemi_2_15625000,
+	},
 	/*
 	 * Brainboxes PX-235/246
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4004,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b0_1_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4016,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_1_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4004),
+		.driver_data = pbn_b0_1_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4016),
+		.driver_data = pbn_oxsemi_1_15625000,
+	},
 	/*
 	 * Brainboxes PX-203/PX-257
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4006,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b0_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4015,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_2_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4006),
+		.driver_data = pbn_b0_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4015),
+		.driver_data = pbn_oxsemi_2_15625000,
+	},
 	/*
 	 * Brainboxes PX-260/PX-701
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x400A,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_4_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x400A),
+		.driver_data = pbn_oxsemi_4_15625000,
+	},
 	/*
 	 * Brainboxes PX-275/279
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x0E41,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b2_8_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x0E41),
+		.driver_data = pbn_b2_8_115200,
+	},
 	/*
 	 * Brainboxes PX-310
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x400E,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_2_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x400E),
+		.driver_data = pbn_oxsemi_2_15625000,
+	},
 	/*
 	 * Brainboxes PX-313
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x400C,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_2_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x400C),
+		.driver_data = pbn_oxsemi_2_15625000,
+	},
 	/*
 	 * Brainboxes PX-320/324/PX-376/PX-387
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x400B,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_1_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x400B),
+		.driver_data = pbn_oxsemi_1_15625000,
+	},
 	/*
 	 * Brainboxes PX-335/346
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x400F,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_4_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x400F),
+		.driver_data = pbn_oxsemi_4_15625000,
+	},
 	/*
 	 * Brainboxes PX-368
 	 */
-	{       PCI_VENDOR_ID_INTASHIELD, 0x4010,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_4_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4010),
+		.driver_data = pbn_oxsemi_4_15625000,
+	},
 	/*
 	 * Brainboxes PX-420
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4000,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b0_4_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4011,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_4_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4000),
+		.driver_data = pbn_b0_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4011),
+		.driver_data = pbn_oxsemi_4_15625000,
+	},
 	/*
 	 * Brainboxes PX-475
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x401D,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_1_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x401D),
+		.driver_data = pbn_oxsemi_1_15625000,
+	},
 	/*
 	 * Brainboxes PX-803/PX-857
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4009,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b0_2_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4018,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_2_15625000 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x401E,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_2_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4009),
+		.driver_data = pbn_b0_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4018),
+		.driver_data = pbn_oxsemi_2_15625000,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x401E),
+		.driver_data = pbn_oxsemi_2_15625000,
+	},
 	/*
 	 * Brainboxes PX-820
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4002,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b0_4_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4013,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_4_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4002),
+		.driver_data = pbn_b0_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4013),
+		.driver_data = pbn_oxsemi_4_15625000,
+	},
 	/*
 	 * Brainboxes PX-835/PX-846
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4008,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_b0_1_115200 },
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4017,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_1_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4008),
+		.driver_data = pbn_b0_1_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4017),
+		.driver_data = pbn_oxsemi_1_15625000,
+	},
 	/*
 	 * Brainboxes XC-235
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4026,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_1_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4026),
+		.driver_data = pbn_oxsemi_1_15625000,
+	},
 	/*
 	 * Brainboxes XC-475
 	 */
-	{	PCI_VENDOR_ID_INTASHIELD, 0x4021,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0,
-		pbn_oxsemi_1_15625000 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTASHIELD, 0x4021),
+		.driver_data = pbn_oxsemi_1_15625000,
+	},
 
 	/*
 	 * Perle PCI-RAS cards
 	 */
-	{       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+	{
+		PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
 		PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS4,
-		0, 0, pbn_b2_4_921600 },
-	{       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+		.driver_data = pbn_b2_4_921600,
+	}, {
+		PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
 		PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8,
-		0, 0, pbn_b2_8_921600 },
+		.driver_data = pbn_b2_8_921600,
+	},
 
 	/*
 	 * Mainpine series cards: Fairly standard layout but fools
@@ -5677,375 +5689,439 @@ static const struct pci_device_id serial_pci_tbl[] = {
 	 * unmatched communications subclasses in the PCI Express case
 	 */
 
-	{	/* RockForceDUO */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x0200,
-		0, 0, pbn_b0_2_115200 },
-	{	/* RockForceQUATRO */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x0300,
-		0, 0, pbn_b0_4_115200 },
-	{	/* RockForceDUO+ */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x0400,
-		0, 0, pbn_b0_2_115200 },
-	{	/* RockForceQUATRO+ */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x0500,
-		0, 0, pbn_b0_4_115200 },
-	{	/* RockForce+ */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x0600,
-		0, 0, pbn_b0_2_115200 },
-	{	/* RockForce+ */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x0700,
-		0, 0, pbn_b0_4_115200 },
-	{	/* RockForceOCTO+ */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x0800,
-		0, 0, pbn_b0_8_115200 },
-	{	/* RockForceDUO+ */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x0C00,
-		0, 0, pbn_b0_2_115200 },
-	{	/* RockForceQUARTRO+ */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x0D00,
-		0, 0, pbn_b0_4_115200 },
-	{	/* RockForceOCTO+ */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x1D00,
-		0, 0, pbn_b0_8_115200 },
-	{	/* RockForceD1 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x2000,
-		0, 0, pbn_b0_1_115200 },
-	{	/* RockForceF1 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x2100,
-		0, 0, pbn_b0_1_115200 },
-	{	/* RockForceD2 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x2200,
-		0, 0, pbn_b0_2_115200 },
-	{	/* RockForceF2 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x2300,
-		0, 0, pbn_b0_2_115200 },
-	{	/* RockForceD4 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x2400,
-		0, 0, pbn_b0_4_115200 },
-	{	/* RockForceF4 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x2500,
-		0, 0, pbn_b0_4_115200 },
-	{	/* RockForceD8 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x2600,
-		0, 0, pbn_b0_8_115200 },
-	{	/* RockForceF8 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x2700,
-		0, 0, pbn_b0_8_115200 },
-	{	/* IQ Express D1 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x3000,
-		0, 0, pbn_b0_1_115200 },
-	{	/* IQ Express F1 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x3100,
-		0, 0, pbn_b0_1_115200 },
-	{	/* IQ Express D2 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x3200,
-		0, 0, pbn_b0_2_115200 },
-	{	/* IQ Express F2 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x3300,
-		0, 0, pbn_b0_2_115200 },
-	{	/* IQ Express D4 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x3400,
-		0, 0, pbn_b0_4_115200 },
-	{	/* IQ Express F4 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x3500,
-		0, 0, pbn_b0_4_115200 },
-	{	/* IQ Express D8 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x3C00,
-		0, 0, pbn_b0_8_115200 },
-	{	/* IQ Express F8 */
-		PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
-		PCI_VENDOR_ID_MAINPINE, 0x3D00,
-		0, 0, pbn_b0_8_115200 },
+	{
+		/* RockForceDUO */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x0200),
+		.driver_data = pbn_b0_2_115200,
+	}, {
+		/* RockForceQUATRO */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x0300),
+		.driver_data = pbn_b0_4_115200,
+	}, {
+		/* RockForceDUO+ */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x0400),
+		.driver_data = pbn_b0_2_115200,
+	}, {
+		/* RockForceQUATRO+ */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x0500),
+			.driver_data = pbn_b0_4_115200,
+	}, {
+		/* RockForce+ */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x0600),
+			.driver_data = pbn_b0_2_115200,
+	}, {
+		/* RockForce+ */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x0700),
+			.driver_data = pbn_b0_4_115200,
+	}, {
+		/* RockForceOCTO+ */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x0800),
+			.driver_data = pbn_b0_8_115200,
+	}, {
+		/* RockForceDUO+ */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x0C00),
+			.driver_data = pbn_b0_2_115200,
+	}, {
+		/* RockForceQUARTRO+ */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x0D00),
+			.driver_data = pbn_b0_4_115200,
+	}, {
+		/* RockForceOCTO+ */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x1D00),
+			.driver_data = pbn_b0_8_115200,
+	}, {
+		/* RockForceD1 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x2000),
+			.driver_data = pbn_b0_1_115200,
+	}, {
+		/* RockForceF1 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x2100),
+			.driver_data = pbn_b0_1_115200,
+	}, {	/* RockForceD2 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x2200),
+			.driver_data = pbn_b0_2_115200,
+	}, {	/* RockForceF2 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x2300),
+			.driver_data = pbn_b0_2_115200,
+	}, {
+		/* RockForceD4 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x2400),
+			.driver_data = pbn_b0_4_115200,
+	}, {
+		/* RockForceF4 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x2500),
+			.driver_data = pbn_b0_4_115200,
+	}, {
+		/* RockForceD8 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x2600),
+			.driver_data = pbn_b0_8_115200,
+	}, {
+		/* RockForceF8 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x2700),
+			.driver_data = pbn_b0_8_115200,
+	}, {
+		/* IQ Express D1 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x3000),
+			.driver_data = pbn_b0_1_115200,
+	}, {
+		/* IQ Express F1 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x3100),
+			.driver_data = pbn_b0_1_115200,
+	}, {
+		/* IQ Express D2 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x3200),
+			.driver_data = pbn_b0_2_115200,
+	}, {
+		/* IQ Express F2 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x3300),
+			.driver_data = pbn_b0_2_115200,
+	}, {
+		/* IQ Express D4 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x3400),
+			.driver_data = pbn_b0_4_115200,
+	}, {
+		/* IQ Express F4 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x3500),
+			.driver_data = pbn_b0_4_115200,
+	}, {
+		/* IQ Express D8 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x3C00),
+			.driver_data = pbn_b0_8_115200,
+	}, {
+		/* IQ Express F8 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+			       PCI_VENDOR_ID_MAINPINE, 0x3D00),
+			.driver_data = pbn_b0_8_115200,
+	},
 
-
-	/*
-	 * PA Semi PA6T-1682M on-chip UART
-	 */
-	{	PCI_VENDOR_ID_PASEMI, 0xa004,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_pasemi_1682M },
+	{
+		/* PA Semi PA6T-1682M on-chip UART */
+		PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa004),
+		.driver_data = pbn_pasemi_1682M,
+	},
 
 	/*
 	 * National Instruments
 	 */
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI23216,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_16_115200 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2328,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_8_115200 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_bt_4_115200 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_bt_2_115200 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324I,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_bt_4_115200 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322I,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_bt_2_115200 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_23216,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_16_115200 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2328,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_8_115200 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2324,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_bt_4_115200 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2322,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_bt_2_115200 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2324,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_bt_4_115200 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2322,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_b1_bt_2_115200 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2322,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_ni8430_2 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2322,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_ni8430_2 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2324,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_ni8430_4 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2324,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_ni8430_4 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2328,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_ni8430_8 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2328,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_ni8430_8 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_23216,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_ni8430_16 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_23216,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_ni8430_16 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2322,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_ni8430_2 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2322,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_ni8430_2 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2324,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_ni8430_4 },
-	{	PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2324,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_ni8430_4 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI23216),
+		.driver_data = pbn_b1_16_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2328),
+		.driver_data = pbn_b1_8_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324),
+		.driver_data = pbn_b1_bt_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322),
+		.driver_data = pbn_b1_bt_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2324I),
+		.driver_data = pbn_b1_bt_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI2322I),
+		.driver_data = pbn_b1_bt_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_23216),
+		.driver_data = pbn_b1_16_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2328),
+		.driver_data = pbn_b1_8_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2324),
+		.driver_data = pbn_b1_bt_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8420_2322),
+		.driver_data = pbn_b1_bt_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2324),
+		.driver_data = pbn_b1_bt_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8422_2322),
+		.driver_data = pbn_b1_bt_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2322),
+		.driver_data = pbn_ni8430_2,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2322),
+		.driver_data = pbn_ni8430_2,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2324),
+		.driver_data = pbn_ni8430_4,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2324),
+		.driver_data = pbn_ni8430_4,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_2328),
+		.driver_data = pbn_ni8430_8,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_2328),
+		.driver_data = pbn_ni8430_8,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8430_23216),
+		.driver_data = pbn_ni8430_16,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8430_23216),
+		.driver_data = pbn_ni8430_16,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2322),
+		.driver_data = pbn_ni8430_2,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2322),
+		.driver_data = pbn_ni8430_2,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI8432_2324),
+		.driver_data = pbn_ni8430_4,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI8432_2324),
+		.driver_data = pbn_ni8430_4,
+	},
 
 	/*
 	 * MOXA
 	 */
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102E),	    pbn_moxa_2 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102EL),    pbn_moxa_2 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102N),	    pbn_moxa_2 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL_A),  pbn_moxa_4 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104N),	    pbn_moxa_4 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP112N),	    pbn_moxa_2 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114EL),    pbn_moxa_4 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114N),	    pbn_moxa_4 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_A), pbn_moxa_8 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_B), pbn_moxa_8 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL_A),  pbn_moxa_8 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118E_A_I), pbn_moxa_8 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132EL),    pbn_moxa_2 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132N),     pbn_moxa_2 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134EL_A),  pbn_moxa_4 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134N),	    pbn_moxa_4 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP138E_A),   pbn_moxa_8 },
-	{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL_A),  pbn_moxa_8 },
+	{
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102E),
+		.driver_data = pbn_moxa_2,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102EL),
+		.driver_data = pbn_moxa_2,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102N),
+		.driver_data = pbn_moxa_2,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL_A),
+		.driver_data = pbn_moxa_4,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104N),
+		.driver_data = pbn_moxa_4,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP112N),
+		.driver_data = pbn_moxa_2,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114EL),
+		.driver_data = pbn_moxa_4,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114N),
+		.driver_data = pbn_moxa_4,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_A),
+		.driver_data = pbn_moxa_8,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_B),
+		.driver_data = pbn_moxa_8,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL_A),
+		.driver_data = pbn_moxa_8,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118E_A_I),
+		.driver_data = pbn_moxa_8,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132EL),
+		.driver_data = pbn_moxa_2,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132N),
+		.driver_data = pbn_moxa_2,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134EL_A),
+		.driver_data = pbn_moxa_4,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134N),
+		.driver_data = pbn_moxa_4,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP138E_A),
+		.driver_data = pbn_moxa_8,
+	}, {
+		PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL_A),
+		.driver_data = pbn_moxa_8,
+	},
 
 	/*
 	* ADDI-DATA GmbH communication cards <info@addi-data.com>
 	*/
-	{	PCI_VENDOR_ID_ADDIDATA,
+	{
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_APCI7500,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_b0_4_115200 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_b0_4_115200,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_APCI7420,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_b0_2_115200 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_b0_2_115200,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_APCI7300,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_b0_1_115200 },
-
-	{	PCI_VENDOR_ID_AMCC,
+		.driver_data = pbn_b0_1_115200,
+	}, {
+		PCI_VENDOR_ID_AMCC,
 		PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_b1_8_115200 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_b1_8_115200,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_APCI7500_2,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_b0_4_115200 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_b0_4_115200,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_APCI7420_2,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_b0_2_115200 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_b0_2_115200,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_APCI7300_2,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_b0_1_115200 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_b0_1_115200,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_APCI7500_3,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_b0_4_115200 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_b0_4_115200,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_APCI7420_3,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_b0_2_115200 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_b0_2_115200,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_APCI7300_3,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_b0_1_115200 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_b0_1_115200,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_APCI7800_3,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_b0_8_115200 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_b0_8_115200,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_APCIe7500,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_ADDIDATA_PCIe_4_3906250 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_ADDIDATA_PCIe_4_3906250,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_APCIe7420,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_ADDIDATA_PCIe_2_3906250 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_ADDIDATA_PCIe_2_3906250,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_APCIe7300,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_ADDIDATA_PCIe_1_3906250 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_ADDIDATA_PCIe_1_3906250,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_APCIe7800,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_ADDIDATA_PCIe_8_3906250 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_ADDIDATA_PCIe_8_3906250,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_CPCI7500,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_b0_4_115200 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_b0_4_115200,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_CPCI7500_NG,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_b0_4_115200 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_b0_4_115200,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_CPCI7420_NG,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_b0_2_115200 },
-
-	{	PCI_VENDOR_ID_ADDIDATA,
+		.driver_data = pbn_b0_2_115200,
+	}, {
+		PCI_VENDOR_ID_ADDIDATA,
 		PCI_DEVICE_ID_ADDIDATA_CPCI7300_NG,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
 		0,
-		pbn_b0_1_115200 },
-
-	{	PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
+		.driver_data = pbn_b0_1_115200,
+	}, {
+		PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
 		PCI_VENDOR_ID_IBM, 0x0299,
-		0, 0, pbn_b0_bt_2_115200 },
+		0, 0,
+		.driver_data = pbn_b0_bt_2_115200,
+	},
 
 	/*
 	 * other NetMos 9835 devices are most likely handled by the
@@ -6053,153 +6129,185 @@ static const struct pci_device_id serial_pci_tbl[] = {
 	 * before adding them here.
 	 */
 
-	{	PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
-		0xA000, 0x1000,
-		0, 0, pbn_b0_1_115200 },
-
-	/* the 9901 is a rebranded 9912 */
-	{	PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912,
-		0xA000, 0x1000,
-		0, 0, pbn_b0_1_115200 },
-
-	{	PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9922,
-		0xA000, 0x1000,
-		0, 0, pbn_b0_1_115200 },
-
-	{	PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9904,
-		0xA000, 0x1000,
-		0, 0, pbn_b0_1_115200 },
-
-	{	PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
-		0xA000, 0x1000,
-		0, 0, pbn_b0_1_115200 },
-
-	{	PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
-		0xA000, 0x3002,
-		0, 0, pbn_NETMOS9900_2s_115200 },
-
-	{	PCIE_VENDOR_ID_ASIX, PCIE_DEVICE_ID_AX99100,
-		0xA000, 0x1000,
-		0, 0, pbn_b0_1_115200 },
+	{
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
+			       0xA000, 0x1000),
+		.driver_data = pbn_b0_1_115200,
+	}, {
+		/* the 9901 is a rebranded 9912 */
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912,
+			       0xA000, 0x1000),
+		.driver_data = pbn_b0_1_115200,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9922,
+			       0xA000, 0x1000),
+		.driver_data = pbn_b0_1_115200,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9904,
+			       0xA000, 0x1000),
+		.driver_data = pbn_b0_1_115200,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
+			       0xA000, 0x1000),
+		.driver_data = pbn_b0_1_115200,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900,
+			       0xA000, 0x3002),
+		.driver_data = pbn_NETMOS9900_2s_115200,
+	}, {
+		PCI_DEVICE_SUB(PCIE_VENDOR_ID_ASIX, PCIE_DEVICE_ID_AX99100,
+			       0xA000, 0x1000),
+		.driver_data = pbn_b0_1_115200,
+	},
 
 	/*
 	 * Best Connectivity and Rosewill PCI Multi I/O cards
 	 */
 
-	{	PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
-		0xA000, 0x1000,
-		0, 0, pbn_b0_1_115200 },
-
-	{	PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
-		0xA000, 0x3002,
-		0, 0, pbn_b0_bt_2_115200 },
-
-	{	PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
-		0xA000, 0x3004,
-		0, 0, pbn_b0_bt_4_115200 },
+	{
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+			       0xA000, 0x1000),
+		.driver_data = pbn_b0_1_115200,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+			       0xA000, 0x3002),
+		.driver_data = pbn_b0_bt_2_115200,
+	}, {
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+			       0xA000, 0x3004),
+		.driver_data = pbn_b0_bt_4_115200,
+	},
 
 	/*
 	 * ASIX AX99100 PCIe to Multi I/O Controller
 	 */
-	{	PCI_VENDOR_ID_ASIX, PCI_DEVICE_ID_ASIX_AX99100,
-		0xA000, 0x1000,
-		0, 0, pbn_b0_1_115200 },
+	{
+		PCI_DEVICE_SUB(PCI_VENDOR_ID_ASIX, PCI_DEVICE_ID_ASIX_AX99100,
+			       0xA000, 0x1000),
+		.driver_data = pbn_b0_1_115200,
+	},
 
 	/* Intel CE4100 */
-	{	PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART,
-		PCI_ANY_ID,  PCI_ANY_ID, 0, 0,
-		pbn_ce4100_1_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART),
+		.driver_data = pbn_ce4100_1_115200,
+	},
 
 	/*
 	 * Cronyx Omega PCI
 	 */
-	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_CRONYX_OMEGA,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_omegapci },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_CRONYX_OMEGA),
+		.driver_data = pbn_omegapci,
+	},
 
 	/*
 	 * Broadcom TruManage
 	 */
-	{	PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BROADCOM_TRUMANAGE,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_brcm_trumanage },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BROADCOM_TRUMANAGE),
+		.driver_data = pbn_brcm_trumanage,
+	},
 
 	/*
 	 * AgeStar as-prs2-009
 	 */
-	{	PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0, pbn_b0_bt_2_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375),
+		.driver_data = pbn_b0_bt_2_115200,
+	},
 
 	/*
 	 * WCH CH353 series devices: The 2S1P is handled by parport_serial
 	 * so not listed here.
 	 */
-	{	PCI_VENDOR_ID_WCHCN, PCI_DEVICE_ID_WCHCN_CH353_4S,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0, pbn_b0_bt_4_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_WCHCN, PCI_DEVICE_ID_WCHCN_CH353_4S),
+		.driver_data = pbn_b0_bt_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_WCHCN, PCI_DEVICE_ID_WCHCN_CH353_2S1PF),
+		.driver_data = pbn_b0_bt_2_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_WCHCN, PCI_DEVICE_ID_WCHCN_CH355_4S),
+		.driver_data = pbn_b0_bt_4_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_WCHIC, PCI_DEVICE_ID_WCHIC_CH382_2S),
+		.driver_data = pbn_wch382_2,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_WCHIC, PCI_DEVICE_ID_WCHIC_CH384_4S),
+		.driver_data = pbn_wch384_4,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_WCHIC, PCI_DEVICE_ID_WCHIC_CH384_8S),
+		.driver_data = pbn_wch384_8,
+	},
 
-	{	PCI_VENDOR_ID_WCHCN, PCI_DEVICE_ID_WCHCN_CH353_2S1PF,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0, pbn_b0_bt_2_115200 },
-
-	{	PCI_VENDOR_ID_WCHCN, PCI_DEVICE_ID_WCHCN_CH355_4S,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0, pbn_b0_bt_4_115200 },
-
-	{	PCI_VENDOR_ID_WCHIC, PCI_DEVICE_ID_WCHIC_CH382_2S,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0, pbn_wch382_2 },
-
-	{	PCI_VENDOR_ID_WCHIC, PCI_DEVICE_ID_WCHIC_CH384_4S,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0, pbn_wch384_4 },
-
-	{	PCI_VENDOR_ID_WCHIC, PCI_DEVICE_ID_WCHIC_CH384_8S,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0, pbn_wch384_8 },
 	/*
 	 * Realtek RealManage
 	 */
-	{	PCI_VENDOR_ID_REALTEK, 0x816a,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0, pbn_b0_1_115200 },
-
-	{	PCI_VENDOR_ID_REALTEK, 0x816b,
-		PCI_ANY_ID, PCI_ANY_ID,
-		0, 0, pbn_b0_1_115200 },
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x816a),
+		.driver_data = pbn_b0_1_115200,
+	}, {
+		PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x816b),
+		.driver_data = pbn_b0_1_115200,
+	},
 
 	/* Fintek PCI serial cards */
-	{ PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 },
-	{ PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 },
-	{ PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 },
-	{ PCI_DEVICE(0x1c29, 0x1204), .driver_data = pbn_fintek_F81504A },
-	{ PCI_DEVICE(0x1c29, 0x1208), .driver_data = pbn_fintek_F81508A },
-	{ PCI_DEVICE(0x1c29, 0x1212), .driver_data = pbn_fintek_F81512A },
+	{
+		PCI_DEVICE(0x1c29, 0x1104),
+		.driver_data = pbn_fintek_4,
+	}, {
+		PCI_DEVICE(0x1c29, 0x1108),
+		.driver_data = pbn_fintek_8,
+	}, {
+		PCI_DEVICE(0x1c29, 0x1112),
+		.driver_data = pbn_fintek_12,
+	}, {
+		PCI_DEVICE(0x1c29, 0x1204),
+		.driver_data = pbn_fintek_F81504A,
+	}, {
+		PCI_DEVICE(0x1c29, 0x1208),
+		.driver_data = pbn_fintek_F81508A,
+	}, {
+		PCI_DEVICE(0x1c29, 0x1212),
+		.driver_data = pbn_fintek_F81512A,
+	},
 
 	/* MKS Tenta SCOM-080x serial cards */
-	{ PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 },
-	{ PCI_DEVICE(0x1601, 0xa801), .driver_data = pbn_b0_4_1250000 },
+	{
+		PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000,
+	}, {
+		PCI_DEVICE(0x1601, 0xa801), .driver_data = pbn_b0_4_1250000,
+	},
 
 	/* Amazon PCI serial device */
-	{ PCI_DEVICE(0x1d0f, 0x8250), .driver_data = pbn_b0_1_115200 },
+	{
+		PCI_DEVICE(0x1d0f, 0x8250), .driver_data = pbn_b0_1_115200,
+	},
 
 	/*
 	 * These entries match devices with class COMMUNICATION_SERIAL,
 	 * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
 	 */
-	{	PCI_ANY_ID, PCI_ANY_ID,
+	{
+		PCI_ANY_ID, PCI_ANY_ID,
 		PCI_ANY_ID, PCI_ANY_ID,
 		PCI_CLASS_COMMUNICATION_SERIAL << 8,
-		0xffff00, pbn_default },
-	{	PCI_ANY_ID, PCI_ANY_ID,
+		0xffff00,
+		.driver_data = pbn_default,
+	}, {
+		PCI_ANY_ID, PCI_ANY_ID,
 		PCI_ANY_ID, PCI_ANY_ID,
 		PCI_CLASS_COMMUNICATION_MODEM << 8,
-		0xffff00, pbn_default },
-	{	PCI_ANY_ID, PCI_ANY_ID,
+		0xffff00,
+		.driver_data = pbn_default,
+	}, {
+		PCI_ANY_ID, PCI_ANY_ID,
 		PCI_ANY_ID, PCI_ANY_ID,
 		PCI_CLASS_COMMUNICATION_MULTISERIAL << 8,
-		0xffff00, pbn_default },
+		0xffff00,
+		.driver_data = pbn_default,
+	},
 	{ 0, }
 };
 

base-commit: 028ef9c96e96197026887c0f092424679298aae8
-- 
2.47.3


^ permalink raw reply related

* Re: [PATCH] serial: sh-sci: optimize max_freq determination
From: Hugo Villeneuve @ 2026-04-20 16:12 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Greg Kroah-Hartman, Jiri Slaby, Hugo Villeneuve, biju.das.jz,
	linux-kernel, linux-serial
In-Reply-To: <CAMuHMdXpZjVctirMuH=n_PrK4nnEnWqjuCzRjc4y6kC1--99kQ@mail.gmail.com>

Hi Geert,

On Mon, 20 Apr 2026 09:23:55 +0200
Geert Uytterhoeven <geert@linux-m68k.org> wrote:

> Hi Hugo,
> 
> On Sat, 18 Apr 2026 at 07:24, Hugo Villeneuve <hugo@hugovil.com> wrote:
> > From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
> >
> > Follow example of rsci driver to avoid code duplication and useless
> > max_freq search when port->uartclk is set to zero.
> >
> > Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
> 
> Thanks for your patch!
> 
> > --- a/drivers/tty/serial/sh-sci.c
> > +++ b/drivers/tty/serial/sh-sci.c
> > @@ -2711,14 +2711,15 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
> >          * setup the baud rate generator hardware for us already.
> >          */
> >         if (!port->uartclk) {
> > -               baud = uart_get_baud_rate(port, termios, old, 0, 115200);
> > -               goto done;
> 
> There was no "useless max_freq search", due to this goto?

You are right, this part of the comment is wrong.

> 
> > +               max_freq = 115200;
> > +       } else {
> > +               for (i = 0; i < SCI_NUM_CLKS; i++)
> > +                       max_freq = max(max_freq, s->clk_rates[i]);
> > +
> > +               max_freq /= min_sr(s);
> >         }
> >
> > -       for (i = 0; i < SCI_NUM_CLKS; i++)
> > -               max_freq = max(max_freq, s->clk_rates[i]);
> > -
> > -       baud = uart_get_baud_rate(port, termios, old, 0, max_freq / min_sr(s));
> > +       baud = uart_get_baud_rate(port, termios, old, 0, max_freq);
> >         if (!baud)
> >                 goto done;
> >
> 
> Due to removing the goto above (for the casual reader: this is the
> earlyprintk case, when port->uartclk is zero), the code will now
> continue here, calculating transmission parameters and setting best_clk,
> and overwriting the register configuration done by the bootloader.

Yes, I see it now for sh-sci where we have "if (best_clk >= 0) {"... to
not configure the registers.

However, for the rsci driver, I think that, even after Biju's cleanup
serie V3, we still overwrite the register configuration done by the
bootloader?

Maybe configure only "if (!port->uartclk) {" ?

Hugo.



> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 
> -- 
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
> 
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
>                                 -- Linus Torvalds
> 


-- 
Hugo Villeneuve

^ permalink raw reply

* Re: [PATCH v3 2/3] serial: sh-sci: Drop check for zero baud rate from uart_get_baud_rate()
From: Hugo Villeneuve @ 2026-04-20 15:59 UTC (permalink / raw)
  To: Biju
  Cc: Greg Kroah-Hartman, Jiri Slaby, Biju Das, Geert Uytterhoeven,
	Lad Prabhakar, Thierry Bultel, linux-kernel, linux-serial,
	linux-renesas-soc
In-Reply-To: <20260420140426.237865-3-biju.das.jz@bp.renesas.com>

Hi Biju,

On Mon, 20 Apr 2026 15:04:22 +0100
Biju <biju.das.au@gmail.com> wrote:

> From: Biju Das <biju.das.jz@bp.renesas.com>
> 
> On DT systems, a zero baud rate from uart_get_baud_rate() is not possible
> even earlycon derives its bit rate from chosen/stdout-path. The zero baud
> guard and its associated done label are therefore dead code. So remove it.
> 
> Also drop the unused done label from rsci_set_termios().
> 
> Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>

Acked-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>


> ---
> v3:
>  * New patch
> ---
>  drivers/tty/serial/rsci.c   | 3 ---
>  drivers/tty/serial/sh-sci.c | 2 --
>  2 files changed, 5 deletions(-)
> 
> diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c
> index b00c9e385169..40db9daa4272 100644
> --- a/drivers/tty/serial/rsci.c
> +++ b/drivers/tty/serial/rsci.c
> @@ -265,8 +265,6 @@ static void rsci_set_termios(struct uart_port *port, struct ktermios *termios,
>  	}
>  
>  	baud = uart_get_baud_rate(port, termios, old, 0, max_freq);
> -	if (!baud)
> -		goto done;
>  
>  	/* Divided Functional Clock using standard Bit Rate Register */
>  	err = sci_scbrr_calc(s, baud, &brr1, &srr1, &cks1);
> @@ -278,7 +276,6 @@ static void rsci_set_termios(struct uart_port *port, struct ktermios *termios,
>  		cks = cks1;
>  	}
 
> -done:
>  	if (best_clk >= 0)
>  		dev_dbg(port->dev, "Using clk %pC for %u%+d bps\n",
>  			s->clks[best_clk], baud, min_err);
> diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
> index 7473b26ce9cf..9be359e04995 100644
> --- a/drivers/tty/serial/sh-sci.c
> +++ b/drivers/tty/serial/sh-sci.c
> @@ -2719,8 +2719,6 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
>  		max_freq = max(max_freq, s->clk_rates[i]);
>  
>  	baud = uart_get_baud_rate(port, termios, old, 0, max_freq / min_sr(s));
> -	if (!baud)
> -		goto done;
>  
>  	/*
>  	 * There can be multiple sources for the sampling clock.  Find the one
> -- 
> 2.43.0
> 
> 


-- 
Hugo Villeneuve

^ permalink raw reply

* [PATCH v3 3/3] serial: rsci: Refactor baud rate clock selection
From: Biju @ 2026-04-20 14:04 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby
  Cc: Biju Das, Geert Uytterhoeven, Lad Prabhakar, Thierry Bultel,
	linux-kernel, linux-serial, Biju Das, linux-renesas-soc
In-Reply-To: <20260420140426.237865-1-biju.das.jz@bp.renesas.com>

From: Biju Das <biju.das.jz@bp.renesas.com>

Since RSCI only uses a single clock source (SCI_FCK), the multi-clock
tracking variables (best_clk, min_err, brr1, srr1, cks1) are redundant
and removed. ccr0_val and ccr4_val are likewise dropped, replaced with
hardcoded 0 at their write sites, as they were never modified from their
initial zero values.

No functional change intended.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v2->v3:
 * Dropped reported by tag as the goto statement in rsci_set_termios()
   removed in the previous patch.
 * baud check removed by previous patch.
 * Added missing macro CCR0_RE while dropping ccr0_val variable.
 * Updated commit description.
v1->v2:
 * Dropped the check (abs(err) < abs(min_err) as it is always true.
 * Dropped the check (abs(err) < abs(min_err) as it is always true.
 * Dropped variables best_clk and min_err as they are no longer needed.
 * Dropped intermediate variables brr1, cks1 and srr1; results are now
   written directly into brr, cks and srr.
 * Moved dev_dbg() inside the if (baud) block.
 * Dropped ccr0_val and ccr4_val, replaced with hardcoded 0 at their
   write sites, as they were never modified from their initial values.
 * Scoped variables err and srr locally within the if (baud) block.
 * Updated commit description.
---
 drivers/tty/serial/rsci.c | 31 ++++++++++---------------------
 1 file changed, 10 insertions(+), 21 deletions(-)

diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c
index 40db9daa4272..444e89696310 100644
--- a/drivers/tty/serial/rsci.c
+++ b/drivers/tty/serial/rsci.c
@@ -217,16 +217,15 @@ static void rsci_set_termios(struct uart_port *port, struct ktermios *termios,
 			     const struct ktermios *old)
 {
 	unsigned int ccr2_val = CCR2_INIT, ccr3_val = CCR3_INIT;
-	unsigned int ccr0_val = 0, ccr1_val = 0, ccr4_val = 0;
-	unsigned int brr1 = 255, cks1 = 0, srr1 = 15;
 	struct sci_port *s = to_sci_port(port);
 	unsigned int brr = 255, cks = 0;
-	int min_err = INT_MAX, err;
-	unsigned long max_freq = 0;
+	unsigned int ccr1_val = 0;
+	unsigned long max_freq;
 	unsigned int baud, i;
 	unsigned long flags;
 	unsigned int ctrl;
-	int best_clk = -1;
+	unsigned int srr;
+	int err;
 
 	if ((termios->c_cflag & CSIZE) == CS7) {
 		ccr3_val |= CCR3_CHR0;
@@ -267,25 +266,16 @@ static void rsci_set_termios(struct uart_port *port, struct ktermios *termios,
 	baud = uart_get_baud_rate(port, termios, old, 0, max_freq);
 
 	/* Divided Functional Clock using standard Bit Rate Register */
-	err = sci_scbrr_calc(s, baud, &brr1, &srr1, &cks1);
-	if (abs(err) < abs(min_err)) {
-		best_clk = SCI_FCK;
-		ccr0_val = 0;
-		min_err = err;
-		brr = brr1;
-		cks = cks1;
-	}
-
-	if (best_clk >= 0)
-		dev_dbg(port->dev, "Using clk %pC for %u%+d bps\n",
-			s->clks[best_clk], baud, min_err);
+	err = sci_scbrr_calc(s, baud, &brr, &srr, &cks);
+	dev_dbg(port->dev, "Using clk %pC for %u%+d bps\n", s->clks[SCI_FCK],
+		baud, err);
 
 	sci_port_enable(s);
 	uart_port_lock_irqsave(port, &flags);
 
 	uart_update_timeout(port, termios->c_cflag, baud);
 
-	rsci_serial_out(port, CCR0, ccr0_val);
+	rsci_serial_out(port, CCR0, 0);
 
 	ccr3_val |= CCR3_FM;
 	rsci_serial_out(port, CCR3, ccr3_val);
@@ -294,7 +284,7 @@ static void rsci_set_termios(struct uart_port *port, struct ktermios *termios,
 	rsci_serial_out(port, CCR2, ccr2_val);
 
 	rsci_serial_out(port, CCR1, ccr1_val);
-	rsci_serial_out(port, CCR4, ccr4_val);
+	rsci_serial_out(port, CCR4, 0);
 
 	ctrl = rsci_serial_in(port, FCR);
 	ctrl |= (FCR_RFRST | FCR_TFRST);
@@ -315,8 +305,7 @@ static void rsci_set_termios(struct uart_port *port, struct ktermios *termios,
 	rsci_serial_out(port, CFCLR, CFCLR_CLRFLAG);
 	rsci_serial_out(port, FFCLR, FFCLR_DRC);
 
-	ccr0_val |= CCR0_RE;
-	rsci_serial_out(port, CCR0, ccr0_val);
+	rsci_serial_out(port, CCR0, CCR0_RE);
 
 	if ((termios->c_cflag & CREAD) != 0)
 		rsci_start_rx(port);
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 2/3] serial: sh-sci: Drop check for zero baud rate from uart_get_baud_rate()
From: Biju @ 2026-04-20 14:04 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby
  Cc: Biju Das, Geert Uytterhoeven, Lad Prabhakar, Thierry Bultel,
	linux-kernel, linux-serial, Biju Das, linux-renesas-soc
In-Reply-To: <20260420140426.237865-1-biju.das.jz@bp.renesas.com>

From: Biju Das <biju.das.jz@bp.renesas.com>

On DT systems, a zero baud rate from uart_get_baud_rate() is not possible
even earlycon derives its bit rate from chosen/stdout-path. The zero baud
guard and its associated done label are therefore dead code. So remove it.

Also drop the unused done label from rsci_set_termios().

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v3:
 * New patch
---
 drivers/tty/serial/rsci.c   | 3 ---
 drivers/tty/serial/sh-sci.c | 2 --
 2 files changed, 5 deletions(-)

diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c
index b00c9e385169..40db9daa4272 100644
--- a/drivers/tty/serial/rsci.c
+++ b/drivers/tty/serial/rsci.c
@@ -265,8 +265,6 @@ static void rsci_set_termios(struct uart_port *port, struct ktermios *termios,
 	}
 
 	baud = uart_get_baud_rate(port, termios, old, 0, max_freq);
-	if (!baud)
-		goto done;
 
 	/* Divided Functional Clock using standard Bit Rate Register */
 	err = sci_scbrr_calc(s, baud, &brr1, &srr1, &cks1);
@@ -278,7 +276,6 @@ static void rsci_set_termios(struct uart_port *port, struct ktermios *termios,
 		cks = cks1;
 	}
 
-done:
 	if (best_clk >= 0)
 		dev_dbg(port->dev, "Using clk %pC for %u%+d bps\n",
 			s->clks[best_clk], baud, min_err);
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 7473b26ce9cf..9be359e04995 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -2719,8 +2719,6 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
 		max_freq = max(max_freq, s->clk_rates[i]);
 
 	baud = uart_get_baud_rate(port, termios, old, 0, max_freq / min_sr(s));
-	if (!baud)
-		goto done;
 
 	/*
 	 * There can be multiple sources for the sampling clock.  Find the one
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 1/3] serial: sh-sci: Avoid divide-by-zero fault
From: Biju @ 2026-04-20 14:04 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby
  Cc: Biju Das, Geert Uytterhoeven, Lad Prabhakar, Thierry Bultel,
	linux-kernel, linux-serial, Biju Das, linux-renesas-soc
In-Reply-To: <20260420140426.237865-1-biju.das.jz@bp.renesas.com>

From: Biju Das <biju.das.jz@bp.renesas.com>

The expression (10000 * bits) / (baud / 100) can produce a divide-by-zero
if baud is less than 100, since integer division yields zero before the
outer divide occurs. Rewrite it as (10000 * bits) * 100 / baud, which is
algebraically equivalent but eliminates the intermediate division, making
a zero divisor impossible for any valid baud rate.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
---
v3:
 * New patch.
---
 drivers/tty/serial/sh-sci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 6c819b6b2425..7473b26ce9cf 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -2915,7 +2915,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
 	}
 
 	/* Calculate delay for 2 DMA buffers (4 FIFO). */
-	s->rx_frame = (10000 * bits) / (baud / 100);
+	s->rx_frame = (10000 * bits) * 100 / baud;
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
 	s->rx_timeout = s->buf_len_rx * 2 * s->rx_frame;
 #endif
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 0/3] serial: sh-sci/rsci: Fix divide-by-zero and clean up baud rate handling
From: Biju @ 2026-04-20 14:04 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby
  Cc: Biju Das, Geert Uytterhoeven, Lad Prabhakar, Thierry Bultel,
	linux-kernel, linux-serial, Biju Das, linux-renesas-soc

From: Biju Das <biju.das.jz@bp.renesas.com>

This series fixes a divide-by-zero fault in the SH-SCI driver and cleans
up dead code and redundant variables related to baud rate handling in both
the SH-SCI and RSCI drivers.

Patch 1 fixes a divide-by-zero fault in sci_set_termios() where the
expression (10000 * bits) / (baud / 100) could divide by zero if baud is
less than 100. The expression is rewritten as (10000 * bits) * 100 / baud,
which is algebraically equivalent but eliminates the intermediate
division.

Patch 2 removes the dead zero baud rate guard from both sci_set_termios()
and rsci_set_termios(). On DT systems, uart_get_baud_rate() never returns
zero, making the if (!baud) goto done; check and its associated done label
unreachable dead code.

Patch 3 refactors the baud rate clock selection in rsci_set_termios().
Since RSCI only supports a single clock source (SCI_FCK), the multi-clock
tracking variables are redundant and removed. ccr0_val and ccr4_val, which
were never modified from their initial zero values, are replaced with
hardcoded 0 at their write sites.

v2->v3:
 * Added a patch to rewrite rx_frame calculation to avoid divide-by-zero.
 * Added a patch to drop zero baud check from sh-sci and rsci drivers.
 * Dropped reported by tag as the goto statement in rsci_set_termios()
   removed in the previous patch.
 * baud check removed by previous patch.
 * Added missing macro CCR0_RE while dropping ccr0_val variable.
 * Updated commit description for patch#3.
v1->v2:
 * Add a patch for avoiding divide-by-zero fault.
 * Dropped the check (abs(err) < abs(min_err) as it is always true.
 * Dropped variables best_clk and min_err as they are no longer needed.
 * Dropped intermediate variables brr1, cks1 and srr1; results are now
   written directly into brr, cks and srr.
 * Moved dev_dbg() inside the if (baud) block.
 * Dropped ccr0_val and ccr4_val, replaced with hardcoded 0 at their
   write sites, as they were never modified from their initial values.
 * Scoped variables err and srr locally within the if (baud) block.
 * Updated commit description.

Biju Das (3):
  serial: sh-sci: Avoid divide-by-zero fault
  serial: sh-sci: Drop check for zero baud rate from
    uart_get_baud_rate()
  serial: rsci: Refactor baud rate clock selection

 drivers/tty/serial/rsci.c   | 34 ++++++++++------------------------
 drivers/tty/serial/sh-sci.c |  4 +---
 2 files changed, 11 insertions(+), 27 deletions(-)

-- 
2.43.0


^ permalink raw reply

* [PATCH] serial: fsl_lpuart: fix rx buffer and DMA map leaks in start_rx_dma
From: Shitalkumar Gandhi @ 2026-04-20 13:59 UTC (permalink / raw)
  To: gregkh, jirislaby
  Cc: bhuvanchandra.dv, Frank.Li, peng.fan, sherry.sun, linux-serial,
	imx, linux-arm-kernel, linux-kernel, stable, Shitalkumar Gandhi

lpuart_start_rx_dma() allocates sport->rx_ring.buf with kzalloc() and
then maps a scatterlist via dma_map_sg().  On three subsequent error
paths the function returns directly without releasing those resources:

  - when dma_map_sg() returns 0 (-EINVAL):
      ring->buf is leaked.
  - when dmaengine_slave_config() fails:
      ring->buf and the DMA mapping are leaked.
  - when dmaengine_prep_dma_cyclic() returns NULL:
      ring->buf and the DMA mapping are leaked.

The sole cleanup path, lpuart_dma_rx_free(), is only reached when
lpuart_dma_rx_use is set, and the caller lpuart_rx_dma_startup() clears
that flag on failure of lpuart_start_rx_dma().  So these resources are
permanently leaked on every failure in this function.  Repeated port
open/close or termios changes under error conditions will slowly consume
memory and leave stale streaming DMA mappings behind.

Fix it by introducing two error labels that unmap the scatterlist and
free the ring buffer as appropriate.  While here, replace the misleading
-EFAULT (bad userspace pointer) returned when dmaengine_prep_dma_cyclic()
fails with the more accurate -ENOMEM, matching how other dmaengine users
in the tree treat this failure.

No functional change on the success path.

Fixes: 5887ad43ee02 ("tty: serial: fsl_lpuart: Use cyclic DMA for Rx")
Cc: stable@vger.kernel.org

Signed-off-by: Shitalkumar Gandhi <shitalkumar.gandhi@cambiumnetworks.com>
---
 drivers/tty/serial/fsl_lpuart.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index f36d50fe056f..296a096be351 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -1376,7 +1376,8 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
 
 	if (!nent) {
 		dev_err(sport->port.dev, "DMA Rx mapping error\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_free_buf;
 	}
 
 	dma_rx_sconfig.src_addr = lpuart_dma_datareg_addr(sport);
@@ -1388,7 +1389,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
 	if (ret < 0) {
 		dev_err(sport->port.dev,
 				"DMA Rx slave config failed, err = %d\n", ret);
-		return ret;
+		goto err_unmap_sg;
 	}
 
 	sport->dma_rx_desc = dmaengine_prep_dma_cyclic(chan,
@@ -1399,7 +1400,8 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
 				 DMA_PREP_INTERRUPT);
 	if (!sport->dma_rx_desc) {
 		dev_err(sport->port.dev, "Cannot prepare cyclic DMA\n");
-		return -EFAULT;
+		ret = -ENOMEM;
+		goto err_unmap_sg;
 	}
 
 	sport->dma_rx_desc->callback = lpuart_dma_rx_complete;
@@ -1423,6 +1425,13 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
 	}
 
 	return 0;
+
+err_unmap_sg:
+	dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
+err_free_buf:
+	kfree(ring->buf);
+	ring->buf = NULL;
+	return ret;
 }
 
 static void lpuart_dma_rx_free(struct uart_port *port)
-- 
2.25.1


^ permalink raw reply related

* Re: [PATCH] serial: sh-sci: optimize max_freq determination
From: Hugo Villeneuve @ 2026-04-20 13:45 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Biju Das, Greg Kroah-Hartman, Jiri Slaby, Hugo Villeneuve,
	linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org
In-Reply-To: <CAMuHMdXGR=YOLqBMSY_syvtYbAU216Q_+xC_f8gUujYhLjRWSQ@mail.gmail.com>

Hi Geert,

On Mon, 20 Apr 2026 09:13:55 +0200
Geert Uytterhoeven <geert@linux-m68k.org> wrote:

> Hi Hugo,
> 
> On Sat, 18 Apr 2026 at 16:39, Hugo Villeneuve <hugo@hugovil.com> wrote:
> > On Sat, 18 Apr 2026 07:12:57 +0000
> > Biju Das <biju.das.jz@bp.renesas.com> wrote:
> > > > From: Hugo Villeneuve <hugo@hugovil.com>
> > > > Follow example of rsci driver to avoid code duplication and useless max_freq search when port->uartclk
> > > > is set to zero.
> > > >
> > > > Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
> > > > ---
> > > > Cc: biju.das.jz@bp.renesas.com
> > > >
> > > > Biju: if you want, feel free to pickup this patch when you resubmit your serie for "sh-sci/rsci: Fix
> > > > divide by zero and clean up baud rate logic".
> > > > ---
> > > >  drivers/tty/serial/sh-sci.c | 13 +++++++------
> > > >  1 file changed, 7 insertions(+), 6 deletions(-)
> > > >
> > > > diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index
> > > > 6c819b6b24258..dcee8b69adab2 100644
> > > > --- a/drivers/tty/serial/sh-sci.c
> > > > +++ b/drivers/tty/serial/sh-sci.c
> > > > @@ -2711,14 +2711,15 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
> > > >      * setup the baud rate generator hardware for us already.
> > > >      */
> > > >     if (!port->uartclk) {
> > > > -           baud = uart_get_baud_rate(port, termios, old, 0, 115200);
> > > > -           goto done;
> > > > +           max_freq = 115200;
> > >
> > > I have thought about this change. but the below comment made me not to do this change.
> > >
> > > <snippet from Geert>
> > > IIRC, baud == 0 can (only?) happen when using earlyprintk on a non-DT
> > > system, where the serial console should just keep on using the settings
> > > programmed by the firmware.  So any config register writes should
> > > be skipped.
> > > </snippet>
> >
> > I think Geert comments referred to the clock (port->uartclk) being zero,
> > not the baud (the baud rate cannot be zero)...
> 
> I did mean the baud variable being zero.

uart_get_baud_rate() will not return zero. Even if the baud rate
specified in termios (or the old) is set to 0 (hang up), it will return
9600...

-- 
Hugo Villeneuve

^ permalink raw reply

* Re: [PATCH v4 2/8] dt-bindings: arm: Add zx297520v3 board binding
From: Krzysztof Kozlowski @ 2026-04-20 13:00 UTC (permalink / raw)
  To: Stefan Dösinger
  Cc: Rob Herring (Arm), linux-kernel, Conor Dooley, Jonathan Corbet,
	Alexandre Belloni, Greg Kroah-Hartman, linux-doc, devicetree,
	Drew Fustini, Linus Walleij, Jiri Slaby, Russell King, soc,
	Arnd Bergmann, Krzysztof Kozlowski, linux-arm-kernel,
	linux-serial, Shuah Khan
In-Reply-To: <6264667.lOV4Wx5bFT@strix>

On Sun, Apr 19, 2026 at 11:30:04AM +0300, Stefan Dösinger wrote:
> Hi Rob,
> 
> Am Samstag, 18. April 2026, 00:08:44 Ostafrikanische Zeit schrieben Sie:
> 
> > If you already ran 'make dt_binding_check' and didn't see the above
> > error(s), then make sure 'yamllint' is installed and dt-schema is up to
> > date:
> 
> Here is a new PEBKAC issue for your mail template: I ran dt_binding_check, it 
> wrote the warning you pointed out, but I only checked the return value - which 
> indicated success. Which I guess makes sense for a warning, since there seem 
> to be a few preexisting ones. The warning itself was somewhere in the 
> scrollback because I let dt_binding_check check all the files.
> 
> So I learned I have to actually look at the output to see if there are any 
> warnings.

Same with every other tool warnings, like compiler warnings...

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH] sysrq: add optional logging of caller info on /proc/sysrq-trigger write
From: Xiang Gao @ 2026-04-20 12:03 UTC (permalink / raw)
  To: gregkh; +Cc: jirislaby, akpm, linux-kernel, linux-serial, gaoxiang17,
	Xiang Gao
In-Reply-To: <2026041830-visibly-underpaid-6dc8@gregkh>

On Sat, Apr 18, 2026 at 09:20:14AM +0200, Greg Kroah-Hartman wrote:
> We really do not want or like #ifdef in .c files, and for stuff like
> this, it is not needed at all.
[...]
> Module parameters are really not the way for stuff like this.  And why
> would such a "tiny" option need a config option at all?  If you don't
> use/need it, it's only a single bool being used?
[...]
> n is always the default, no need to add it again.

Agreed on all of these. The #ifdef, the module_param, the Kconfig
entry and the 'default n' all go away -- the feature will be
unconditional.

Before respinning I would like to align on the approach, because
your comments on the kernel log and the ancestry walk touch the
core of what this patch should actually be. Let me describe the
real use case first, since I do not think I made it clear in v1.

Use case

  - Userspace triggers are typically several processes deep:
    some service -> library -> system("echo c > /proc/sysrq-trigger")
    -> sh. The immediate writer is "sh", the actually responsible
    component is several levels up.
  - The sysrq character we care about is almost always 'c', 'b' or
    'o' -- the machine panics, reboots, or powers off as a direct
    result of the write.
  - *After* the device has come back up, we need to identify which
    userspace component issued the write. Otherwise there is no way
    to debug why devices in the field are rebooting themselves.

> The kernel log is not there for doing audits and the like, so is this
> just a debug option?

I agree that security audit belongs in the audit subsystem, not in
printk. What this patch is trying to do is post-mortem diagnostic
for crash/reboot triage, and audit_log() cannot deliver on that:

  1. audit_log() is asynchronous -- the record is queued, then
     delivered via kauditd -> netlink to a userspace subscriber.
     For sysrq c/b/o the panic/reboot happens before kauditd gets
     to run, so the record is never delivered.

  2. In our deployment environment there is no userspace auditd
     persisting records to disk, and audit records are not
     preserved across reboot. The kernel ring buffer, via pstore /
     ramoops, is the only channel whose contents survive the
     reboot and are readable on the next boot. pr_info() is the
     only mechanism that delivers into that persistent path.

I would frame this not as audit but as post-mortem diagnostic,
retitle the commit accordingly ("sysrq: log triggering task info
for post-mortem diagnostics") and drop the audit framing from the
changelog entirely.

> This might cause problems for when the system is hung and sysrq is the
> only way to reboot the box.  Have you tried it in that situation?

Fair -- the while-loop walking 5 levels has to go. The reason it
was there in v1 is the "sh from system()/popen()" case above: the
writer's comm is "sh", and the information we actually want is one
or more levels up the parent chain.

On the hung-system concern specifically: /proc/sysrq-trigger only
runs when userspace is alive enough to complete a write(), so the
keyboard sysrq path via handle_sysrq() is not affected by this
change -- my patch only touches write_sysrq_trigger(). Within that
function, rcu_read_lock() / rcu_dereference() take no locks,
allocate nothing, and are bounded-constant work, so on paper they
should not introduce a new hang. I have not yet reproduced a
partially-hung system to verify this empirically; I will do so
before v2 and report back. Please correct me if I am misreading
the concern.

That said, two options I can see, would like your steer before I
respin:

  (a) One bounded rcu_dereference() of current->real_parent.
      Logs current's pid/comm plus ppid + parent comm. One
      level, no loop. Covers the direct case
        app -> system("echo c > /proc/sysrq-trigger") -> sh
      where sh's parent is the app.

  (b) Two unrolled rcu_dereference()s -- current->real_parent
      and that task's real_parent. Still no loop, just two
      fixed dereferences. Covers the common indirect case
        service -> library -> system(...) -> sh
      where sh's parent is the thin library wrapper and the
      grandparent is the originating service, which is what we
      actually need to identify in the field.

In both cases the RCU read is a fixed number of dereferences,
not iteration over a data structure, so the total work is
bounded and constant.

I lean toward (b): one level is not enough to reach the
originating service in the indirect pattern this patch was
written for. If two dereferences in the sysrq path are still
too much, I will fall back to (a).

Which direction would you accept? I will respin based on your
answer.

Thanks,
Xiang

^ permalink raw reply

* Re: [PATCH tty v3 6/6] serial: 8250: Add support for console flow control
From: Andy Shevchenko @ 2026-04-20 10:16 UTC (permalink / raw)
  To: John Ogness
  Cc: Greg Kroah-Hartman, Jiri Slaby, linux-kernel, Ilpo Järvinen,
	Ingo Molnar, Osama Abdelkader, Krzysztof Kozlowski,
	Gerhard Engleder, Lukas Wunner, Dr. David Alan Gilbert,
	Joseph Tilahun, linux-serial
In-Reply-To: <87jyu20x9e.fsf@jogness.linutronix.de>

On Mon, Apr 20, 2026 at 12:57 PM John Ogness <john.ogness@linutronix.de> wrote:
> On 2026-04-20, Andy Shevchenko <andy.shevchenko@gmail.com> wrote:

> Note that this comment actually applies to patch 1 of the series.

I only received this mail and cover letter. Also at work I saw your
mails dropped into spam (by some corporate filters, not your fault
:-), I don't see the content. In any case I can grab the mbox by using
`b4`.


-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply

* Re: [PATCH tty v3 6/6] serial: 8250: Add support for console flow control
From: John Ogness @ 2026-04-20  9:57 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Greg Kroah-Hartman, Jiri Slaby, linux-kernel, Ilpo Järvinen,
	Ingo Molnar, Osama Abdelkader, Krzysztof Kozlowski,
	Gerhard Engleder, Lukas Wunner, Dr. David Alan Gilbert,
	Joseph Tilahun, linux-serial
In-Reply-To: <CAHp75Vf4YZVqXa7eH-RFeVsycdzoHijcWFnUbGv2PSmtPya1-w@mail.gmail.com>

On 2026-04-20, Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
>>         struct uart_8250_port *uart;
>> +       bool cons_flow;
>
>> +       /* Preserve specified console flow control. */
>> +       cons_flow = uart_get_cons_flow(&uart->port);
>
> Sorry for nit-picking, but when I see 'bool' and see a getter, I got
> confused.

Understandable. Right now the wrappers are a bit overkill since it is
just a single boolean and there are no locking constraints.

> I would rather see getter/setter to be something like
>
>     cons_flow = uart_is_cons_flow_enabled(&uart->port);
>     uart_enable_cons_flow(&uart->port);
>     uart_disable_cons_flow(&uart->port);

I will use your suggested API for v4 unless someone makes a case for a
different API (or just direct accessing with no wrappers).

Note that this comment actually applies to patch 1 of the series.

John

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox