Commit d9795562 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tty-3.10-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial fixes from Greg Kroah-Hartman:
 "Here are some tty / serial driver fixes for 3.10-rc2.

  Nothing huge, although the rocket driver fix looks large, it's just
  moving the code around to fix the reported build issues in it.  Other
  than that, this has the fix for the of-reported lockdep warning from
  the vt layer, as well as some other needed bugfixes.

  All of these have been in linux-next for a while"

* tag 'tty-3.10-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  tty: mxser: Fix build warning introduced by dfc7b837 (Re: linux-next: build warning after merge of the tty.current tree)
  tty: mxser: fix usage of opmode_ioaddr
  serial: 8250_dw: add ACPI ID for Intel BayTrail
  TTY: Fix tty miss restart after we turn off flow-control
  tty/vt: Fix vc_deallocate() lock order
  TTY: ehv_bytechan: add missing platform_driver_unregister() when module exit
  TTY: rocket, fix more no-PCI warnings
  serial: mcf: missing uart_unregister_driver() on error in mcf_init()
  tty: serial: mpc5xxx: fix error handing in mpc52xx_uart_init()
  serial: samsung: add missing platform_driver_unregister() when module exit
  serial: pl011: protect attribute read from NULL platform data struct
  tty: nwpserial: Pass correct pointer to free_irq()
  serial: 8250_dw: Add valid clk pointer check
parents 388c2896 e037f95f
...@@ -859,6 +859,7 @@ static int __init ehv_bc_init(void) ...@@ -859,6 +859,7 @@ static int __init ehv_bc_init(void)
*/ */
static void __exit ehv_bc_exit(void) static void __exit ehv_bc_exit(void)
{ {
platform_driver_unregister(&ehv_bc_tty_driver);
tty_unregister_driver(ehv_bc_driver); tty_unregister_driver(ehv_bc_driver);
put_tty_driver(ehv_bc_driver); put_tty_driver(ehv_bc_driver);
kfree(bcs); kfree(bcs);
......
...@@ -1618,8 +1618,12 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) ...@@ -1618,8 +1618,12 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
if (ip->type == PORT_16550A) if (ip->type == PORT_16550A)
me->fifo[p] = 1; me->fifo[p] = 1;
if (ip->board->chip_flag == MOXA_MUST_MU860_HWID) {
opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2); opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2);
opmode &= OP_MODE_MASK; opmode &= OP_MODE_MASK;
} else {
opmode = RS232_MODE;
}
me->iftype[p] = opmode; me->iftype[p] = opmode;
mutex_unlock(&port->mutex); mutex_unlock(&port->mutex);
} }
...@@ -1676,6 +1680,9 @@ static int mxser_ioctl(struct tty_struct *tty, ...@@ -1676,6 +1680,9 @@ static int mxser_ioctl(struct tty_struct *tty,
int shiftbit; int shiftbit;
unsigned char val, mask; unsigned char val, mask;
if (info->board->chip_flag != MOXA_MUST_MU860_HWID)
return -EFAULT;
p = tty->index % 4; p = tty->index % 4;
if (cmd == MOXA_SET_OP_MODE) { if (cmd == MOXA_SET_OP_MODE) {
if (get_user(opmode, (int __user *) argp)) if (get_user(opmode, (int __user *) argp))
......
...@@ -1573,6 +1573,14 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) ...@@ -1573,6 +1573,14 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
ldata->real_raw = 0; ldata->real_raw = 0;
} }
n_tty_set_room(tty); n_tty_set_room(tty);
/*
* Fix tty hang when I_IXON(tty) is cleared, but the tty
* been stopped by STOP_CHAR(tty) before it.
*/
if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) {
start_tty(tty);
}
/* The termios change make the tty ready for I/O */ /* The termios change make the tty ready for I/O */
wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->write_wait);
wake_up_interruptible(&tty->read_wait); wake_up_interruptible(&tty->read_wait);
......
...@@ -150,12 +150,14 @@ static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = { ...@@ -150,12 +150,14 @@ static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = {
AIOP_INTR_BIT_3 AIOP_INTR_BIT_3
}; };
#ifdef CONFIG_PCI
static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = { static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = {
UPCI_AIOP_INTR_BIT_0, UPCI_AIOP_INTR_BIT_0,
UPCI_AIOP_INTR_BIT_1, UPCI_AIOP_INTR_BIT_1,
UPCI_AIOP_INTR_BIT_2, UPCI_AIOP_INTR_BIT_2,
UPCI_AIOP_INTR_BIT_3 UPCI_AIOP_INTR_BIT_3
}; };
#endif
static Byte_t RData[RDATASIZE] = { static Byte_t RData[RDATASIZE] = {
0x00, 0x09, 0xf6, 0x82, 0x00, 0x09, 0xf6, 0x82,
...@@ -227,7 +229,6 @@ static unsigned long nextLineNumber; ...@@ -227,7 +229,6 @@ static unsigned long nextLineNumber;
static int __init init_ISA(int i); static int __init init_ISA(int i);
static void rp_wait_until_sent(struct tty_struct *tty, int timeout); static void rp_wait_until_sent(struct tty_struct *tty, int timeout);
static void rp_flush_buffer(struct tty_struct *tty); static void rp_flush_buffer(struct tty_struct *tty);
static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model);
static unsigned char GetLineNumber(int ctrl, int aiop, int ch); static unsigned char GetLineNumber(int ctrl, int aiop, int ch);
static unsigned char SetLineNumber(int ctrl, int aiop, int ch); static unsigned char SetLineNumber(int ctrl, int aiop, int ch);
static void rp_start(struct tty_struct *tty); static void rp_start(struct tty_struct *tty);
...@@ -241,11 +242,6 @@ static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags); ...@@ -241,11 +242,6 @@ static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags);
static void sModemReset(CONTROLLER_T * CtlP, int chan, int on); static void sModemReset(CONTROLLER_T * CtlP, int chan, int on);
static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on); static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on);
static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data); static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data);
static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
ByteIO_t * AiopIOList, int AiopIOListSize,
WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
int PeriodicOnly, int altChanRingIndicator,
int UPCIRingInd);
static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
ByteIO_t * AiopIOList, int AiopIOListSize, ByteIO_t * AiopIOList, int AiopIOListSize,
int IRQNum, Byte_t Frequency, int PeriodicOnly); int IRQNum, Byte_t Frequency, int PeriodicOnly);
...@@ -1775,6 +1771,145 @@ static DEFINE_PCI_DEVICE_TABLE(rocket_pci_ids) = { ...@@ -1775,6 +1771,145 @@ static DEFINE_PCI_DEVICE_TABLE(rocket_pci_ids) = {
}; };
MODULE_DEVICE_TABLE(pci, rocket_pci_ids); MODULE_DEVICE_TABLE(pci, rocket_pci_ids);
/* Resets the speaker controller on RocketModem II and III devices */
static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
{
ByteIO_t addr;
/* RocketModem II speaker control is at the 8th port location of offset 0x40 */
if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
addr = CtlP->AiopIO[0] + 0x4F;
sOutB(addr, 0);
}
/* RocketModem III speaker control is at the 1st port location of offset 0x80 */
if ((model == MODEL_UPCI_RM3_8PORT)
|| (model == MODEL_UPCI_RM3_4PORT)) {
addr = CtlP->AiopIO[0] + 0x88;
sOutB(addr, 0);
}
}
/***************************************************************************
Function: sPCIInitController
Purpose: Initialization of controller global registers and controller
structure.
Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
IRQNum,Frequency,PeriodicOnly)
CONTROLLER_T *CtlP; Ptr to controller structure
int CtlNum; Controller number
ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
This list must be in the order the AIOPs will be found on the
controller. Once an AIOP in the list is not found, it is
assumed that there are no more AIOPs on the controller.
int AiopIOListSize; Number of addresses in AiopIOList
int IRQNum; Interrupt Request number. Can be any of the following:
0: Disable global interrupts
3: IRQ 3
4: IRQ 4
5: IRQ 5
9: IRQ 9
10: IRQ 10
11: IRQ 11
12: IRQ 12
15: IRQ 15
Byte_t Frequency: A flag identifying the frequency
of the periodic interrupt, can be any one of the following:
FREQ_DIS - periodic interrupt disabled
FREQ_137HZ - 137 Hertz
FREQ_69HZ - 69 Hertz
FREQ_34HZ - 34 Hertz
FREQ_17HZ - 17 Hertz
FREQ_9HZ - 9 Hertz
FREQ_4HZ - 4 Hertz
If IRQNum is set to 0 the Frequency parameter is
overidden, it is forced to a value of FREQ_DIS.
int PeriodicOnly: 1 if all interrupts except the periodic
interrupt are to be blocked.
0 is both the periodic interrupt and
other channel interrupts are allowed.
If IRQNum is set to 0 the PeriodicOnly parameter is
overidden, it is forced to a value of 0.
Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
initialization failed.
Comments:
If periodic interrupts are to be disabled but AIOP interrupts
are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
If interrupts are to be completely disabled set IRQNum to 0.
Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
invalid combination.
This function performs initialization of global interrupt modes,
but it does not actually enable global interrupts. To enable
and disable global interrupts use functions sEnGlobalInt() and
sDisGlobalInt(). Enabling of global interrupts is normally not
done until all other initializations are complete.
Even if interrupts are globally enabled, they must also be
individually enabled for each channel that is to generate
interrupts.
Warnings: No range checking on any of the parameters is done.
No context switches are allowed while executing this function.
After this function all AIOPs on the controller are disabled,
they can be enabled with sEnAiop().
*/
static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
ByteIO_t * AiopIOList, int AiopIOListSize,
WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
int PeriodicOnly, int altChanRingIndicator,
int UPCIRingInd)
{
int i;
ByteIO_t io;
CtlP->AltChanRingIndicator = altChanRingIndicator;
CtlP->UPCIRingInd = UPCIRingInd;
CtlP->CtlNum = CtlNum;
CtlP->CtlID = CTLID_0001; /* controller release 1 */
CtlP->BusType = isPCI; /* controller release 1 */
if (ConfigIO) {
CtlP->isUPCI = 1;
CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL;
CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL;
CtlP->AiopIntrBits = upci_aiop_intr_bits;
} else {
CtlP->isUPCI = 0;
CtlP->PCIIO =
(WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC);
CtlP->AiopIntrBits = aiop_intr_bits;
}
sPCIControllerEOI(CtlP); /* clear EOI if warm init */
/* Init AIOPs */
CtlP->NumAiop = 0;
for (i = 0; i < AiopIOListSize; i++) {
io = AiopIOList[i];
CtlP->AiopIO[i] = (WordIO_t) io;
CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
break; /* done looking for AIOPs */
CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
sOutB(io + _INDX_DATA, sClockPrescale);
CtlP->NumAiop++; /* bump count of AIOPs */
}
if (CtlP->NumAiop == 0)
return (-1);
else
return (CtlP->NumAiop);
}
/* /*
* Called when a PCI card is found. Retrieves and stores model information, * Called when a PCI card is found. Retrieves and stores model information,
* init's aiopic and serial port hardware. * init's aiopic and serial port hardware.
...@@ -2519,147 +2654,6 @@ static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, ...@@ -2519,147 +2654,6 @@ static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
return (CtlP->NumAiop); return (CtlP->NumAiop);
} }
#ifdef CONFIG_PCI
/***************************************************************************
Function: sPCIInitController
Purpose: Initialization of controller global registers and controller
structure.
Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
IRQNum,Frequency,PeriodicOnly)
CONTROLLER_T *CtlP; Ptr to controller structure
int CtlNum; Controller number
ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
This list must be in the order the AIOPs will be found on the
controller. Once an AIOP in the list is not found, it is
assumed that there are no more AIOPs on the controller.
int AiopIOListSize; Number of addresses in AiopIOList
int IRQNum; Interrupt Request number. Can be any of the following:
0: Disable global interrupts
3: IRQ 3
4: IRQ 4
5: IRQ 5
9: IRQ 9
10: IRQ 10
11: IRQ 11
12: IRQ 12
15: IRQ 15
Byte_t Frequency: A flag identifying the frequency
of the periodic interrupt, can be any one of the following:
FREQ_DIS - periodic interrupt disabled
FREQ_137HZ - 137 Hertz
FREQ_69HZ - 69 Hertz
FREQ_34HZ - 34 Hertz
FREQ_17HZ - 17 Hertz
FREQ_9HZ - 9 Hertz
FREQ_4HZ - 4 Hertz
If IRQNum is set to 0 the Frequency parameter is
overidden, it is forced to a value of FREQ_DIS.
int PeriodicOnly: 1 if all interrupts except the periodic
interrupt are to be blocked.
0 is both the periodic interrupt and
other channel interrupts are allowed.
If IRQNum is set to 0 the PeriodicOnly parameter is
overidden, it is forced to a value of 0.
Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
initialization failed.
Comments:
If periodic interrupts are to be disabled but AIOP interrupts
are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
If interrupts are to be completely disabled set IRQNum to 0.
Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
invalid combination.
This function performs initialization of global interrupt modes,
but it does not actually enable global interrupts. To enable
and disable global interrupts use functions sEnGlobalInt() and
sDisGlobalInt(). Enabling of global interrupts is normally not
done until all other initializations are complete.
Even if interrupts are globally enabled, they must also be
individually enabled for each channel that is to generate
interrupts.
Warnings: No range checking on any of the parameters is done.
No context switches are allowed while executing this function.
After this function all AIOPs on the controller are disabled,
they can be enabled with sEnAiop().
*/
static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
ByteIO_t * AiopIOList, int AiopIOListSize,
WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
int PeriodicOnly, int altChanRingIndicator,
int UPCIRingInd)
{
int i;
ByteIO_t io;
CtlP->AltChanRingIndicator = altChanRingIndicator;
CtlP->UPCIRingInd = UPCIRingInd;
CtlP->CtlNum = CtlNum;
CtlP->CtlID = CTLID_0001; /* controller release 1 */
CtlP->BusType = isPCI; /* controller release 1 */
if (ConfigIO) {
CtlP->isUPCI = 1;
CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL;
CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL;
CtlP->AiopIntrBits = upci_aiop_intr_bits;
} else {
CtlP->isUPCI = 0;
CtlP->PCIIO =
(WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC);
CtlP->AiopIntrBits = aiop_intr_bits;
}
sPCIControllerEOI(CtlP); /* clear EOI if warm init */
/* Init AIOPs */
CtlP->NumAiop = 0;
for (i = 0; i < AiopIOListSize; i++) {
io = AiopIOList[i];
CtlP->AiopIO[i] = (WordIO_t) io;
CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
break; /* done looking for AIOPs */
CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
sOutB(io + _INDX_DATA, sClockPrescale);
CtlP->NumAiop++; /* bump count of AIOPs */
}
if (CtlP->NumAiop == 0)
return (-1);
else
return (CtlP->NumAiop);
}
/* Resets the speaker controller on RocketModem II and III devices */
static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
{
ByteIO_t addr;
/* RocketModem II speaker control is at the 8th port location of offset 0x40 */
if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
addr = CtlP->AiopIO[0] + 0x4F;
sOutB(addr, 0);
}
/* RocketModem III speaker control is at the 1st port location of offset 0x80 */
if ((model == MODEL_UPCI_RM3_8PORT)
|| (model == MODEL_UPCI_RM3_4PORT)) {
addr = CtlP->AiopIO[0] + 0x88;
sOutB(addr, 0);
}
}
#endif
/*************************************************************************** /***************************************************************************
Function: sReadAiopID Function: sReadAiopID
Purpose: Read the AIOP idenfication number directly from an AIOP. Purpose: Read the AIOP idenfication number directly from an AIOP.
......
...@@ -338,6 +338,7 @@ static int dw8250_runtime_suspend(struct device *dev) ...@@ -338,6 +338,7 @@ static int dw8250_runtime_suspend(struct device *dev)
{ {
struct dw8250_data *data = dev_get_drvdata(dev); struct dw8250_data *data = dev_get_drvdata(dev);
if (!IS_ERR(data->clk))
clk_disable_unprepare(data->clk); clk_disable_unprepare(data->clk);
return 0; return 0;
...@@ -347,6 +348,7 @@ static int dw8250_runtime_resume(struct device *dev) ...@@ -347,6 +348,7 @@ static int dw8250_runtime_resume(struct device *dev)
{ {
struct dw8250_data *data = dev_get_drvdata(dev); struct dw8250_data *data = dev_get_drvdata(dev);
if (!IS_ERR(data->clk))
clk_prepare_enable(data->clk); clk_prepare_enable(data->clk);
return 0; return 0;
...@@ -367,6 +369,7 @@ MODULE_DEVICE_TABLE(of, dw8250_of_match); ...@@ -367,6 +369,7 @@ MODULE_DEVICE_TABLE(of, dw8250_of_match);
static const struct acpi_device_id dw8250_acpi_match[] = { static const struct acpi_device_id dw8250_acpi_match[] = {
{ "INT33C4", 0 }, { "INT33C4", 0 },
{ "INT33C5", 0 }, { "INT33C5", 0 },
{ "80860F0A", 0 },
{ }, { },
}; };
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
......
...@@ -332,7 +332,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * ...@@ -332,7 +332,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *
dmaengine_slave_config(chan, &rx_conf); dmaengine_slave_config(chan, &rx_conf);
uap->dmarx.chan = chan; uap->dmarx.chan = chan;
if (plat->dma_rx_poll_enable) { if (plat && plat->dma_rx_poll_enable) {
/* Set poll rate if specified. */ /* Set poll rate if specified. */
if (plat->dma_rx_poll_rate) { if (plat->dma_rx_poll_rate) {
uap->dmarx.auto_poll_rate = false; uap->dmarx.auto_poll_rate = false;
......
...@@ -707,8 +707,10 @@ static int __init mcf_init(void) ...@@ -707,8 +707,10 @@ static int __init mcf_init(void)
if (rc) if (rc)
return rc; return rc;
rc = platform_driver_register(&mcf_platform_driver); rc = platform_driver_register(&mcf_platform_driver);
if (rc) if (rc) {
uart_unregister_driver(&mcf_driver);
return rc; return rc;
}
return 0; return 0;
} }
......
...@@ -1497,18 +1497,23 @@ mpc52xx_uart_init(void) ...@@ -1497,18 +1497,23 @@ mpc52xx_uart_init(void)
if (psc_ops && psc_ops->fifoc_init) { if (psc_ops && psc_ops->fifoc_init) {
ret = psc_ops->fifoc_init(); ret = psc_ops->fifoc_init();
if (ret) if (ret)
return ret; goto err_init;
} }
ret = platform_driver_register(&mpc52xx_uart_of_driver); ret = platform_driver_register(&mpc52xx_uart_of_driver);
if (ret) { if (ret) {
printk(KERN_ERR "%s: platform_driver_register failed (%i)\n", printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",
__FILE__, ret); __FILE__, ret);
uart_unregister_driver(&mpc52xx_uart_driver); goto err_reg;
return ret;
} }
return 0; return 0;
err_reg:
if (psc_ops && psc_ops->fifoc_uninit)
psc_ops->fifoc_uninit();
err_init:
uart_unregister_driver(&mpc52xx_uart_driver);
return ret;
} }
static void __exit static void __exit
......
...@@ -199,7 +199,7 @@ static void nwpserial_shutdown(struct uart_port *port) ...@@ -199,7 +199,7 @@ static void nwpserial_shutdown(struct uart_port *port)
dcr_write(up->dcr_host, UART_IER, up->ier); dcr_write(up->dcr_host, UART_IER, up->ier);
/* free irq */ /* free irq */
free_irq(up->port.irq, port); free_irq(up->port.irq, up);
} }
static int nwpserial_verify_port(struct uart_port *port, static int nwpserial_verify_port(struct uart_port *port,
......
...@@ -1803,6 +1803,7 @@ static int __init s3c24xx_serial_modinit(void) ...@@ -1803,6 +1803,7 @@ static int __init s3c24xx_serial_modinit(void)
static void __exit s3c24xx_serial_modexit(void) static void __exit s3c24xx_serial_modexit(void)
{ {
platform_driver_unregister(&samsung_serial_driver);
uart_unregister_driver(&s3c24xx_uart_drv); uart_unregister_driver(&s3c24xx_uart_drv);
} }
......
...@@ -779,7 +779,6 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ ...@@ -779,7 +779,6 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
con_set_default_unimap(vc); con_set_default_unimap(vc);
vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
if (!vc->vc_screenbuf) { if (!vc->vc_screenbuf) {
tty_port_destroy(&vc->port);
kfree(vc); kfree(vc);
vc_cons[currcons].d = NULL; vc_cons[currcons].d = NULL;
return -ENOMEM; return -ENOMEM;
...@@ -986,26 +985,25 @@ static int vt_resize(struct tty_struct *tty, struct winsize *ws) ...@@ -986,26 +985,25 @@ static int vt_resize(struct tty_struct *tty, struct winsize *ws)
return ret; return ret;
} }
void vc_deallocate(unsigned int currcons) struct vc_data *vc_deallocate(unsigned int currcons)
{ {
struct vc_data *vc = NULL;
WARN_CONSOLE_UNLOCKED(); WARN_CONSOLE_UNLOCKED();
if (vc_cons_allocated(currcons)) { if (vc_cons_allocated(currcons)) {
struct vc_data *vc = vc_cons[currcons].d; struct vt_notifier_param param;
struct vt_notifier_param param = { .vc = vc };
param.vc = vc = vc_cons[currcons].d;
atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param); atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);
vcs_remove_sysfs(currcons); vcs_remove_sysfs(currcons);
vc->vc_sw->con_deinit(vc); vc->vc_sw->con_deinit(vc);
put_pid(vc->vt_pid); put_pid(vc->vt_pid);
module_put(vc->vc_sw->owner); module_put(vc->vc_sw->owner);
kfree(vc->vc_screenbuf); kfree(vc->vc_screenbuf);
if (currcons >= MIN_NR_CONSOLES) {
tty_port_destroy(&vc->port);
kfree(vc);
}
vc_cons[currcons].d = NULL; vc_cons[currcons].d = NULL;
} }
return vc;
} }
/* /*
......
...@@ -283,6 +283,51 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_ ...@@ -283,6 +283,51 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_
return 0; return 0;
} }
/* deallocate a single console, if possible (leave 0) */
static int vt_disallocate(unsigned int vc_num)
{
struct vc_data *vc = NULL;
int ret = 0;
if (!vc_num)
return 0;
console_lock();
if (VT_BUSY(vc_num))
ret = -EBUSY;
else
vc = vc_deallocate(vc_num);
console_unlock();
if (vc && vc_num >= MIN_NR_CONSOLES) {
tty_port_destroy(&vc->port);
kfree(vc);
}
return ret;
}
/* deallocate all unused consoles, but leave 0 */
static void vt_disallocate_all(void)
{
struct vc_data *vc[MAX_NR_CONSOLES];
int i;
console_lock();
for (i = 1; i < MAX_NR_CONSOLES; i++)
if (!VT_BUSY(i))
vc[i] = vc_deallocate(i);
else
vc[i] = NULL;
console_unlock();
for (i = 1; i < MAX_NR_CONSOLES; i++) {
if (vc[i] && i >= MIN_NR_CONSOLES) {
tty_port_destroy(&vc[i]->port);
kfree(vc[i]);
}
}
}
/* /*
...@@ -769,24 +814,10 @@ int vt_ioctl(struct tty_struct *tty, ...@@ -769,24 +814,10 @@ int vt_ioctl(struct tty_struct *tty,
ret = -ENXIO; ret = -ENXIO;
break; break;
} }
if (arg == 0) { if (arg == 0)
/* deallocate all unused consoles, but leave 0 */ vt_disallocate_all();
console_lock(); else
for (i=1; i<MAX_NR_CONSOLES; i++) ret = vt_disallocate(--arg);
if (! VT_BUSY(i))
vc_deallocate(i);
console_unlock();
} else {
/* deallocate a single console, if possible */
arg--;
if (VT_BUSY(arg))
ret = -EBUSY;
else if (arg) { /* leave 0 */
console_lock();
vc_deallocate(arg);
console_unlock();
}
}
break; break;
case VT_RESIZE: case VT_RESIZE:
......
...@@ -36,7 +36,7 @@ extern int fg_console, last_console, want_console; ...@@ -36,7 +36,7 @@ extern int fg_console, last_console, want_console;
int vc_allocate(unsigned int console); int vc_allocate(unsigned int console);
int vc_cons_allocated(unsigned int console); int vc_cons_allocated(unsigned int console);
int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines); int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines);
void vc_deallocate(unsigned int console); struct vc_data *vc_deallocate(unsigned int console);
void reset_palette(struct vc_data *vc); void reset_palette(struct vc_data *vc);
void do_blank_screen(int entering_gfx); void do_blank_screen(int entering_gfx);
void do_unblank_screen(int leaving_gfx); void do_unblank_screen(int leaving_gfx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment