mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-11 13:27:06 +09:00
mdm6600: First pass at suspend/resume support.
Add suspend/resume handler. Usb framework will no longer de-register tty on suspend/resume now. Kill URB's with usbcore while in suspend. Switch from dev_foo() to pr_foo() printk helpers. The dev_ ones are a pain to find the right device struct, and occasionally caused null pointer panics. Change-Id: I38769dc3befaef1a783ec5ab77169db2e963a9bc Signed-off-by: Nick Pelly <npelly@google.com>
This commit is contained in:
@@ -116,13 +116,11 @@ static int mdm6600_attach(struct usb_serial *serial)
|
||||
epread = ep;
|
||||
}
|
||||
if (!epwrite) {
|
||||
dev_err(&serial->dev->dev, "%s No bulk out endpoint\n",
|
||||
__func__);
|
||||
pr_err("%s No bulk out endpoint\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
if (!epread) {
|
||||
dev_err(&serial->dev->dev, "%s No bulk in endpoint\n",
|
||||
__func__);
|
||||
pr_err("%s No bulk in endpoint\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -175,10 +173,8 @@ static int mdm6600_attach(struct usb_serial *serial)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mdm6600_disconnect(struct usb_serial *serial)
|
||||
static void mdm6600_kill_urbs(struct mdm6600_port *modem)
|
||||
{
|
||||
struct mdm6600_port *modem = usb_get_serial_data(serial);
|
||||
|
||||
dbg("%s: port %d", __func__, modem->port->number);
|
||||
|
||||
/* cancel pending writes */
|
||||
@@ -188,6 +184,16 @@ static void mdm6600_disconnect(struct usb_serial *serial)
|
||||
usb_kill_anchored_urbs(&modem->read.in_flight);
|
||||
usb_kill_urb(modem->port->interrupt_in_urb);
|
||||
|
||||
}
|
||||
|
||||
static void mdm6600_disconnect(struct usb_serial *serial)
|
||||
{
|
||||
struct mdm6600_port *modem = usb_get_serial_data(serial);
|
||||
|
||||
dbg("%s: port %d", __func__, modem->port->number);
|
||||
|
||||
mdm6600_kill_urbs(modem);
|
||||
|
||||
/* cancel read bottom half */
|
||||
cancel_work_sync(&modem->read.work);
|
||||
|
||||
@@ -218,11 +224,38 @@ static void mdm6600_release(struct usb_serial *serial)
|
||||
}
|
||||
}
|
||||
|
||||
static int mdm6600_submit_urbs(struct mdm6600_port *modem)
|
||||
{
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
dbg("%s: port %d", __func__, modem->port->number);
|
||||
|
||||
if (modem->port->number == MODEM_INTERFACE_NUM) {
|
||||
WARN_ON_ONCE(!modem->port->interrupt_in_urb);
|
||||
rc = usb_submit_urb(modem->port->interrupt_in_urb, GFP_KERNEL);
|
||||
if (rc) {
|
||||
pr_err("%s: failed to submit interrupt urb, error %d\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < POOL_SZ; i++) {
|
||||
rc = usb_submit_urb(modem->read.urb[i], GFP_KERNEL);
|
||||
if (rc) {
|
||||
pr_err("%s: failed to submit bulk read urb, error %d\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
usb_anchor_urb(modem->read.urb[i], &modem->read.in_flight);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called when tty is opened */
|
||||
static int mdm6600_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||||
{
|
||||
int i;
|
||||
int rc = 0;
|
||||
struct mdm6600_port *modem = usb_get_serial_data(port->serial);
|
||||
|
||||
dbg("%s: port %d", __func__, port->number);
|
||||
@@ -231,27 +264,7 @@ static int mdm6600_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||||
|
||||
modem->tiocm_status = 0;
|
||||
|
||||
if (port->number == MODEM_INTERFACE_NUM) {
|
||||
WARN_ON_ONCE(!port->interrupt_in_urb);
|
||||
rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
|
||||
if (rc) {
|
||||
dev_err(&port->dev,
|
||||
"%s: failed to submit interrupt urb, error %d\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < POOL_SZ; i++) {
|
||||
rc = usb_submit_urb(modem->read.urb[i], GFP_KERNEL);
|
||||
if (rc) {
|
||||
dev_err(&port->dev,
|
||||
"%s: failed to submit bulk read urb, error %d\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
return mdm6600_submit_urbs(modem);
|
||||
}
|
||||
|
||||
static void mdm6600_close(struct usb_serial_port *port)
|
||||
@@ -260,12 +273,7 @@ static void mdm6600_close(struct usb_serial_port *port)
|
||||
|
||||
dbg("%s: port %d", __func__, port->number);
|
||||
|
||||
/* cancel pending writes */
|
||||
usb_kill_anchored_urbs(&modem->write.in_flight);
|
||||
|
||||
/* stop reading from mdm6600 */
|
||||
usb_kill_anchored_urbs(&modem->read.in_flight);
|
||||
usb_kill_urb(port->interrupt_in_urb);
|
||||
mdm6600_kill_urbs(modem);
|
||||
|
||||
/* cancel read bottom half */
|
||||
cancel_work_sync(&modem->read.work);
|
||||
@@ -331,12 +339,10 @@ static void mdm6600_write_bulk_cb(struct urb *u)
|
||||
|
||||
status = u->status;
|
||||
if (status)
|
||||
dev_warn(&modem->serial->dev->dev, "%s non-zero status %d\n",
|
||||
__func__, u->status);
|
||||
pr_warn("%s non-zero status %d\n", __func__, u->status);
|
||||
|
||||
if (mdm6600_mark_write_urb_unused(&modem->write, u))
|
||||
dev_warn(&modem->serial->dev->dev, "%s unknown urb %p\n",
|
||||
__func__, u);
|
||||
pr_warn("%s unknown urb %p\n", __func__, u);
|
||||
|
||||
if (!status)
|
||||
usb_serial_port_softint(modem->port);
|
||||
@@ -358,7 +364,7 @@ static int mdm6600_write(struct tty_struct *tty, struct usb_serial_port *port,
|
||||
|
||||
u = mdm6600_get_unused_write_urb(&modem->write);
|
||||
if (!u) {
|
||||
dev_info(&port->dev, "%s: all buffers busy!\n", __func__);
|
||||
pr_info("%s: all buffers busy!\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -370,8 +376,7 @@ static int mdm6600_write(struct tty_struct *tty, struct usb_serial_port *port,
|
||||
|
||||
rc = usb_submit_urb(u, GFP_ATOMIC);
|
||||
if (rc < 0) {
|
||||
dev_err(&port->dev, "%s: submit bulk urb failed %d\n",
|
||||
__func__, rc);
|
||||
pr_err("%s: submit bulk urb failed %d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -400,9 +405,8 @@ static int mdm6600_dtr_control(struct usb_serial_port *port, int ctrl)
|
||||
|
||||
rc = usb_autopm_get_interface(iface);
|
||||
if (rc < 0) {
|
||||
dev_err(&dev->dev, "%s %s autopm failed %d",
|
||||
dev_driver_string(&iface->dev), dev_name(&iface->dev),
|
||||
rc);
|
||||
pr_err("%s %s autopm failed %d", dev_driver_string(&iface->dev),
|
||||
dev_name(&iface->dev), rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -464,9 +468,9 @@ static void mdm6600_read_int_callback(struct urb *u)
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
dbg("%s: urb terminated, status %d", __func__, u->status);
|
||||
goto exit;
|
||||
return;
|
||||
default:
|
||||
dbg("%s: urb status non-zero %d", __func__, u->status);
|
||||
pr_warn("%s non-zero status %d\n", __func__, u->status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -483,8 +487,7 @@ static void mdm6600_read_int_callback(struct urb *u)
|
||||
switch (request) {
|
||||
case BP_MODEM_STATUS:
|
||||
if (u->actual_length < 9) {
|
||||
dev_err(&port->dev,
|
||||
"%s: modem status urb too small %d\n",
|
||||
pr_err("%s: modem status urb too small %d\n",
|
||||
__func__, u->actual_length);
|
||||
break;
|
||||
}
|
||||
@@ -507,8 +510,7 @@ static void mdm6600_read_int_callback(struct urb *u)
|
||||
exit:
|
||||
rc = usb_submit_urb(u, GFP_ATOMIC);
|
||||
if (rc)
|
||||
dev_err(&u->dev->dev,
|
||||
"%s: Error %d re-submitting interrupt urb\n",
|
||||
pr_err("%s: Error %d re-submitting interrupt urb\n",
|
||||
__func__, rc);
|
||||
}
|
||||
|
||||
@@ -555,15 +557,13 @@ static void mdm6600_read_bulk_work(struct work_struct *work)
|
||||
u->actual_length, u->transfer_buffer);
|
||||
tty = tty_port_tty_get(&modem->port->port);
|
||||
if (!tty) {
|
||||
dev_warn(&modem->port->dev, "%s: could not find tty\n",
|
||||
__func__);
|
||||
pr_warn("%s: could not find tty\n", __func__);
|
||||
goto next;
|
||||
}
|
||||
c = mdm6600_pass_to_tty(tty, u->transfer_buffer,
|
||||
u->actual_length);
|
||||
if (c != u->actual_length)
|
||||
dev_warn(&modem->port->dev,
|
||||
"%s: dropped %u of %u bytes\n",
|
||||
pr_warn("%s: dropped %u of %u bytes\n",
|
||||
__func__, u->actual_length - c,
|
||||
u->actual_length);
|
||||
tty_kref_put(tty);
|
||||
@@ -571,41 +571,74 @@ static void mdm6600_read_bulk_work(struct work_struct *work)
|
||||
next:
|
||||
rc = usb_submit_urb(u, GFP_KERNEL);
|
||||
if (rc)
|
||||
dev_err(&u->dev->dev,
|
||||
"%s: Error %d re-submitting read urb\n",
|
||||
pr_err("%s: Error %d re-submitting read urb\n",
|
||||
__func__, rc);
|
||||
else
|
||||
usb_anchor_urb(u, &modem->read.in_flight);
|
||||
}
|
||||
}
|
||||
|
||||
static void mdm6600_read_bulk_cb(struct urb *u)
|
||||
{
|
||||
int rc;
|
||||
struct mdm6600_port *modem = u->context;
|
||||
|
||||
dbg("%s: urb %p", __func__, u);
|
||||
|
||||
if (u->status) {
|
||||
int rc;
|
||||
dev_warn(&modem->serial->dev->dev, "%s non-zero status %d\n",
|
||||
__func__, u->status);
|
||||
switch (u->status) {
|
||||
case 0:
|
||||
break; /* success */
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
dbg("%s: urb terminated, status %d", __func__, u->status);
|
||||
return;
|
||||
default:
|
||||
pr_warn("%s non-zero status %d\n", __func__, u->status);
|
||||
/* straight back into use */
|
||||
rc = usb_submit_urb(u, GFP_ATOMIC);
|
||||
if (rc)
|
||||
dev_err(&u->dev->dev,
|
||||
"%s: Error %d re-submitting read urb\n",
|
||||
pr_err("%s: Error %d re-submitting read urb\n",
|
||||
__func__, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* process urb in bottom half */
|
||||
usb_anchor_urb(u, &modem->read.pending);
|
||||
schedule_work(&modem->read.work);
|
||||
}
|
||||
|
||||
static int mdm6600_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
{
|
||||
struct usb_serial *serial = usb_get_intfdata(intf);
|
||||
struct mdm6600_port *modem = usb_get_serial_data(serial);
|
||||
|
||||
dbg("%s: event=%d", __func__, message.event);
|
||||
|
||||
mdm6600_kill_urbs(modem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdm6600_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct usb_serial *serial = usb_get_intfdata(intf);
|
||||
struct mdm6600_port *modem = usb_get_serial_data(serial);
|
||||
|
||||
dbg("%s", __func__);
|
||||
|
||||
return mdm6600_submit_urbs(modem);
|
||||
}
|
||||
|
||||
static struct usb_driver mdm6600_usb_driver = {
|
||||
.name = "mdm6600",
|
||||
.probe = usb_serial_probe,
|
||||
.disconnect = usb_serial_disconnect,
|
||||
.id_table = mdm6600_id_table,
|
||||
.no_dynamic_id = 1,
|
||||
.supports_autosuspend = 1,
|
||||
.suspend = mdm6600_suspend,
|
||||
.resume = mdm6600_resume,
|
||||
};
|
||||
|
||||
static struct usb_serial_driver mdm6600_usb_serial_driver = {
|
||||
|
||||
Reference in New Issue
Block a user