1
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3
* Copyright (C) 2009 David Zeuthen <david@fubar.dk>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
#include <scsi/sg_lib.h>
28
#include <scsi/sg_cmds.h>
30
#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
38
g_printerr ("incorrect usage\n");
42
main (int argc, char *argv[])
47
const gchar *sysfs_path;
49
struct udev_device *udevice;
50
struct udev_device *udevice_usb_interface;
51
struct udev_device *udevice_usb_device;
53
gchar *power_level_path;
54
gchar *usb_interface_name;
55
size_t usb_interface_name_len;
60
udevice_usb_interface = NULL;
61
udevice_usb_device = NULL;
62
usb_interface_name = NULL;
64
power_level_path = NULL;
78
sg_fd = sg_cmds_open_device (device, 1 /* read_only */, 1);
81
g_printerr ("Cannot open %s: %m\n", device);
85
if (sg_ll_sync_cache_10 (sg_fd,
95
g_printerr ("Error SYNCHRONIZE CACHE for %s: %m\n", device);
96
/* this is not a catastrophe, carry on */
99
if (sg_ll_start_stop_unit (sg_fd,
101
0, /* pc_mod__fl_num */
110
g_printerr ("Error STOP UNIT for %s: %m\n", device);
114
/* OK, close the device */
115
sg_cmds_close_device (sg_fd);
118
/* Now unbind the usb-storage driver from the usb interface */
122
g_printerr ("Error initializing libudev: %m\n");
126
udevice = udev_device_new_from_syspath (udev, sysfs_path);
129
g_printerr ("No udev device for %s: %m\n", sysfs_path);
133
/* unbind the mass storage driver (e.g. usb-storage) */
134
udevice_usb_interface = udev_device_get_parent_with_subsystem_devtype (udevice, "usb", "usb_interface");
135
if (udevice_usb_interface == NULL)
137
g_printerr ("No usb parent interface for %s: %m\n", sysfs_path);
141
usb_interface_name = g_path_get_basename (udev_device_get_devpath (udevice_usb_interface));
142
usb_interface_name_len = strlen (usb_interface_name);
144
unbind_path = g_strdup_printf ("%s/driver/unbind", udev_device_get_syspath (udevice_usb_interface));
145
f = fopen (unbind_path, "w");
148
g_printerr ("Cannot open %s for writing: %m\n", unbind_path);
151
if (fwrite (usb_interface_name, sizeof (char), usb_interface_name_len, f) < usb_interface_name_len)
153
g_printerr ("Error writing %s to %s: %m\n", unbind_path, usb_interface_name);
159
/* If this is the only USB interface on the device, also suspend the
160
* USB device to e.g. make the lights on the device power off.
162
* Failing to do so is not an error, the user may not have
163
* CONFIG_USB_SUSPEND enabled in their kernel.
167
udevice_usb_device = udev_device_get_parent_with_subsystem_devtype (udevice, "usb", "usb_device");
168
if (udevice_usb_device != NULL)
170
const char *bNumInterfaces;
173
gchar *power_level_path;
174
gchar suspend_str[] = "suspend";
176
bNumInterfaces = udev_device_get_sysattr_value (udevice_usb_device, "bNumInterfaces");
177
num_interfaces = strtol (bNumInterfaces, &endp, 0);
178
if (endp != NULL && num_interfaces == 1)
180
power_level_path = g_strdup_printf ("%s/power/level", udev_device_get_syspath (udevice_usb_device));
181
f = fopen (power_level_path, "w");
184
g_printerr ("Cannot open %s for writing: %m\n", unbind_path);
188
if (fwrite (suspend_str, sizeof (char), strlen (suspend_str), f) < strlen (suspend_str))
190
g_printerr ("Error writing %s to %s: %m\n", power_level_path, suspend_str);
198
g_free (usb_interface_name);
199
g_free (unbind_path);
200
g_free (power_level_path);
202
sg_cmds_close_device (sg_fd);
204
udev_device_unref (udevice);