提交 80c00750 编写于 作者: J Johan Hovold 提交者: Greg Kroah-Hartman

USB: mos7840: fix port-data memory leak

Fix port-data memory leak by moving port data allocation and
deallocation to port_probe and port_remove.

Since commit 0998d063 (device-core: Ensure drvdata = NULL when no
driver is bound) the port private data is no longer freed at release as
it is no longer accessible.

Note that the indentation was kept intact using a do-while(0) in order
to facilitate review. A follow-up patch will remove it.

Compile-only tested.
Signed-off-by: NJohan Hovold <jhovold@gmail.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
上级 e681b66f
...@@ -2327,49 +2327,45 @@ static int mos7840_calc_num_ports(struct usb_serial *serial) ...@@ -2327,49 +2327,45 @@ static int mos7840_calc_num_ports(struct usb_serial *serial)
return mos7840_num_ports; return mos7840_num_ports;
} }
/**************************************************************************** static int mos7840_port_probe(struct usb_serial_port *port)
* mos7840_startup
****************************************************************************/
static int mos7840_startup(struct usb_serial *serial)
{ {
struct usb_serial *serial = port->serial;
struct moschip_port *mos7840_port; struct moschip_port *mos7840_port;
struct usb_device *dev; int status;
int i, status; int pnum;
__u16 Data; __u16 Data;
dev = serial->dev;
/* we set up the pointers to the endpoints in the mos7840_open * /* we set up the pointers to the endpoints in the mos7840_open *
* function, as the structures aren't created yet. */ * function, as the structures aren't created yet. */
/* set up port private structures */ pnum = port->number - serial->minor;
for (i = 0; i < serial->num_ports; ++i) {
dev_dbg(&dev->dev, "mos7840_startup: configuring port %d............\n", i); /* FIXME: remove do-while(0) loop used to keep stable patch minimal.
*/
do {
dev_dbg(&port->dev, "mos7840_startup: configuring port %d............\n", pnum);
mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
if (mos7840_port == NULL) { if (mos7840_port == NULL) {
dev_err(&dev->dev, "%s - Out of memory\n", __func__); dev_err(&port->dev, "%s - Out of memory\n", __func__);
status = -ENOMEM; return -ENOMEM;
i--; /* don't follow NULL pointer cleaning up */
goto error;
} }
/* Initialize all port interrupt end point to port 0 int /* Initialize all port interrupt end point to port 0 int
* endpoint. Our device has only one interrupt end point * endpoint. Our device has only one interrupt end point
* common to all port */ * common to all port */
mos7840_port->port = serial->port[i]; mos7840_port->port = port;
mos7840_set_port_private(serial->port[i], mos7840_port); mos7840_set_port_private(port, mos7840_port);
spin_lock_init(&mos7840_port->pool_lock); spin_lock_init(&mos7840_port->pool_lock);
/* minor is not initialised until later by /* minor is not initialised until later by
* usb-serial.c:get_free_serial() and cannot therefore be used * usb-serial.c:get_free_serial() and cannot therefore be used
* to index device instances */ * to index device instances */
mos7840_port->port_num = i + 1; mos7840_port->port_num = pnum + 1;
dev_dbg(&dev->dev, "serial->port[i]->number = %d\n", serial->port[i]->number); dev_dbg(&port->dev, "port->number = %d\n", port->number);
dev_dbg(&dev->dev, "serial->port[i]->serial->minor = %d\n", serial->port[i]->serial->minor); dev_dbg(&port->dev, "port->serial->minor = %d\n", port->serial->minor);
dev_dbg(&dev->dev, "mos7840_port->port_num = %d\n", mos7840_port->port_num); dev_dbg(&port->dev, "mos7840_port->port_num = %d\n", mos7840_port->port_num);
dev_dbg(&dev->dev, "serial->minor = %d\n", serial->minor); dev_dbg(&port->dev, "serial->minor = %d\n", serial->minor);
if (mos7840_port->port_num == 1) { if (mos7840_port->port_num == 1) {
mos7840_port->SpRegOffset = 0x0; mos7840_port->SpRegOffset = 0x0;
...@@ -2396,115 +2392,115 @@ static int mos7840_startup(struct usb_serial *serial) ...@@ -2396,115 +2392,115 @@ static int mos7840_startup(struct usb_serial *serial)
mos7840_port->ControlRegOffset = 0xd; mos7840_port->ControlRegOffset = 0xd;
mos7840_port->DcrRegOffset = 0x1c; mos7840_port->DcrRegOffset = 0x1c;
} }
mos7840_dump_serial_port(serial->port[i], mos7840_port); mos7840_dump_serial_port(port, mos7840_port);
mos7840_set_port_private(serial->port[i], mos7840_port); mos7840_set_port_private(port, mos7840_port);
/* enable rx_disable bit in control register */ /* enable rx_disable bit in control register */
status = mos7840_get_reg_sync(serial->port[i], status = mos7840_get_reg_sync(port,
mos7840_port->ControlRegOffset, &Data); mos7840_port->ControlRegOffset, &Data);
if (status < 0) { if (status < 0) {
dev_dbg(&dev->dev, "Reading ControlReg failed status-0x%x\n", status); dev_dbg(&port->dev, "Reading ControlReg failed status-0x%x\n", status);
break; break;
} else } else
dev_dbg(&dev->dev, "ControlReg Reading success val is %x, status%d\n", Data, status); dev_dbg(&port->dev, "ControlReg Reading success val is %x, status%d\n", Data, status);
Data |= 0x08; /* setting driver done bit */ Data |= 0x08; /* setting driver done bit */
Data |= 0x04; /* sp1_bit to have cts change reflect in Data |= 0x04; /* sp1_bit to have cts change reflect in
modem status reg */ modem status reg */
/* Data |= 0x20; //rx_disable bit */ /* Data |= 0x20; //rx_disable bit */
status = mos7840_set_reg_sync(serial->port[i], status = mos7840_set_reg_sync(port,
mos7840_port->ControlRegOffset, Data); mos7840_port->ControlRegOffset, Data);
if (status < 0) { if (status < 0) {
dev_dbg(&dev->dev, "Writing ControlReg failed(rx_disable) status-0x%x\n", status); dev_dbg(&port->dev, "Writing ControlReg failed(rx_disable) status-0x%x\n", status);
break; break;
} else } else
dev_dbg(&dev->dev, "ControlReg Writing success(rx_disable) status%d\n", status); dev_dbg(&port->dev, "ControlReg Writing success(rx_disable) status%d\n", status);
/* Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2 /* Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2
and 0x24 in DCR3 */ and 0x24 in DCR3 */
Data = 0x01; Data = 0x01;
status = mos7840_set_reg_sync(serial->port[i], status = mos7840_set_reg_sync(port,
(__u16) (mos7840_port->DcrRegOffset + 0), Data); (__u16) (mos7840_port->DcrRegOffset + 0), Data);
if (status < 0) { if (status < 0) {
dev_dbg(&dev->dev, "Writing DCR0 failed status-0x%x\n", status); dev_dbg(&port->dev, "Writing DCR0 failed status-0x%x\n", status);
break; break;
} else } else
dev_dbg(&dev->dev, "DCR0 Writing success status%d\n", status); dev_dbg(&port->dev, "DCR0 Writing success status%d\n", status);
Data = 0x05; Data = 0x05;
status = mos7840_set_reg_sync(serial->port[i], status = mos7840_set_reg_sync(port,
(__u16) (mos7840_port->DcrRegOffset + 1), Data); (__u16) (mos7840_port->DcrRegOffset + 1), Data);
if (status < 0) { if (status < 0) {
dev_dbg(&dev->dev, "Writing DCR1 failed status-0x%x\n", status); dev_dbg(&port->dev, "Writing DCR1 failed status-0x%x\n", status);
break; break;
} else } else
dev_dbg(&dev->dev, "DCR1 Writing success status%d\n", status); dev_dbg(&port->dev, "DCR1 Writing success status%d\n", status);
Data = 0x24; Data = 0x24;
status = mos7840_set_reg_sync(serial->port[i], status = mos7840_set_reg_sync(port,
(__u16) (mos7840_port->DcrRegOffset + 2), Data); (__u16) (mos7840_port->DcrRegOffset + 2), Data);
if (status < 0) { if (status < 0) {
dev_dbg(&dev->dev, "Writing DCR2 failed status-0x%x\n", status); dev_dbg(&port->dev, "Writing DCR2 failed status-0x%x\n", status);
break; break;
} else } else
dev_dbg(&dev->dev, "DCR2 Writing success status%d\n", status); dev_dbg(&port->dev, "DCR2 Writing success status%d\n", status);
/* write values in clkstart0x0 and clkmulti 0x20 */ /* write values in clkstart0x0 and clkmulti 0x20 */
Data = 0x0; Data = 0x0;
status = mos7840_set_reg_sync(serial->port[i], status = mos7840_set_reg_sync(port,
CLK_START_VALUE_REGISTER, Data); CLK_START_VALUE_REGISTER, Data);
if (status < 0) { if (status < 0) {
dev_dbg(&dev->dev, "Writing CLK_START_VALUE_REGISTER failed status-0x%x\n", status); dev_dbg(&port->dev, "Writing CLK_START_VALUE_REGISTER failed status-0x%x\n", status);
break; break;
} else } else
dev_dbg(&dev->dev, "CLK_START_VALUE_REGISTER Writing success status%d\n", status); dev_dbg(&port->dev, "CLK_START_VALUE_REGISTER Writing success status%d\n", status);
Data = 0x20; Data = 0x20;
status = mos7840_set_reg_sync(serial->port[i], status = mos7840_set_reg_sync(port,
CLK_MULTI_REGISTER, Data); CLK_MULTI_REGISTER, Data);
if (status < 0) { if (status < 0) {
dev_dbg(&dev->dev, "Writing CLK_MULTI_REGISTER failed status-0x%x\n", status); dev_dbg(&port->dev, "Writing CLK_MULTI_REGISTER failed status-0x%x\n", status);
goto error; goto error;
} else } else
dev_dbg(&dev->dev, "CLK_MULTI_REGISTER Writing success status%d\n", status); dev_dbg(&port->dev, "CLK_MULTI_REGISTER Writing success status%d\n", status);
/* write value 0x0 to scratchpad register */ /* write value 0x0 to scratchpad register */
Data = 0x00; Data = 0x00;
status = mos7840_set_uart_reg(serial->port[i], status = mos7840_set_uart_reg(port,
SCRATCH_PAD_REGISTER, Data); SCRATCH_PAD_REGISTER, Data);
if (status < 0) { if (status < 0) {
dev_dbg(&dev->dev, "Writing SCRATCH_PAD_REGISTER failed status-0x%x\n", status); dev_dbg(&port->dev, "Writing SCRATCH_PAD_REGISTER failed status-0x%x\n", status);
break; break;
} else } else
dev_dbg(&dev->dev, "SCRATCH_PAD_REGISTER Writing success status%d\n", status); dev_dbg(&port->dev, "SCRATCH_PAD_REGISTER Writing success status%d\n", status);
/* Zero Length flag register */ /* Zero Length flag register */
if ((mos7840_port->port_num != 1) if ((mos7840_port->port_num != 1)
&& (serial->num_ports == 2)) { && (serial->num_ports == 2)) {
Data = 0xff; Data = 0xff;
status = mos7840_set_reg_sync(serial->port[i], status = mos7840_set_reg_sync(port,
(__u16) (ZLP_REG1 + (__u16) (ZLP_REG1 +
((__u16)mos7840_port->port_num)), Data); ((__u16)mos7840_port->port_num)), Data);
dev_dbg(&dev->dev, "ZLIP offset %x\n", dev_dbg(&port->dev, "ZLIP offset %x\n",
(__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num))); (__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num)));
if (status < 0) { if (status < 0) {
dev_dbg(&dev->dev, "Writing ZLP_REG%d failed status-0x%x\n", i + 2, status); dev_dbg(&port->dev, "Writing ZLP_REG%d failed status-0x%x\n", pnum + 2, status);
break; break;
} else } else
dev_dbg(&dev->dev, "ZLP_REG%d Writing success status%d\n", i + 2, status); dev_dbg(&port->dev, "ZLP_REG%d Writing success status%d\n", pnum + 2, status);
} else { } else {
Data = 0xff; Data = 0xff;
status = mos7840_set_reg_sync(serial->port[i], status = mos7840_set_reg_sync(port,
(__u16) (ZLP_REG1 + (__u16) (ZLP_REG1 +
((__u16)mos7840_port->port_num) - 0x1), Data); ((__u16)mos7840_port->port_num) - 0x1), Data);
dev_dbg(&dev->dev, "ZLIP offset %x\n", dev_dbg(&port->dev, "ZLIP offset %x\n",
(__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num) - 0x1)); (__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num) - 0x1));
if (status < 0) { if (status < 0) {
dev_dbg(&dev->dev, "Writing ZLP_REG%d failed status-0x%x\n", i + 1, status); dev_dbg(&port->dev, "Writing ZLP_REG%d failed status-0x%x\n", pnum + 1, status);
break; break;
} else } else
dev_dbg(&dev->dev, "ZLP_REG%d Writing success status%d\n", i + 1, status); dev_dbg(&port->dev, "ZLP_REG%d Writing success status%d\n", pnum + 1, status);
} }
mos7840_port->control_urb = usb_alloc_urb(0, GFP_KERNEL); mos7840_port->control_urb = usb_alloc_urb(0, GFP_KERNEL);
...@@ -2541,92 +2537,56 @@ static int mos7840_startup(struct usb_serial *serial) ...@@ -2541,92 +2537,56 @@ static int mos7840_startup(struct usb_serial *serial)
mos7840_port->led_flag = false; mos7840_port->led_flag = false;
/* Turn off LED */ /* Turn off LED */
mos7840_set_led_sync(serial->port[i], mos7840_set_led_sync(port,
MODEM_CONTROL_REGISTER, 0x0300); MODEM_CONTROL_REGISTER, 0x0300);
} }
} } while (0);
/* Zero Length flag enable */ if (pnum == serial->num_ports - 1) {
Data = 0x0f; /* Zero Length flag enable */
status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data); Data = 0x0f;
if (status < 0) { status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data);
dev_dbg(&dev->dev, "Writing ZLP_REG5 failed status-0x%x\n", status); if (status < 0) {
goto error; dev_dbg(&port->dev, "Writing ZLP_REG5 failed status-0x%x\n", status);
} else goto error;
dev_dbg(&dev->dev, "ZLP_REG5 Writing success status%d\n", status); } else
dev_dbg(&port->dev, "ZLP_REG5 Writing success status%d\n", status);
/* setting configuration feature to one */
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), /* setting configuration feature to one */
(__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, MOS_WDR_TIMEOUT); usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
0x03, 0x00, 0x01, 0x00, NULL, 0x00,
MOS_WDR_TIMEOUT);
}
return 0; return 0;
error: error:
for (/* nothing */; i >= 0; i--) { kfree(mos7840_port->dr);
mos7840_port = mos7840_get_port_private(serial->port[i]); kfree(mos7840_port->ctrl_buf);
usb_free_urb(mos7840_port->control_urb);
kfree(mos7840_port);
kfree(mos7840_port->dr);
kfree(mos7840_port->ctrl_buf);
usb_free_urb(mos7840_port->control_urb);
kfree(mos7840_port);
}
return status; return status;
} }
/**************************************************************************** static int mos7840_port_remove(struct usb_serial_port *port)
* mos7840_disconnect
* This function is called whenever the device is removed from the usb bus.
****************************************************************************/
static void mos7840_disconnect(struct usb_serial *serial)
{ {
int i;
unsigned long flags;
struct moschip_port *mos7840_port; struct moschip_port *mos7840_port;
/* check for the ports to be closed,close the ports and disconnect */ mos7840_port = mos7840_get_port_private(port);
/* free private structure allocated for serial port * if (mos7840_port->has_led) {
* stop reads and writes on all ports */ /* Turn off LED */
mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300);
for (i = 0; i < serial->num_ports; ++i) { del_timer_sync(&mos7840_port->led_timer1);
mos7840_port = mos7840_get_port_private(serial->port[i]); del_timer_sync(&mos7840_port->led_timer2);
if (mos7840_port) {
usb_kill_urb(mos7840_port->control_urb);
}
} }
} usb_kill_urb(mos7840_port->control_urb);
usb_free_urb(mos7840_port->control_urb);
/**************************************************************************** kfree(mos7840_port->ctrl_buf);
* mos7840_release kfree(mos7840_port->dr);
* This function is called when the usb_serial structure is freed. kfree(mos7840_port);
****************************************************************************/
static void mos7840_release(struct usb_serial *serial)
{
int i;
struct moschip_port *mos7840_port;
/* check for the ports to be closed,close the ports and disconnect */ return 0;
/* free private structure allocated for serial port *
* stop reads and writes on all ports */
for (i = 0; i < serial->num_ports; ++i) {
mos7840_port = mos7840_get_port_private(serial->port[i]);
if (mos7840_port) {
if (mos7840_port->has_led) {
/* Turn off LED */
mos7840_set_led_sync(mos7840_port->port,
MODEM_CONTROL_REGISTER, 0x0300);
del_timer_sync(&mos7840_port->led_timer1);
del_timer_sync(&mos7840_port->led_timer2);
}
usb_free_urb(mos7840_port->control_urb);
kfree(mos7840_port->ctrl_buf);
kfree(mos7840_port->dr);
kfree(mos7840_port);
}
}
} }
static struct usb_serial_driver moschip7840_4port_device = { static struct usb_serial_driver moschip7840_4port_device = {
...@@ -2654,9 +2614,8 @@ static struct usb_serial_driver moschip7840_4port_device = { ...@@ -2654,9 +2614,8 @@ static struct usb_serial_driver moschip7840_4port_device = {
.tiocmget = mos7840_tiocmget, .tiocmget = mos7840_tiocmget,
.tiocmset = mos7840_tiocmset, .tiocmset = mos7840_tiocmset,
.get_icount = mos7840_get_icount, .get_icount = mos7840_get_icount,
.attach = mos7840_startup, .port_probe = mos7840_port_probe,
.disconnect = mos7840_disconnect, .port_remove = mos7840_port_remove,
.release = mos7840_release,
.read_bulk_callback = mos7840_bulk_in_callback, .read_bulk_callback = mos7840_bulk_in_callback,
.read_int_callback = mos7840_interrupt_callback, .read_int_callback = mos7840_interrupt_callback,
}; };
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册