コード例 #1
0
ファイル: usb.c プロジェクト: 325116067/semc-qsd8x50
/*
 * Get the device ready for USB port or system standby and hibernation
 *
 * USB port and system standby are handled the same.
 *
 * When the system hibernates, the USB device is powered down and then
 * up, so we don't really have to do much here, as it will be seen as
 * a reconnect. Still for simplicity we consider this case the same as
 * suspend, so that the device has a chance to do notify the base
 * station (if connected).
 *
 * So at the end, the three cases require common handling.
 *
 * If at the time of this call the device's firmware is not loaded,
 * nothing has to be done.
 *
 * If the firmware is loaded, we need to:
 *
 *  - tell the device to go into host interface power save mode, wait
 *    for it to ack
 *
 *    This is quite more interesting than it is; we need to execute a
 *    command, but this time, we don't want the code in usb-{tx,rx}.c
 *    to call the usb_autopm_get/put_interface() barriers as it'd
 *    deadlock, so we need to decrement i2400mu->do_autopm, that acts
 *    as a poor man's semaphore. Ugly, but it works.
 *
 *    As well, the device might refuse going to sleep for whichever
 *    reason. In this case we just fail. For system suspend/hibernate,
 *    we *can't* fail. We look at usb_dev->auto_pm to see if the
 *    suspend call comes from the USB stack or from the system and act
 *    in consequence.
 *
 *  - stop the notification endpoint polling
 */
static
int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg)
{
	int result = 0;
	struct device *dev = &iface->dev;
	struct i2400mu *i2400mu = usb_get_intfdata(iface);
#ifdef CONFIG_PM
	struct usb_device *usb_dev = i2400mu->usb_dev;
#endif
	unsigned is_autosuspend = 0;
	struct i2400m *i2400m = &i2400mu->i2400m;

#ifdef CONFIG_PM
	if (usb_dev->auto_pm > 0)
		is_autosuspend = 1;
#endif

	d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event);
	if (i2400m->updown == 0)
		goto no_firmware;
	if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) {
		/* ugh -- the device is connected and this suspend
		 * request is an autosuspend one (not a system standby
		 * / hibernate).
		 *
		 * The only way the device can go to standby is if the
		 * link with the base station is in IDLE mode; that
		 * were the case, we'd be in status
		 * I2400M_SS_CONNECTED_IDLE. But we are not.
		 *
		 * If we *tell* him to go power save now, it'll reset
		 * as a precautionary measure, so if this is an
		 * autosuspend thing, say no and it'll come back
		 * later, when the link is IDLE
		 */
		result = -EBADF;
		d_printf(1, dev, "fw up, link up, not-idle, autosuspend: "
			 "not entering powersave\n");
		goto error_not_now;
	}
	d_printf(1, dev, "fw up: entering powersave\n");
	atomic_dec(&i2400mu->do_autopm);
	result = i2400m_cmd_enter_powersave(i2400m);
	atomic_inc(&i2400mu->do_autopm);
	if (result < 0 && !is_autosuspend) {
		/* System suspend, can't fail */
		dev_err(dev, "failed to suspend, will reset on resume\n");
		result = 0;
	}
	if (result < 0)
		goto error_enter_powersave;
	i2400mu_notification_release(i2400mu);
	d_printf(1, dev, "powersave requested\n");
error_enter_powersave:
error_not_now:
no_firmware:
	d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n",
		iface, pm_msg.event, result);
	return result;
}
コード例 #2
0
ファイル: usb.c プロジェクト: romanbb/android_kernel_lge_d851
static
int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg)
{
	int result = 0;
	struct device *dev = &iface->dev;
	struct i2400mu *i2400mu = usb_get_intfdata(iface);
	unsigned is_autosuspend = 0;
	struct i2400m *i2400m = &i2400mu->i2400m;

#ifdef CONFIG_PM
	if (PMSG_IS_AUTO(pm_msg))
		is_autosuspend = 1;
#endif

	d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event);
	rmb();		/*                                     */
	if (i2400m->updown == 0)
		goto no_firmware;
	if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) {
		/*                                                
                                                        
                  
    
                                                        
                                                     
                                     
                                              
    
                                                       
                                                 
                                                  
                                 
   */
		result = -EBADF;
		d_printf(1, dev, "fw up, link up, not-idle, autosuspend: "
			 "not entering powersave\n");
		goto error_not_now;
	}
	d_printf(1, dev, "fw up: entering powersave\n");
	atomic_dec(&i2400mu->do_autopm);
	result = i2400m_cmd_enter_powersave(i2400m);
	atomic_inc(&i2400mu->do_autopm);
	if (result < 0 && !is_autosuspend) {
		/*                            */
		dev_err(dev, "failed to suspend, will reset on resume\n");
		result = 0;
	}
	if (result < 0)
		goto error_enter_powersave;
	i2400mu_notification_release(i2400mu);
	d_printf(1, dev, "powersave requested\n");
error_enter_powersave:
error_not_now:
no_firmware:
	d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n",
		iface, pm_msg.event, result);
	return result;
}
コード例 #3
0
static
void i2400mu_bus_dev_stop(struct i2400m *i2400m)
{
	struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
	struct device *dev = &i2400mu->usb_iface->dev;

	d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
	i2400mu_notification_release(i2400mu);
	i2400mu_rx_release(i2400mu);
	i2400mu_tx_release(i2400mu);
	d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
}