USB-serial updates for v4.13-rc1
Here are the USB-serial updates for 4.13, including support for manipulating the modem-control signals of qcserial devices, propagation of errnos after late probe errors from usb-serial core, and a couple of clean ups. All have been in linux-next with no reported issues. Signed-off-by: Johan Hovold <johan@kernel.org> -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEHszNKQClByu0A+9RQQ3kT97htJUFAllTZSARHGpvaGFuQGtl cm5lbC5vcmcACgkQQQ3kT97htJWM+A//U7WSk6Y0iFdT9lw6EWg55BsybGv3HZ1O 2UA3y2P1TEWlsD+hBZs/4TRnay6udxc/zgIs2dDL7jPLw3ZNZCp8hIqtMjiLZA8i Ca4KgQlDkPEHps7rn1fbiZAsgFI25Y0+Bs3fzz+JDW+jV9jkWGQ1jpBoFOHgIc6v LbiWZOyLFWoF59BzFeys0PW1ar4Yl5BRKIlztkJOu7NVKwvp7SEQeyIyhplKWDP1 egvptlGRIy1vDJMFMz5PYCyt4jFFgdDKp1ffXHEKAbcBRgiZbvjGrVRE3RePskN9 Ui/SI0a6+DAfbJxSXovpdoOVvQqYKzm6QuneROXDpKYoPSLe7/31XJxM7U8gO0+J dju6EANUncVrzCeThyTfaa38FT8/eInUuygQzr0mwrouDxQRMPWsePX+o2T4k04U 5PZ2IBx/PpAss4GNPL5gx9PJSxd8fnQVmRCAgsxFAZn4N8o1NXh7rpHby0D0X2GZ 5iaKhuYCT0pxxv6ueey4HnLlxEcmhQBdur0AIEK6iaUG24mIHiSu5V5JxDNHIyYX LECv8HpLVi1htaO8khlSNOZ5zTsaa21c7GRXKLrdHiy7XKF/TPTNgky6Wqdr/X+8 rRxYp5fC1DXOvjXJZlArnNbG2fbIgxeIFbJI/qjTut2fUyLlIN7vwn5zTKOyqaRT CJOSP039aJg= =1HgT -----END PGP SIGNATURE----- Merge tag 'usb-serial-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next Johan writes: USB-serial updates for v4.13-rc1 Here are the USB-serial updates for 4.13, including support for manipulating the modem-control signals of qcserial devices, propagation of errnos after late probe errors from usb-serial core, and a couple of clean ups. All have been in linux-next with no reported issues. Signed-off-by: Johan Hovold <johan@kernel.org>
This commit is contained in:
Коммит
0e4b470c0a
|
@ -454,6 +454,8 @@ static struct usb_serial_driver qcdevice = {
|
||||||
.write = usb_wwan_write,
|
.write = usb_wwan_write,
|
||||||
.write_room = usb_wwan_write_room,
|
.write_room = usb_wwan_write_room,
|
||||||
.chars_in_buffer = usb_wwan_chars_in_buffer,
|
.chars_in_buffer = usb_wwan_chars_in_buffer,
|
||||||
|
.tiocmget = usb_wwan_tiocmget,
|
||||||
|
.tiocmset = usb_wwan_tiocmset,
|
||||||
.attach = qc_attach,
|
.attach = qc_attach,
|
||||||
.release = qc_release,
|
.release = qc_release,
|
||||||
.port_probe = usb_wwan_port_probe,
|
.port_probe = usb_wwan_port_probe,
|
||||||
|
|
|
@ -288,7 +288,7 @@ static void upd78f0730_dtr_rts(struct usb_serial_port *port, int on)
|
||||||
static speed_t upd78f0730_get_baud_rate(struct tty_struct *tty)
|
static speed_t upd78f0730_get_baud_rate(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
const speed_t baud_rate = tty_get_baud_rate(tty);
|
const speed_t baud_rate = tty_get_baud_rate(tty);
|
||||||
const speed_t supported[] = {
|
static const speed_t supported[] = {
|
||||||
0, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 153600
|
0, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 153600
|
||||||
};
|
};
|
||||||
int i;
|
int i;
|
||||||
|
@ -384,7 +384,7 @@ static void upd78f0730_set_termios(struct tty_struct *tty,
|
||||||
|
|
||||||
static int upd78f0730_open(struct tty_struct *tty, struct usb_serial_port *port)
|
static int upd78f0730_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||||||
{
|
{
|
||||||
struct upd78f0730_open_close request = {
|
static const struct upd78f0730_open_close request = {
|
||||||
.opcode = UPD78F0730_CMD_OPEN_CLOSE,
|
.opcode = UPD78F0730_CMD_OPEN_CLOSE,
|
||||||
.state = UPD78F0730_PORT_OPEN
|
.state = UPD78F0730_PORT_OPEN
|
||||||
};
|
};
|
||||||
|
@ -402,7 +402,7 @@ static int upd78f0730_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||||||
|
|
||||||
static void upd78f0730_close(struct usb_serial_port *port)
|
static void upd78f0730_close(struct usb_serial_port *port)
|
||||||
{
|
{
|
||||||
struct upd78f0730_open_close request = {
|
static const struct upd78f0730_open_close request = {
|
||||||
.opcode = UPD78F0730_CMD_OPEN_CLOSE,
|
.opcode = UPD78F0730_CMD_OPEN_CLOSE,
|
||||||
.state = UPD78F0730_PORT_CLOSE
|
.state = UPD78F0730_PORT_CLOSE
|
||||||
};
|
};
|
||||||
|
|
|
@ -742,6 +742,124 @@ static void find_endpoints(struct usb_serial *serial,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int setup_port_bulk_in(struct usb_serial_port *port,
|
||||||
|
struct usb_endpoint_descriptor *epd)
|
||||||
|
{
|
||||||
|
struct usb_serial_driver *type = port->serial->type;
|
||||||
|
struct usb_device *udev = port->serial->dev;
|
||||||
|
int buffer_size;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
buffer_size = max_t(int, type->bulk_in_size, usb_endpoint_maxp(epd));
|
||||||
|
port->bulk_in_size = buffer_size;
|
||||||
|
port->bulk_in_endpointAddress = epd->bEndpointAddress;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
|
||||||
|
set_bit(i, &port->read_urbs_free);
|
||||||
|
port->read_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
|
if (!port->read_urbs[i])
|
||||||
|
return -ENOMEM;
|
||||||
|
port->bulk_in_buffers[i] = kmalloc(buffer_size, GFP_KERNEL);
|
||||||
|
if (!port->bulk_in_buffers[i])
|
||||||
|
return -ENOMEM;
|
||||||
|
usb_fill_bulk_urb(port->read_urbs[i], udev,
|
||||||
|
usb_rcvbulkpipe(udev, epd->bEndpointAddress),
|
||||||
|
port->bulk_in_buffers[i], buffer_size,
|
||||||
|
type->read_bulk_callback, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
port->read_urb = port->read_urbs[0];
|
||||||
|
port->bulk_in_buffer = port->bulk_in_buffers[0];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setup_port_bulk_out(struct usb_serial_port *port,
|
||||||
|
struct usb_endpoint_descriptor *epd)
|
||||||
|
{
|
||||||
|
struct usb_serial_driver *type = port->serial->type;
|
||||||
|
struct usb_device *udev = port->serial->dev;
|
||||||
|
int buffer_size;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))
|
||||||
|
return -ENOMEM;
|
||||||
|
if (type->bulk_out_size)
|
||||||
|
buffer_size = type->bulk_out_size;
|
||||||
|
else
|
||||||
|
buffer_size = usb_endpoint_maxp(epd);
|
||||||
|
port->bulk_out_size = buffer_size;
|
||||||
|
port->bulk_out_endpointAddress = epd->bEndpointAddress;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) {
|
||||||
|
set_bit(i, &port->write_urbs_free);
|
||||||
|
port->write_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
|
if (!port->write_urbs[i])
|
||||||
|
return -ENOMEM;
|
||||||
|
port->bulk_out_buffers[i] = kmalloc(buffer_size, GFP_KERNEL);
|
||||||
|
if (!port->bulk_out_buffers[i])
|
||||||
|
return -ENOMEM;
|
||||||
|
usb_fill_bulk_urb(port->write_urbs[i], udev,
|
||||||
|
usb_sndbulkpipe(udev, epd->bEndpointAddress),
|
||||||
|
port->bulk_out_buffers[i], buffer_size,
|
||||||
|
type->write_bulk_callback, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
port->write_urb = port->write_urbs[0];
|
||||||
|
port->bulk_out_buffer = port->bulk_out_buffers[0];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setup_port_interrupt_in(struct usb_serial_port *port,
|
||||||
|
struct usb_endpoint_descriptor *epd)
|
||||||
|
{
|
||||||
|
struct usb_serial_driver *type = port->serial->type;
|
||||||
|
struct usb_device *udev = port->serial->dev;
|
||||||
|
int buffer_size;
|
||||||
|
|
||||||
|
port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
|
if (!port->interrupt_in_urb)
|
||||||
|
return -ENOMEM;
|
||||||
|
buffer_size = usb_endpoint_maxp(epd);
|
||||||
|
port->interrupt_in_endpointAddress = epd->bEndpointAddress;
|
||||||
|
port->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
|
||||||
|
if (!port->interrupt_in_buffer)
|
||||||
|
return -ENOMEM;
|
||||||
|
usb_fill_int_urb(port->interrupt_in_urb, udev,
|
||||||
|
usb_rcvintpipe(udev, epd->bEndpointAddress),
|
||||||
|
port->interrupt_in_buffer, buffer_size,
|
||||||
|
type->read_int_callback, port,
|
||||||
|
epd->bInterval);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int setup_port_interrupt_out(struct usb_serial_port *port,
|
||||||
|
struct usb_endpoint_descriptor *epd)
|
||||||
|
{
|
||||||
|
struct usb_serial_driver *type = port->serial->type;
|
||||||
|
struct usb_device *udev = port->serial->dev;
|
||||||
|
int buffer_size;
|
||||||
|
|
||||||
|
port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
|
if (!port->interrupt_out_urb)
|
||||||
|
return -ENOMEM;
|
||||||
|
buffer_size = usb_endpoint_maxp(epd);
|
||||||
|
port->interrupt_out_size = buffer_size;
|
||||||
|
port->interrupt_out_endpointAddress = epd->bEndpointAddress;
|
||||||
|
port->interrupt_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
|
||||||
|
if (!port->interrupt_out_buffer)
|
||||||
|
return -ENOMEM;
|
||||||
|
usb_fill_int_urb(port->interrupt_out_urb, udev,
|
||||||
|
usb_sndintpipe(udev, epd->bEndpointAddress),
|
||||||
|
port->interrupt_out_buffer, buffer_size,
|
||||||
|
type->write_int_callback, port,
|
||||||
|
epd->bInterval);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int usb_serial_probe(struct usb_interface *interface,
|
static int usb_serial_probe(struct usb_interface *interface,
|
||||||
const struct usb_device_id *id)
|
const struct usb_device_id *id)
|
||||||
{
|
{
|
||||||
|
@ -749,13 +867,10 @@ static int usb_serial_probe(struct usb_interface *interface,
|
||||||
struct usb_device *dev = interface_to_usbdev(interface);
|
struct usb_device *dev = interface_to_usbdev(interface);
|
||||||
struct usb_serial *serial = NULL;
|
struct usb_serial *serial = NULL;
|
||||||
struct usb_serial_port *port;
|
struct usb_serial_port *port;
|
||||||
struct usb_endpoint_descriptor *endpoint;
|
|
||||||
struct usb_serial_endpoints *epds;
|
struct usb_serial_endpoints *epds;
|
||||||
struct usb_serial_driver *type = NULL;
|
struct usb_serial_driver *type = NULL;
|
||||||
int retval;
|
int retval;
|
||||||
int buffer_size;
|
|
||||||
int i;
|
int i;
|
||||||
int j;
|
|
||||||
int num_ports = 0;
|
int num_ports = 0;
|
||||||
unsigned char max_endpoints;
|
unsigned char max_endpoints;
|
||||||
|
|
||||||
|
@ -847,8 +962,10 @@ static int usb_serial_probe(struct usb_interface *interface,
|
||||||
dev_dbg(ddev, "setting up %d port structure(s)\n", max_endpoints);
|
dev_dbg(ddev, "setting up %d port structure(s)\n", max_endpoints);
|
||||||
for (i = 0; i < max_endpoints; ++i) {
|
for (i = 0; i < max_endpoints; ++i) {
|
||||||
port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
|
port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
|
||||||
if (!port)
|
if (!port) {
|
||||||
goto probe_error;
|
retval = -ENOMEM;
|
||||||
|
goto err_free_epds;
|
||||||
|
}
|
||||||
tty_port_init(&port->port);
|
tty_port_init(&port->port);
|
||||||
port->port.ops = &serial_port_ops;
|
port->port.ops = &serial_port_ops;
|
||||||
port->serial = serial;
|
port->serial = serial;
|
||||||
|
@ -867,86 +984,24 @@ static int usb_serial_probe(struct usb_interface *interface,
|
||||||
|
|
||||||
/* set up the endpoint information */
|
/* set up the endpoint information */
|
||||||
for (i = 0; i < epds->num_bulk_in; ++i) {
|
for (i = 0; i < epds->num_bulk_in; ++i) {
|
||||||
endpoint = epds->bulk_in[i];
|
retval = setup_port_bulk_in(serial->port[i], epds->bulk_in[i]);
|
||||||
port = serial->port[i];
|
if (retval)
|
||||||
buffer_size = max_t(int, serial->type->bulk_in_size,
|
goto err_free_epds;
|
||||||
usb_endpoint_maxp(endpoint));
|
|
||||||
port->bulk_in_size = buffer_size;
|
|
||||||
port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
|
|
||||||
|
|
||||||
for (j = 0; j < ARRAY_SIZE(port->read_urbs); ++j) {
|
|
||||||
set_bit(j, &port->read_urbs_free);
|
|
||||||
port->read_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
|
|
||||||
if (!port->read_urbs[j])
|
|
||||||
goto probe_error;
|
|
||||||
port->bulk_in_buffers[j] = kmalloc(buffer_size,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!port->bulk_in_buffers[j])
|
|
||||||
goto probe_error;
|
|
||||||
usb_fill_bulk_urb(port->read_urbs[j], dev,
|
|
||||||
usb_rcvbulkpipe(dev,
|
|
||||||
endpoint->bEndpointAddress),
|
|
||||||
port->bulk_in_buffers[j], buffer_size,
|
|
||||||
serial->type->read_bulk_callback,
|
|
||||||
port);
|
|
||||||
}
|
|
||||||
|
|
||||||
port->read_urb = port->read_urbs[0];
|
|
||||||
port->bulk_in_buffer = port->bulk_in_buffers[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < epds->num_bulk_out; ++i) {
|
for (i = 0; i < epds->num_bulk_out; ++i) {
|
||||||
endpoint = epds->bulk_out[i];
|
retval = setup_port_bulk_out(serial->port[i],
|
||||||
port = serial->port[i];
|
epds->bulk_out[i]);
|
||||||
if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))
|
if (retval)
|
||||||
goto probe_error;
|
goto err_free_epds;
|
||||||
buffer_size = serial->type->bulk_out_size;
|
|
||||||
if (!buffer_size)
|
|
||||||
buffer_size = usb_endpoint_maxp(endpoint);
|
|
||||||
port->bulk_out_size = buffer_size;
|
|
||||||
port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
|
|
||||||
|
|
||||||
for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) {
|
|
||||||
set_bit(j, &port->write_urbs_free);
|
|
||||||
port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
|
|
||||||
if (!port->write_urbs[j])
|
|
||||||
goto probe_error;
|
|
||||||
port->bulk_out_buffers[j] = kmalloc(buffer_size,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!port->bulk_out_buffers[j])
|
|
||||||
goto probe_error;
|
|
||||||
usb_fill_bulk_urb(port->write_urbs[j], dev,
|
|
||||||
usb_sndbulkpipe(dev,
|
|
||||||
endpoint->bEndpointAddress),
|
|
||||||
port->bulk_out_buffers[j], buffer_size,
|
|
||||||
serial->type->write_bulk_callback,
|
|
||||||
port);
|
|
||||||
}
|
|
||||||
|
|
||||||
port->write_urb = port->write_urbs[0];
|
|
||||||
port->bulk_out_buffer = port->bulk_out_buffers[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serial->type->read_int_callback) {
|
if (serial->type->read_int_callback) {
|
||||||
for (i = 0; i < epds->num_interrupt_in; ++i) {
|
for (i = 0; i < epds->num_interrupt_in; ++i) {
|
||||||
endpoint = epds->interrupt_in[i];
|
retval = setup_port_interrupt_in(serial->port[i],
|
||||||
port = serial->port[i];
|
epds->interrupt_in[i]);
|
||||||
port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
|
if (retval)
|
||||||
if (!port->interrupt_in_urb)
|
goto err_free_epds;
|
||||||
goto probe_error;
|
|
||||||
buffer_size = usb_endpoint_maxp(endpoint);
|
|
||||||
port->interrupt_in_endpointAddress =
|
|
||||||
endpoint->bEndpointAddress;
|
|
||||||
port->interrupt_in_buffer = kmalloc(buffer_size,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!port->interrupt_in_buffer)
|
|
||||||
goto probe_error;
|
|
||||||
usb_fill_int_urb(port->interrupt_in_urb, dev,
|
|
||||||
usb_rcvintpipe(dev,
|
|
||||||
endpoint->bEndpointAddress),
|
|
||||||
port->interrupt_in_buffer, buffer_size,
|
|
||||||
serial->type->read_int_callback, port,
|
|
||||||
endpoint->bInterval);
|
|
||||||
}
|
}
|
||||||
} else if (epds->num_interrupt_in) {
|
} else if (epds->num_interrupt_in) {
|
||||||
dev_dbg(ddev, "The device claims to support interrupt in transfers, but read_int_callback is not defined\n");
|
dev_dbg(ddev, "The device claims to support interrupt in transfers, but read_int_callback is not defined\n");
|
||||||
|
@ -954,25 +1009,10 @@ static int usb_serial_probe(struct usb_interface *interface,
|
||||||
|
|
||||||
if (serial->type->write_int_callback) {
|
if (serial->type->write_int_callback) {
|
||||||
for (i = 0; i < epds->num_interrupt_out; ++i) {
|
for (i = 0; i < epds->num_interrupt_out; ++i) {
|
||||||
endpoint = epds->interrupt_out[i];
|
retval = setup_port_interrupt_out(serial->port[i],
|
||||||
port = serial->port[i];
|
epds->interrupt_out[i]);
|
||||||
port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
|
if (retval)
|
||||||
if (!port->interrupt_out_urb)
|
goto err_free_epds;
|
||||||
goto probe_error;
|
|
||||||
buffer_size = usb_endpoint_maxp(endpoint);
|
|
||||||
port->interrupt_out_size = buffer_size;
|
|
||||||
port->interrupt_out_endpointAddress =
|
|
||||||
endpoint->bEndpointAddress;
|
|
||||||
port->interrupt_out_buffer = kmalloc(buffer_size,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!port->interrupt_out_buffer)
|
|
||||||
goto probe_error;
|
|
||||||
usb_fill_int_urb(port->interrupt_out_urb, dev,
|
|
||||||
usb_sndintpipe(dev,
|
|
||||||
endpoint->bEndpointAddress),
|
|
||||||
port->interrupt_out_buffer, buffer_size,
|
|
||||||
serial->type->write_int_callback, port,
|
|
||||||
endpoint->bInterval);
|
|
||||||
}
|
}
|
||||||
} else if (epds->num_interrupt_out) {
|
} else if (epds->num_interrupt_out) {
|
||||||
dev_dbg(ddev, "The device claims to support interrupt out transfers, but write_int_callback is not defined\n");
|
dev_dbg(ddev, "The device claims to support interrupt out transfers, but write_int_callback is not defined\n");
|
||||||
|
@ -984,7 +1024,7 @@ static int usb_serial_probe(struct usb_interface *interface,
|
||||||
if (type->attach) {
|
if (type->attach) {
|
||||||
retval = type->attach(serial);
|
retval = type->attach(serial);
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
goto probe_error;
|
goto err_free_epds;
|
||||||
serial->attached = 1;
|
serial->attached = 1;
|
||||||
if (retval > 0) {
|
if (retval > 0) {
|
||||||
/* quietly accept this device, but don't bind to a
|
/* quietly accept this device, but don't bind to a
|
||||||
|
@ -996,9 +1036,10 @@ static int usb_serial_probe(struct usb_interface *interface,
|
||||||
serial->attached = 1;
|
serial->attached = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allocate_minors(serial, num_ports)) {
|
retval = allocate_minors(serial, num_ports);
|
||||||
|
if (retval) {
|
||||||
dev_err(ddev, "No more free serial minor numbers\n");
|
dev_err(ddev, "No more free serial minor numbers\n");
|
||||||
goto probe_error;
|
goto err_free_epds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* register all of the individual ports with the driver core */
|
/* register all of the individual ports with the driver core */
|
||||||
|
@ -1020,8 +1061,6 @@ exit:
|
||||||
module_put(type->driver.owner);
|
module_put(type->driver.owner);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
probe_error:
|
|
||||||
retval = -EIO;
|
|
||||||
err_free_epds:
|
err_free_epds:
|
||||||
kfree(epds);
|
kfree(epds);
|
||||||
err_put_serial:
|
err_put_serial:
|
||||||
|
|
Загрузка…
Ссылка в новой задаче