diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/serial/option.c | 1 | ||||
-rw-r--r-- | drivers/usb/serial/usb-wwan.h | 2 | ||||
-rw-r--r-- | drivers/usb/serial/usb_wwan.c | 78 |
3 files changed, 81 insertions, 0 deletions
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 2297fb1bcf65..2a56cc35ad31 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c | |||
@@ -989,6 +989,7 @@ static struct usb_serial_driver option_1port_device = { | |||
989 | .set_termios = usb_wwan_set_termios, | 989 | .set_termios = usb_wwan_set_termios, |
990 | .tiocmget = usb_wwan_tiocmget, | 990 | .tiocmget = usb_wwan_tiocmget, |
991 | .tiocmset = usb_wwan_tiocmset, | 991 | .tiocmset = usb_wwan_tiocmset, |
992 | .ioctl = usb_wwan_ioctl, | ||
992 | .attach = usb_wwan_startup, | 993 | .attach = usb_wwan_startup, |
993 | .disconnect = usb_wwan_disconnect, | 994 | .disconnect = usb_wwan_disconnect, |
994 | .release = usb_wwan_release, | 995 | .release = usb_wwan_release, |
diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h index 2be298a1305b..3ab77c5d9819 100644 --- a/drivers/usb/serial/usb-wwan.h +++ b/drivers/usb/serial/usb-wwan.h | |||
@@ -18,6 +18,8 @@ extern void usb_wwan_set_termios(struct tty_struct *tty, | |||
18 | extern int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file); | 18 | extern int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file); |
19 | extern int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file, | 19 | extern int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file, |
20 | unsigned int set, unsigned int clear); | 20 | unsigned int set, unsigned int clear); |
21 | extern int usb_wwan_ioctl(struct tty_struct *tty, struct file *file, | ||
22 | unsigned int cmd, unsigned long arg); | ||
21 | extern int usb_wwan_send_setup(struct usb_serial_port *port); | 23 | extern int usb_wwan_send_setup(struct usb_serial_port *port); |
22 | extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, | 24 | extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, |
23 | const unsigned char *buf, int count); | 25 | const unsigned char *buf, int count); |
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index fbc946797801..660b7caef784 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/bitops.h> | 33 | #include <linux/bitops.h> |
34 | #include <linux/usb.h> | 34 | #include <linux/usb.h> |
35 | #include <linux/usb/serial.h> | 35 | #include <linux/usb/serial.h> |
36 | #include <linux/serial.h> | ||
36 | #include "usb-wwan.h" | 37 | #include "usb-wwan.h" |
37 | 38 | ||
38 | static int debug; | 39 | static int debug; |
@@ -123,6 +124,83 @@ int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file, | |||
123 | } | 124 | } |
124 | EXPORT_SYMBOL(usb_wwan_tiocmset); | 125 | EXPORT_SYMBOL(usb_wwan_tiocmset); |
125 | 126 | ||
127 | static int get_serial_info(struct usb_serial_port *port, | ||
128 | struct serial_struct __user *retinfo) | ||
129 | { | ||
130 | struct serial_struct tmp; | ||
131 | |||
132 | if (!retinfo) | ||
133 | return -EFAULT; | ||
134 | |||
135 | memset(&tmp, 0, sizeof(tmp)); | ||
136 | tmp.line = port->serial->minor; | ||
137 | tmp.port = port->number; | ||
138 | tmp.baud_base = tty_get_baud_rate(port->port.tty); | ||
139 | tmp.close_delay = port->port.close_delay / 10; | ||
140 | tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? | ||
141 | ASYNC_CLOSING_WAIT_NONE : | ||
142 | port->port.closing_wait / 10; | ||
143 | |||
144 | if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) | ||
145 | return -EFAULT; | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int set_serial_info(struct usb_serial_port *port, | ||
150 | struct serial_struct __user *newinfo) | ||
151 | { | ||
152 | struct serial_struct new_serial; | ||
153 | unsigned int closing_wait, close_delay; | ||
154 | int retval = 0; | ||
155 | |||
156 | if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) | ||
157 | return -EFAULT; | ||
158 | |||
159 | close_delay = new_serial.close_delay * 10; | ||
160 | closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? | ||
161 | ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; | ||
162 | |||
163 | mutex_lock(&port->port.mutex); | ||
164 | |||
165 | if (!capable(CAP_SYS_ADMIN)) { | ||
166 | if ((close_delay != port->port.close_delay) || | ||
167 | (closing_wait != port->port.closing_wait)) | ||
168 | retval = -EPERM; | ||
169 | else | ||
170 | retval = -EOPNOTSUPP; | ||
171 | } else { | ||
172 | port->port.close_delay = close_delay; | ||
173 | port->port.closing_wait = closing_wait; | ||
174 | } | ||
175 | |||
176 | mutex_unlock(&port->port.mutex); | ||
177 | return retval; | ||
178 | } | ||
179 | |||
180 | int usb_wwan_ioctl(struct tty_struct *tty, struct file *file, | ||
181 | unsigned int cmd, unsigned long arg) | ||
182 | { | ||
183 | struct usb_serial_port *port = tty->driver_data; | ||
184 | |||
185 | dbg("%s cmd 0x%04x", __func__, cmd); | ||
186 | |||
187 | switch (cmd) { | ||
188 | case TIOCGSERIAL: | ||
189 | return get_serial_info(port, | ||
190 | (struct serial_struct __user *) arg); | ||
191 | case TIOCSSERIAL: | ||
192 | return set_serial_info(port, | ||
193 | (struct serial_struct __user *) arg); | ||
194 | default: | ||
195 | break; | ||
196 | } | ||
197 | |||
198 | dbg("%s arg not supported", __func__); | ||
199 | |||
200 | return -ENOIOCTLCMD; | ||
201 | } | ||
202 | EXPORT_SYMBOL(usb_wwan_ioctl); | ||
203 | |||
126 | /* Write */ | 204 | /* Write */ |
127 | int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, | 205 | int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, |
128 | const unsigned char *buf, int count) | 206 | const unsigned char *buf, int count) |