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

Configure Feed

Select the types of activity you want to include in your feed.

comedi: dmm32at: serialize use of paged registers

Some of the hardware registers of the DMM-32-AT board are multiplexed,
using the least significant two bits of the Miscellaneous Control
register to select the function of registers at offsets 12 to 15:

00 => 8254 timer/counter registers are accessible
01 => 8255 digital I/O registers are accessible
10 => Reserved
11 => Calibration registers are accessible

The interrupt service routine (`dmm32at_isr()`) clobbers the bottom two
bits of the register with value 00, which would interfere with access to
the 8255 registers by the `dm32at_8255_io()` function (used for Comedi
instruction handling on the digital I/O subdevice).

Make use of the generic Comedi device spin-lock `dev->spinlock` (which
is otherwise unused by this driver) to serialize access to the
miscellaneous control register and paged registers.

Fixes: 3c501880ac44 ("Staging: comedi: add dmm32at driver")
Cc: stable@vger.kernel.org
Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Link: https://patch.msgid.link/20260112162835.91688-1-abbotti@mev.co.uk
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Ian Abbott and committed by
Greg Kroah-Hartman
e03b29b5 06d5a7af

+30 -2
+30 -2
drivers/comedi/drivers/dmm32at.c
··· 330 330 331 331 static void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec) 332 332 { 333 + unsigned long irq_flags; 333 334 unsigned char lo1, lo2, hi2; 334 335 unsigned short both2; 335 336 ··· 342 341 343 342 /* set counter clocks to 10MHz, disable all aux dio */ 344 343 outb(0, dev->iobase + DMM32AT_CTRDIO_CFG_REG); 344 + 345 + /* serialize access to control register and paged registers */ 346 + spin_lock_irqsave(&dev->spinlock, irq_flags); 345 347 346 348 /* get access to the clock regs */ 347 349 outb(DMM32AT_CTRL_PAGE_8254, dev->iobase + DMM32AT_CTRL_REG); ··· 358 354 outb(lo2, dev->iobase + DMM32AT_CLK2); 359 355 outb(hi2, dev->iobase + DMM32AT_CLK2); 360 356 357 + spin_unlock_irqrestore(&dev->spinlock, irq_flags); 358 + 361 359 /* enable the ai conversion interrupt and the clock to start scans */ 362 360 outb(DMM32AT_INTCLK_ADINT | 363 361 DMM32AT_INTCLK_CLKEN | DMM32AT_INTCLK_CLKSEL, ··· 369 363 static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 370 364 { 371 365 struct comedi_cmd *cmd = &s->async->cmd; 366 + unsigned long irq_flags; 372 367 int ret; 373 368 374 369 dmm32at_ai_set_chanspec(dev, s, cmd->chanlist[0], cmd->chanlist_len); 375 370 371 + /* serialize access to control register and paged registers */ 372 + spin_lock_irqsave(&dev->spinlock, irq_flags); 373 + 376 374 /* reset the interrupt just in case */ 377 375 outb(DMM32AT_CTRL_INTRST, dev->iobase + DMM32AT_CTRL_REG); 376 + 377 + spin_unlock_irqrestore(&dev->spinlock, irq_flags); 378 378 379 379 /* 380 380 * wait for circuit to settle ··· 441 429 comedi_handle_events(dev, s); 442 430 } 443 431 432 + /* serialize access to control register and paged registers */ 433 + spin_lock(&dev->spinlock); 434 + 444 435 /* reset the interrupt */ 445 436 outb(DMM32AT_CTRL_INTRST, dev->iobase + DMM32AT_CTRL_REG); 437 + 438 + spin_unlock(&dev->spinlock); 446 439 return IRQ_HANDLED; 447 440 } 448 441 ··· 498 481 static int dmm32at_8255_io(struct comedi_device *dev, 499 482 int dir, int port, int data, unsigned long regbase) 500 483 { 484 + unsigned long irq_flags; 485 + int ret; 486 + 487 + /* serialize access to control register and paged registers */ 488 + spin_lock_irqsave(&dev->spinlock, irq_flags); 489 + 501 490 /* get access to the DIO regs */ 502 491 outb(DMM32AT_CTRL_PAGE_8255, dev->iobase + DMM32AT_CTRL_REG); 503 492 504 493 if (dir) { 505 494 outb(data, dev->iobase + regbase + port); 506 - return 0; 495 + ret = 0; 496 + } else { 497 + ret = inb(dev->iobase + regbase + port); 507 498 } 508 - return inb(dev->iobase + regbase + port); 499 + 500 + spin_unlock_irqrestore(&dev->spinlock, irq_flags); 501 + 502 + return ret; 509 503 } 510 504 511 505 /* Make sure the board is there and put it to a known state */