Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

staging: gpib: Add Computer Equipment Corporation GPIB driver

Driver for Computer Equipment Corporation and compatible boards.

Signed-off-by: Dave Penkler <dpenkler@gmail.com>
Link: https://lore.kernel.org/r/20240918121908.19366-12-dpenkler@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Dave Penkler and committed by
Greg Kroah-Hartman
e1339245 e9dc6995

+440
+3
drivers/staging/gpib/cec/Makefile
··· 1 + 2 + obj-m += cec_gpib.o 3 +
+53
drivers/staging/gpib/cec/cec.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + /*************************************************************************** 4 + * copyright : (C) 2002 by Frank Mori Hess 5 + ***************************************************************************/ 6 + 7 + #include "nec7210.h" 8 + #include "gpibP.h" 9 + #include "plx9050.h" 10 + 11 + struct cec_priv { 12 + struct nec7210_priv nec7210_priv; 13 + struct pci_dev *pci_device; 14 + // base address for plx9052 pci chip 15 + unsigned long plx_iobase; 16 + unsigned int irq; 17 + }; 18 + 19 + // interfaces 20 + extern gpib_interface_t cec_pci_interface; 21 + extern gpib_interface_t cec_pcmcia_interface; 22 + 23 + // interface functions 24 + int cec_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, size_t *bytes_read); 25 + int cec_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, 26 + size_t *bytes_written); 27 + int cec_command(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written); 28 + int cec_take_control(gpib_board_t *board, int synchronous); 29 + int cec_go_to_standby(gpib_board_t *board); 30 + void cec_request_system_control(gpib_board_t *board, int request_control); 31 + void cec_interface_clear(gpib_board_t *board, int assert); 32 + void cec_remote_enable(gpib_board_t *board, int enable); 33 + int cec_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits); 34 + void cec_disable_eos(gpib_board_t *board); 35 + unsigned int cec_update_status(gpib_board_t *board, unsigned int clear_mask); 36 + int cec_primary_address(gpib_board_t *board, unsigned int address); 37 + int cec_secondary_address(gpib_board_t *board, unsigned int address, int enable); 38 + int cec_parallel_poll(gpib_board_t *board, uint8_t *result); 39 + void cec_parallel_poll_configure(gpib_board_t *board, uint8_t configuration); 40 + void cec_parallel_poll_response(gpib_board_t *board, int ist); 41 + void cec_serial_poll_response(gpib_board_t *board, uint8_t status); 42 + void cec_return_to_local(gpib_board_t *board); 43 + 44 + // interrupt service routines 45 + irqreturn_t cec_interrupt(int irq, void *arg); 46 + 47 + // utility functions 48 + void cec_free_private(gpib_board_t *board); 49 + int cec_generic_attach(gpib_board_t *board); 50 + void cec_init(struct cec_priv *priv, const gpib_board_t *board); 51 + 52 + // offset between consecutive nec7210 registers 53 + static const int cec_reg_offset = 1;
+384
drivers/staging/gpib/cec/cec_gpib.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + /*************************************************************************** 4 + * copyright : (C) 2002 by Frank Mori Hess 5 + ***************************************************************************/ 6 + 7 + #include "cec.h" 8 + #include <linux/pci.h> 9 + #include <linux/io.h> 10 + #include <linux/bitops.h> 11 + #include <asm/dma.h> 12 + #include <linux/module.h> 13 + #include <linux/slab.h> 14 + 15 + MODULE_LICENSE("GPL"); 16 + 17 + /* 18 + * GPIB interrupt service routines 19 + */ 20 + 21 + irqreturn_t cec_interrupt(int irq, void *arg) 22 + { 23 + gpib_board_t *board = arg; 24 + struct cec_priv *priv = board->private_data; 25 + unsigned long flags; 26 + irqreturn_t retval; 27 + 28 + spin_lock_irqsave(&board->spinlock, flags); 29 + retval = nec7210_interrupt(board, &priv->nec7210_priv); 30 + spin_unlock_irqrestore(&board->spinlock, flags); 31 + return retval; 32 + } 33 + 34 + #define CEC_VENDOR_ID 0x12fc 35 + #define CEC_DEV_ID 0x5cec 36 + #define CEC_SUBID 0x9050 37 + 38 + static int cec_pci_attach(gpib_board_t *board, const gpib_board_config_t *config); 39 + 40 + static void cec_pci_detach(gpib_board_t *board); 41 + 42 + // wrappers for interface functions 43 + int cec_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, size_t *bytes_read) 44 + { 45 + struct cec_priv *priv = board->private_data; 46 + 47 + return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read); 48 + } 49 + 50 + int cec_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, 51 + size_t *bytes_written) 52 + { 53 + struct cec_priv *priv = board->private_data; 54 + 55 + return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); 56 + } 57 + 58 + int cec_command(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written) 59 + { 60 + struct cec_priv *priv = board->private_data; 61 + 62 + return nec7210_command(board, &priv->nec7210_priv, buffer, length, bytes_written); 63 + } 64 + 65 + int cec_take_control(gpib_board_t *board, int synchronous) 66 + { 67 + struct cec_priv *priv = board->private_data; 68 + 69 + return nec7210_take_control(board, &priv->nec7210_priv, synchronous); 70 + } 71 + 72 + int cec_go_to_standby(gpib_board_t *board) 73 + { 74 + struct cec_priv *priv = board->private_data; 75 + 76 + return nec7210_go_to_standby(board, &priv->nec7210_priv); 77 + } 78 + 79 + void cec_request_system_control(gpib_board_t *board, int request_control) 80 + { 81 + struct cec_priv *priv = board->private_data; 82 + 83 + nec7210_request_system_control(board, &priv->nec7210_priv, request_control); 84 + } 85 + 86 + void cec_interface_clear(gpib_board_t *board, int assert) 87 + { 88 + struct cec_priv *priv = board->private_data; 89 + 90 + nec7210_interface_clear(board, &priv->nec7210_priv, assert); 91 + } 92 + 93 + void cec_remote_enable(gpib_board_t *board, int enable) 94 + { 95 + struct cec_priv *priv = board->private_data; 96 + 97 + nec7210_remote_enable(board, &priv->nec7210_priv, enable); 98 + } 99 + 100 + int cec_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits) 101 + { 102 + struct cec_priv *priv = board->private_data; 103 + 104 + return nec7210_enable_eos(board, &priv->nec7210_priv, eos_byte, compare_8_bits); 105 + } 106 + 107 + void cec_disable_eos(gpib_board_t *board) 108 + { 109 + struct cec_priv *priv = board->private_data; 110 + 111 + nec7210_disable_eos(board, &priv->nec7210_priv); 112 + } 113 + 114 + unsigned int cec_update_status(gpib_board_t *board, unsigned int clear_mask) 115 + { 116 + struct cec_priv *priv = board->private_data; 117 + 118 + return nec7210_update_status(board, &priv->nec7210_priv, clear_mask); 119 + } 120 + 121 + int cec_primary_address(gpib_board_t *board, unsigned int address) 122 + { 123 + struct cec_priv *priv = board->private_data; 124 + 125 + return nec7210_primary_address(board, &priv->nec7210_priv, address); 126 + } 127 + 128 + int cec_secondary_address(gpib_board_t *board, unsigned int address, int enable) 129 + { 130 + struct cec_priv *priv = board->private_data; 131 + 132 + return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); 133 + } 134 + 135 + int cec_parallel_poll(gpib_board_t *board, uint8_t *result) 136 + { 137 + struct cec_priv *priv = board->private_data; 138 + 139 + return nec7210_parallel_poll(board, &priv->nec7210_priv, result); 140 + } 141 + 142 + void cec_parallel_poll_configure(gpib_board_t *board, uint8_t config) 143 + { 144 + struct cec_priv *priv = board->private_data; 145 + 146 + nec7210_parallel_poll_configure(board, &priv->nec7210_priv, config); 147 + } 148 + 149 + void cec_parallel_poll_response(gpib_board_t *board, int ist) 150 + { 151 + struct cec_priv *priv = board->private_data; 152 + 153 + nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist); 154 + } 155 + 156 + void cec_serial_poll_response(gpib_board_t *board, uint8_t status) 157 + { 158 + struct cec_priv *priv = board->private_data; 159 + 160 + nec7210_serial_poll_response(board, &priv->nec7210_priv, status); 161 + } 162 + 163 + static uint8_t cec_serial_poll_status(gpib_board_t *board) 164 + { 165 + struct cec_priv *priv = board->private_data; 166 + 167 + return nec7210_serial_poll_status(board, &priv->nec7210_priv); 168 + } 169 + 170 + static unsigned int cec_t1_delay(gpib_board_t *board, unsigned int nano_sec) 171 + { 172 + struct cec_priv *priv = board->private_data; 173 + 174 + return nec7210_t1_delay(board, &priv->nec7210_priv, nano_sec); 175 + } 176 + 177 + void cec_return_to_local(gpib_board_t *board) 178 + { 179 + struct cec_priv *priv = board->private_data; 180 + 181 + nec7210_return_to_local(board, &priv->nec7210_priv); 182 + } 183 + 184 + gpib_interface_t cec_pci_interface = { 185 + name: "cec_pci", 186 + attach : cec_pci_attach, 187 + detach : cec_pci_detach, 188 + read : cec_read, 189 + write : cec_write, 190 + command : cec_command, 191 + take_control : cec_take_control, 192 + go_to_standby : cec_go_to_standby, 193 + request_system_control : cec_request_system_control, 194 + interface_clear : cec_interface_clear, 195 + remote_enable : cec_remote_enable, 196 + enable_eos : cec_enable_eos, 197 + disable_eos : cec_disable_eos, 198 + parallel_poll : cec_parallel_poll, 199 + parallel_poll_configure : cec_parallel_poll_configure, 200 + parallel_poll_response : cec_parallel_poll_response, 201 + local_parallel_poll_mode : NULL, // XXX 202 + line_status : NULL, //XXX 203 + update_status : cec_update_status, 204 + primary_address : cec_primary_address, 205 + secondary_address : cec_secondary_address, 206 + serial_poll_response : cec_serial_poll_response, 207 + serial_poll_status : cec_serial_poll_status, 208 + t1_delay : cec_t1_delay, 209 + return_to_local : cec_return_to_local, 210 + }; 211 + 212 + static int cec_allocate_private(gpib_board_t *board) 213 + { 214 + struct cec_priv *priv; 215 + 216 + board->private_data = kmalloc(sizeof(struct cec_priv), GFP_KERNEL); 217 + if (!board->private_data) 218 + return -1; 219 + priv = board->private_data; 220 + memset(priv, 0, sizeof(struct cec_priv)); 221 + init_nec7210_private(&priv->nec7210_priv); 222 + return 0; 223 + } 224 + 225 + void cec_free_private(gpib_board_t *board) 226 + { 227 + kfree(board->private_data); 228 + board->private_data = NULL; 229 + } 230 + 231 + int cec_generic_attach(gpib_board_t *board) 232 + { 233 + struct cec_priv *cec_priv; 234 + struct nec7210_priv *nec_priv; 235 + 236 + board->status = 0; 237 + 238 + if (cec_allocate_private(board)) 239 + return -ENOMEM; 240 + cec_priv = board->private_data; 241 + nec_priv = &cec_priv->nec7210_priv; 242 + nec_priv->read_byte = nec7210_ioport_read_byte; 243 + nec_priv->write_byte = nec7210_ioport_write_byte; 244 + nec_priv->offset = cec_reg_offset; 245 + nec_priv->type = NEC7210; // guess 246 + return 0; 247 + } 248 + 249 + void cec_init(struct cec_priv *cec_priv, const gpib_board_t *board) 250 + { 251 + struct nec7210_priv *nec_priv = &cec_priv->nec7210_priv; 252 + 253 + nec7210_board_reset(nec_priv, board); 254 + 255 + /* set internal counter register for 8 MHz input clock */ 256 + write_byte(nec_priv, ICR | 8, AUXMR); 257 + 258 + nec7210_board_online(nec_priv, board); 259 + } 260 + 261 + int cec_pci_attach(gpib_board_t *board, const gpib_board_config_t *config) 262 + { 263 + struct cec_priv *cec_priv; 264 + struct nec7210_priv *nec_priv; 265 + int isr_flags = 0; 266 + int retval; 267 + 268 + retval = cec_generic_attach(board); 269 + if (retval) 270 + return retval; 271 + 272 + cec_priv = board->private_data; 273 + nec_priv = &cec_priv->nec7210_priv; 274 + 275 + // find board 276 + cec_priv->pci_device = NULL; 277 + while ((cec_priv->pci_device = 278 + gpib_pci_get_device(config, CEC_VENDOR_ID, 279 + CEC_DEV_ID, cec_priv->pci_device))) { 280 + // check for board with plx9050 controller 281 + if (cec_priv->pci_device->subsystem_device == CEC_SUBID) 282 + break; 283 + } 284 + if (!cec_priv->pci_device) { 285 + pr_err("gpib: no cec PCI board found\n"); 286 + return -1; 287 + } 288 + 289 + if (pci_enable_device(cec_priv->pci_device)) { 290 + pr_err("error enabling pci device\n"); 291 + return -1; 292 + } 293 + 294 + if (pci_request_regions(cec_priv->pci_device, "cec-gpib")) 295 + return -1; 296 + 297 + cec_priv->plx_iobase = pci_resource_start(cec_priv->pci_device, 1); 298 + pr_info(" plx9050 base address 0x%lx\n", cec_priv->plx_iobase); 299 + nec_priv->iobase = (void *)(pci_resource_start(cec_priv->pci_device, 3)); 300 + pr_info(" nec7210 base address 0x%p\n", nec_priv->iobase); 301 + 302 + isr_flags |= IRQF_SHARED; 303 + if (request_irq(cec_priv->pci_device->irq, cec_interrupt, isr_flags, "pci-gpib", board)) { 304 + pr_err("gpib: can't request IRQ %d\n", cec_priv->pci_device->irq); 305 + return -1; 306 + } 307 + cec_priv->irq = cec_priv->pci_device->irq; 308 + if (gpib_request_pseudo_irq(board, cec_interrupt)) { 309 + pr_err("cec: failed to allocate pseudo irq\n"); 310 + return -1; 311 + } 312 + cec_init(cec_priv, board); 313 + 314 + // enable interrupts on plx chip 315 + outl(PLX9050_LINTR1_EN_BIT | PLX9050_LINTR1_POLARITY_BIT | PLX9050_PCI_INTR_EN_BIT, 316 + cec_priv->plx_iobase + PLX9050_INTCSR_REG); 317 + 318 + return 0; 319 + } 320 + 321 + void cec_pci_detach(gpib_board_t *board) 322 + { 323 + struct cec_priv *cec_priv = board->private_data; 324 + struct nec7210_priv *nec_priv; 325 + 326 + if (cec_priv) { 327 + nec_priv = &cec_priv->nec7210_priv; 328 + gpib_free_pseudo_irq(board); 329 + if (cec_priv->irq) { 330 + // disable plx9050 interrupts 331 + outl(0, cec_priv->plx_iobase + PLX9050_INTCSR_REG); 332 + free_irq(cec_priv->irq, board); 333 + } 334 + if (nec_priv->iobase) { 335 + nec7210_board_reset(nec_priv, board); 336 + pci_release_regions(cec_priv->pci_device); 337 + } 338 + if (cec_priv->pci_device) 339 + pci_dev_put(cec_priv->pci_device); 340 + } 341 + cec_free_private(board); 342 + } 343 + 344 + static int cec_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) 345 + { 346 + return 0; 347 + } 348 + 349 + static const struct pci_device_id cec_pci_table[] = { 350 + {CEC_VENDOR_ID, CEC_DEV_ID, PCI_ANY_ID, CEC_SUBID, 0, 0, 0 }, 351 + {0} 352 + }; 353 + MODULE_DEVICE_TABLE(pci, cec_pci_table); 354 + 355 + static struct pci_driver cec_pci_driver = { 356 + .name = "cec_gpib", 357 + .id_table = cec_pci_table, 358 + .probe = &cec_pci_probe 359 + }; 360 + 361 + static int __init cec_init_module(void) 362 + { 363 + int result; 364 + 365 + result = pci_register_driver(&cec_pci_driver); 366 + if (result) { 367 + pr_err("cec_gpib: pci_driver_register failed!\n"); 368 + return result; 369 + } 370 + 371 + gpib_register_driver(&cec_pci_interface, THIS_MODULE); 372 + 373 + return 0; 374 + } 375 + 376 + static void cec_exit_module(void) 377 + { 378 + gpib_unregister_driver(&cec_pci_interface); 379 + 380 + pci_unregister_driver(&cec_pci_driver); 381 + } 382 + 383 + module_init(cec_init_module); 384 + module_exit(cec_exit_module);