1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * f_phonet.c -- USB CDC Phonet function
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2007-2008 Nokia Corporation. All rights reserved.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Author: Rémi Denis-Courmont
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/mm.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/device.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include <linux/netdevice.h>
17*4882a593Smuzhiyun #include <linux/if_ether.h>
18*4882a593Smuzhiyun #include <linux/if_phonet.h>
19*4882a593Smuzhiyun #include <linux/if_arp.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include <linux/usb/ch9.h>
22*4882a593Smuzhiyun #include <linux/usb/cdc.h>
23*4882a593Smuzhiyun #include <linux/usb/composite.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include "u_phonet.h"
26*4882a593Smuzhiyun #include "u_ether.h"
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #define PN_MEDIA_USB 0x1B
29*4882a593Smuzhiyun #define MAXPACKET 512
30*4882a593Smuzhiyun #if (PAGE_SIZE % MAXPACKET)
31*4882a593Smuzhiyun #error MAXPACKET must divide PAGE_SIZE!
32*4882a593Smuzhiyun #endif
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun struct phonet_port {
37*4882a593Smuzhiyun struct f_phonet *usb;
38*4882a593Smuzhiyun spinlock_t lock;
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun struct f_phonet {
42*4882a593Smuzhiyun struct usb_function function;
43*4882a593Smuzhiyun struct {
44*4882a593Smuzhiyun struct sk_buff *skb;
45*4882a593Smuzhiyun spinlock_t lock;
46*4882a593Smuzhiyun } rx;
47*4882a593Smuzhiyun struct net_device *dev;
48*4882a593Smuzhiyun struct usb_ep *in_ep, *out_ep;
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun struct usb_request *in_req;
51*4882a593Smuzhiyun struct usb_request *out_reqv[];
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun static int phonet_rxq_size = 17;
55*4882a593Smuzhiyun
func_to_pn(struct usb_function * f)56*4882a593Smuzhiyun static inline struct f_phonet *func_to_pn(struct usb_function *f)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun return container_of(f, struct f_phonet, function);
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun #define USB_CDC_SUBCLASS_PHONET 0xfe
64*4882a593Smuzhiyun #define USB_CDC_PHONET_TYPE 0xab
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun static struct usb_interface_descriptor
67*4882a593Smuzhiyun pn_control_intf_desc = {
68*4882a593Smuzhiyun .bLength = sizeof pn_control_intf_desc,
69*4882a593Smuzhiyun .bDescriptorType = USB_DT_INTERFACE,
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun /* .bInterfaceNumber = DYNAMIC, */
72*4882a593Smuzhiyun .bInterfaceClass = USB_CLASS_COMM,
73*4882a593Smuzhiyun .bInterfaceSubClass = USB_CDC_SUBCLASS_PHONET,
74*4882a593Smuzhiyun };
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun static const struct usb_cdc_header_desc
77*4882a593Smuzhiyun pn_header_desc = {
78*4882a593Smuzhiyun .bLength = sizeof pn_header_desc,
79*4882a593Smuzhiyun .bDescriptorType = USB_DT_CS_INTERFACE,
80*4882a593Smuzhiyun .bDescriptorSubType = USB_CDC_HEADER_TYPE,
81*4882a593Smuzhiyun .bcdCDC = cpu_to_le16(0x0110),
82*4882a593Smuzhiyun };
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun static const struct usb_cdc_header_desc
85*4882a593Smuzhiyun pn_phonet_desc = {
86*4882a593Smuzhiyun .bLength = sizeof pn_phonet_desc,
87*4882a593Smuzhiyun .bDescriptorType = USB_DT_CS_INTERFACE,
88*4882a593Smuzhiyun .bDescriptorSubType = USB_CDC_PHONET_TYPE,
89*4882a593Smuzhiyun .bcdCDC = cpu_to_le16(0x1505), /* ??? */
90*4882a593Smuzhiyun };
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun static struct usb_cdc_union_desc
93*4882a593Smuzhiyun pn_union_desc = {
94*4882a593Smuzhiyun .bLength = sizeof pn_union_desc,
95*4882a593Smuzhiyun .bDescriptorType = USB_DT_CS_INTERFACE,
96*4882a593Smuzhiyun .bDescriptorSubType = USB_CDC_UNION_TYPE,
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /* .bMasterInterface0 = DYNAMIC, */
99*4882a593Smuzhiyun /* .bSlaveInterface0 = DYNAMIC, */
100*4882a593Smuzhiyun };
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun static struct usb_interface_descriptor
103*4882a593Smuzhiyun pn_data_nop_intf_desc = {
104*4882a593Smuzhiyun .bLength = sizeof pn_data_nop_intf_desc,
105*4882a593Smuzhiyun .bDescriptorType = USB_DT_INTERFACE,
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun /* .bInterfaceNumber = DYNAMIC, */
108*4882a593Smuzhiyun .bAlternateSetting = 0,
109*4882a593Smuzhiyun .bNumEndpoints = 0,
110*4882a593Smuzhiyun .bInterfaceClass = USB_CLASS_CDC_DATA,
111*4882a593Smuzhiyun };
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun static struct usb_interface_descriptor
114*4882a593Smuzhiyun pn_data_intf_desc = {
115*4882a593Smuzhiyun .bLength = sizeof pn_data_intf_desc,
116*4882a593Smuzhiyun .bDescriptorType = USB_DT_INTERFACE,
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun /* .bInterfaceNumber = DYNAMIC, */
119*4882a593Smuzhiyun .bAlternateSetting = 1,
120*4882a593Smuzhiyun .bNumEndpoints = 2,
121*4882a593Smuzhiyun .bInterfaceClass = USB_CLASS_CDC_DATA,
122*4882a593Smuzhiyun };
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun static struct usb_endpoint_descriptor
125*4882a593Smuzhiyun pn_fs_sink_desc = {
126*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
127*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun .bEndpointAddress = USB_DIR_OUT,
130*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
131*4882a593Smuzhiyun };
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun static struct usb_endpoint_descriptor
134*4882a593Smuzhiyun pn_hs_sink_desc = {
135*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
136*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun .bEndpointAddress = USB_DIR_OUT,
139*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
140*4882a593Smuzhiyun .wMaxPacketSize = cpu_to_le16(MAXPACKET),
141*4882a593Smuzhiyun };
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun static struct usb_endpoint_descriptor
144*4882a593Smuzhiyun pn_fs_source_desc = {
145*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
146*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun .bEndpointAddress = USB_DIR_IN,
149*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun static struct usb_endpoint_descriptor
153*4882a593Smuzhiyun pn_hs_source_desc = {
154*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
155*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun .bEndpointAddress = USB_DIR_IN,
158*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_BULK,
159*4882a593Smuzhiyun .wMaxPacketSize = cpu_to_le16(512),
160*4882a593Smuzhiyun };
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun static struct usb_descriptor_header *fs_pn_function[] = {
163*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_control_intf_desc,
164*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_header_desc,
165*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_phonet_desc,
166*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_union_desc,
167*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_data_nop_intf_desc,
168*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_data_intf_desc,
169*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_fs_sink_desc,
170*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_fs_source_desc,
171*4882a593Smuzhiyun NULL,
172*4882a593Smuzhiyun };
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun static struct usb_descriptor_header *hs_pn_function[] = {
175*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_control_intf_desc,
176*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_header_desc,
177*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_phonet_desc,
178*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_union_desc,
179*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_data_nop_intf_desc,
180*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_data_intf_desc,
181*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_hs_sink_desc,
182*4882a593Smuzhiyun (struct usb_descriptor_header *) &pn_hs_source_desc,
183*4882a593Smuzhiyun NULL,
184*4882a593Smuzhiyun };
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
187*4882a593Smuzhiyun
pn_net_open(struct net_device * dev)188*4882a593Smuzhiyun static int pn_net_open(struct net_device *dev)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun netif_wake_queue(dev);
191*4882a593Smuzhiyun return 0;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
pn_net_close(struct net_device * dev)194*4882a593Smuzhiyun static int pn_net_close(struct net_device *dev)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun netif_stop_queue(dev);
197*4882a593Smuzhiyun return 0;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
pn_tx_complete(struct usb_ep * ep,struct usb_request * req)200*4882a593Smuzhiyun static void pn_tx_complete(struct usb_ep *ep, struct usb_request *req)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun struct f_phonet *fp = ep->driver_data;
203*4882a593Smuzhiyun struct net_device *dev = fp->dev;
204*4882a593Smuzhiyun struct sk_buff *skb = req->context;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun switch (req->status) {
207*4882a593Smuzhiyun case 0:
208*4882a593Smuzhiyun dev->stats.tx_packets++;
209*4882a593Smuzhiyun dev->stats.tx_bytes += skb->len;
210*4882a593Smuzhiyun break;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun case -ESHUTDOWN: /* disconnected */
213*4882a593Smuzhiyun case -ECONNRESET: /* disabled */
214*4882a593Smuzhiyun dev->stats.tx_aborted_errors++;
215*4882a593Smuzhiyun fallthrough;
216*4882a593Smuzhiyun default:
217*4882a593Smuzhiyun dev->stats.tx_errors++;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun dev_kfree_skb_any(skb);
221*4882a593Smuzhiyun netif_wake_queue(dev);
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
pn_net_xmit(struct sk_buff * skb,struct net_device * dev)224*4882a593Smuzhiyun static netdev_tx_t pn_net_xmit(struct sk_buff *skb, struct net_device *dev)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun struct phonet_port *port = netdev_priv(dev);
227*4882a593Smuzhiyun struct f_phonet *fp;
228*4882a593Smuzhiyun struct usb_request *req;
229*4882a593Smuzhiyun unsigned long flags;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun if (skb->protocol != htons(ETH_P_PHONET))
232*4882a593Smuzhiyun goto out;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
235*4882a593Smuzhiyun fp = port->usb;
236*4882a593Smuzhiyun if (unlikely(!fp)) /* race with carrier loss */
237*4882a593Smuzhiyun goto out_unlock;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun req = fp->in_req;
240*4882a593Smuzhiyun req->buf = skb->data;
241*4882a593Smuzhiyun req->length = skb->len;
242*4882a593Smuzhiyun req->complete = pn_tx_complete;
243*4882a593Smuzhiyun req->zero = 1;
244*4882a593Smuzhiyun req->context = skb;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun if (unlikely(usb_ep_queue(fp->in_ep, req, GFP_ATOMIC)))
247*4882a593Smuzhiyun goto out_unlock;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun netif_stop_queue(dev);
250*4882a593Smuzhiyun skb = NULL;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun out_unlock:
253*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
254*4882a593Smuzhiyun out:
255*4882a593Smuzhiyun if (unlikely(skb)) {
256*4882a593Smuzhiyun dev_kfree_skb(skb);
257*4882a593Smuzhiyun dev->stats.tx_dropped++;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun return NETDEV_TX_OK;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun static const struct net_device_ops pn_netdev_ops = {
263*4882a593Smuzhiyun .ndo_open = pn_net_open,
264*4882a593Smuzhiyun .ndo_stop = pn_net_close,
265*4882a593Smuzhiyun .ndo_start_xmit = pn_net_xmit,
266*4882a593Smuzhiyun };
267*4882a593Smuzhiyun
pn_net_setup(struct net_device * dev)268*4882a593Smuzhiyun static void pn_net_setup(struct net_device *dev)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun dev->features = 0;
271*4882a593Smuzhiyun dev->type = ARPHRD_PHONET;
272*4882a593Smuzhiyun dev->flags = IFF_POINTOPOINT | IFF_NOARP;
273*4882a593Smuzhiyun dev->mtu = PHONET_DEV_MTU;
274*4882a593Smuzhiyun dev->min_mtu = PHONET_MIN_MTU;
275*4882a593Smuzhiyun dev->max_mtu = PHONET_MAX_MTU;
276*4882a593Smuzhiyun dev->hard_header_len = 1;
277*4882a593Smuzhiyun dev->dev_addr[0] = PN_MEDIA_USB;
278*4882a593Smuzhiyun dev->addr_len = 1;
279*4882a593Smuzhiyun dev->tx_queue_len = 1;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun dev->netdev_ops = &pn_netdev_ops;
282*4882a593Smuzhiyun dev->needs_free_netdev = true;
283*4882a593Smuzhiyun dev->header_ops = &phonet_header_ops;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun /*
289*4882a593Smuzhiyun * Queue buffer for data from the host
290*4882a593Smuzhiyun */
291*4882a593Smuzhiyun static int
pn_rx_submit(struct f_phonet * fp,struct usb_request * req,gfp_t gfp_flags)292*4882a593Smuzhiyun pn_rx_submit(struct f_phonet *fp, struct usb_request *req, gfp_t gfp_flags)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun struct page *page;
295*4882a593Smuzhiyun int err;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun page = __dev_alloc_page(gfp_flags | __GFP_NOMEMALLOC);
298*4882a593Smuzhiyun if (!page)
299*4882a593Smuzhiyun return -ENOMEM;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun req->buf = page_address(page);
302*4882a593Smuzhiyun req->length = PAGE_SIZE;
303*4882a593Smuzhiyun req->context = page;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun err = usb_ep_queue(fp->out_ep, req, gfp_flags);
306*4882a593Smuzhiyun if (unlikely(err))
307*4882a593Smuzhiyun put_page(page);
308*4882a593Smuzhiyun return err;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun
pn_rx_complete(struct usb_ep * ep,struct usb_request * req)311*4882a593Smuzhiyun static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun struct f_phonet *fp = ep->driver_data;
314*4882a593Smuzhiyun struct net_device *dev = fp->dev;
315*4882a593Smuzhiyun struct page *page = req->context;
316*4882a593Smuzhiyun struct sk_buff *skb;
317*4882a593Smuzhiyun unsigned long flags;
318*4882a593Smuzhiyun int status = req->status;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun switch (status) {
321*4882a593Smuzhiyun case 0:
322*4882a593Smuzhiyun spin_lock_irqsave(&fp->rx.lock, flags);
323*4882a593Smuzhiyun skb = fp->rx.skb;
324*4882a593Smuzhiyun if (!skb)
325*4882a593Smuzhiyun skb = fp->rx.skb = netdev_alloc_skb(dev, 12);
326*4882a593Smuzhiyun if (req->actual < req->length) /* Last fragment */
327*4882a593Smuzhiyun fp->rx.skb = NULL;
328*4882a593Smuzhiyun spin_unlock_irqrestore(&fp->rx.lock, flags);
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun if (unlikely(!skb))
331*4882a593Smuzhiyun break;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun if (skb->len == 0) { /* First fragment */
334*4882a593Smuzhiyun skb->protocol = htons(ETH_P_PHONET);
335*4882a593Smuzhiyun skb_reset_mac_header(skb);
336*4882a593Smuzhiyun /* Can't use pskb_pull() on page in IRQ */
337*4882a593Smuzhiyun skb_put_data(skb, page_address(page), 1);
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
341*4882a593Smuzhiyun skb->len <= 1, req->actual, PAGE_SIZE);
342*4882a593Smuzhiyun page = NULL;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun if (req->actual < req->length) { /* Last fragment */
345*4882a593Smuzhiyun skb->dev = dev;
346*4882a593Smuzhiyun dev->stats.rx_packets++;
347*4882a593Smuzhiyun dev->stats.rx_bytes += skb->len;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun netif_rx(skb);
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun break;
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun /* Do not resubmit in these cases: */
354*4882a593Smuzhiyun case -ESHUTDOWN: /* disconnect */
355*4882a593Smuzhiyun case -ECONNABORTED: /* hw reset */
356*4882a593Smuzhiyun case -ECONNRESET: /* dequeued (unlink or netif down) */
357*4882a593Smuzhiyun req = NULL;
358*4882a593Smuzhiyun break;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun /* Do resubmit in these cases: */
361*4882a593Smuzhiyun case -EOVERFLOW: /* request buffer overflow */
362*4882a593Smuzhiyun dev->stats.rx_over_errors++;
363*4882a593Smuzhiyun fallthrough;
364*4882a593Smuzhiyun default:
365*4882a593Smuzhiyun dev->stats.rx_errors++;
366*4882a593Smuzhiyun break;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun if (page)
370*4882a593Smuzhiyun put_page(page);
371*4882a593Smuzhiyun if (req)
372*4882a593Smuzhiyun pn_rx_submit(fp, req, GFP_ATOMIC);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
376*4882a593Smuzhiyun
__pn_reset(struct usb_function * f)377*4882a593Smuzhiyun static void __pn_reset(struct usb_function *f)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun struct f_phonet *fp = func_to_pn(f);
380*4882a593Smuzhiyun struct net_device *dev = fp->dev;
381*4882a593Smuzhiyun struct phonet_port *port = netdev_priv(dev);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun netif_carrier_off(dev);
384*4882a593Smuzhiyun port->usb = NULL;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun usb_ep_disable(fp->out_ep);
387*4882a593Smuzhiyun usb_ep_disable(fp->in_ep);
388*4882a593Smuzhiyun if (fp->rx.skb) {
389*4882a593Smuzhiyun dev_kfree_skb_irq(fp->rx.skb);
390*4882a593Smuzhiyun fp->rx.skb = NULL;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
pn_set_alt(struct usb_function * f,unsigned intf,unsigned alt)394*4882a593Smuzhiyun static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun struct f_phonet *fp = func_to_pn(f);
397*4882a593Smuzhiyun struct usb_gadget *gadget = fp->function.config->cdev->gadget;
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun if (intf == pn_control_intf_desc.bInterfaceNumber)
400*4882a593Smuzhiyun /* control interface, no altsetting */
401*4882a593Smuzhiyun return (alt > 0) ? -EINVAL : 0;
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun if (intf == pn_data_intf_desc.bInterfaceNumber) {
404*4882a593Smuzhiyun struct net_device *dev = fp->dev;
405*4882a593Smuzhiyun struct phonet_port *port = netdev_priv(dev);
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun /* data intf (0: inactive, 1: active) */
408*4882a593Smuzhiyun if (alt > 1)
409*4882a593Smuzhiyun return -EINVAL;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun spin_lock(&port->lock);
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun if (fp->in_ep->enabled)
414*4882a593Smuzhiyun __pn_reset(f);
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun if (alt == 1) {
417*4882a593Smuzhiyun int i;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun if (config_ep_by_speed(gadget, f, fp->in_ep) ||
420*4882a593Smuzhiyun config_ep_by_speed(gadget, f, fp->out_ep)) {
421*4882a593Smuzhiyun fp->in_ep->desc = NULL;
422*4882a593Smuzhiyun fp->out_ep->desc = NULL;
423*4882a593Smuzhiyun spin_unlock(&port->lock);
424*4882a593Smuzhiyun return -EINVAL;
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun usb_ep_enable(fp->out_ep);
427*4882a593Smuzhiyun usb_ep_enable(fp->in_ep);
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun port->usb = fp;
430*4882a593Smuzhiyun fp->out_ep->driver_data = fp;
431*4882a593Smuzhiyun fp->in_ep->driver_data = fp;
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun netif_carrier_on(dev);
434*4882a593Smuzhiyun for (i = 0; i < phonet_rxq_size; i++)
435*4882a593Smuzhiyun pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC);
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun spin_unlock(&port->lock);
438*4882a593Smuzhiyun return 0;
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun return -EINVAL;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
pn_get_alt(struct usb_function * f,unsigned intf)444*4882a593Smuzhiyun static int pn_get_alt(struct usb_function *f, unsigned intf)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun struct f_phonet *fp = func_to_pn(f);
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun if (intf == pn_control_intf_desc.bInterfaceNumber)
449*4882a593Smuzhiyun return 0;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun if (intf == pn_data_intf_desc.bInterfaceNumber) {
452*4882a593Smuzhiyun struct phonet_port *port = netdev_priv(fp->dev);
453*4882a593Smuzhiyun u8 alt;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun spin_lock(&port->lock);
456*4882a593Smuzhiyun alt = port->usb != NULL;
457*4882a593Smuzhiyun spin_unlock(&port->lock);
458*4882a593Smuzhiyun return alt;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun return -EINVAL;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
pn_disconnect(struct usb_function * f)464*4882a593Smuzhiyun static void pn_disconnect(struct usb_function *f)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun struct f_phonet *fp = func_to_pn(f);
467*4882a593Smuzhiyun struct phonet_port *port = netdev_priv(fp->dev);
468*4882a593Smuzhiyun unsigned long flags;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun /* remain disabled until set_alt */
471*4882a593Smuzhiyun spin_lock_irqsave(&port->lock, flags);
472*4882a593Smuzhiyun __pn_reset(f);
473*4882a593Smuzhiyun spin_unlock_irqrestore(&port->lock, flags);
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
477*4882a593Smuzhiyun
pn_bind(struct usb_configuration * c,struct usb_function * f)478*4882a593Smuzhiyun static int pn_bind(struct usb_configuration *c, struct usb_function *f)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun struct usb_composite_dev *cdev = c->cdev;
481*4882a593Smuzhiyun struct usb_gadget *gadget = cdev->gadget;
482*4882a593Smuzhiyun struct f_phonet *fp = func_to_pn(f);
483*4882a593Smuzhiyun struct usb_ep *ep;
484*4882a593Smuzhiyun int status, i;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun struct f_phonet_opts *phonet_opts;
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun phonet_opts = container_of(f->fi, struct f_phonet_opts, func_inst);
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun /*
491*4882a593Smuzhiyun * in drivers/usb/gadget/configfs.c:configfs_composite_bind()
492*4882a593Smuzhiyun * configurations are bound in sequence with list_for_each_entry,
493*4882a593Smuzhiyun * in each configuration its functions are bound in sequence
494*4882a593Smuzhiyun * with list_for_each_entry, so we assume no race condition
495*4882a593Smuzhiyun * with regard to phonet_opts->bound access
496*4882a593Smuzhiyun */
497*4882a593Smuzhiyun if (!phonet_opts->bound) {
498*4882a593Smuzhiyun gphonet_set_gadget(phonet_opts->net, gadget);
499*4882a593Smuzhiyun status = gphonet_register_netdev(phonet_opts->net);
500*4882a593Smuzhiyun if (status)
501*4882a593Smuzhiyun return status;
502*4882a593Smuzhiyun phonet_opts->bound = true;
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun /* Reserve interface IDs */
506*4882a593Smuzhiyun status = usb_interface_id(c, f);
507*4882a593Smuzhiyun if (status < 0)
508*4882a593Smuzhiyun goto err;
509*4882a593Smuzhiyun pn_control_intf_desc.bInterfaceNumber = status;
510*4882a593Smuzhiyun pn_union_desc.bMasterInterface0 = status;
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun status = usb_interface_id(c, f);
513*4882a593Smuzhiyun if (status < 0)
514*4882a593Smuzhiyun goto err;
515*4882a593Smuzhiyun pn_data_nop_intf_desc.bInterfaceNumber = status;
516*4882a593Smuzhiyun pn_data_intf_desc.bInterfaceNumber = status;
517*4882a593Smuzhiyun pn_union_desc.bSlaveInterface0 = status;
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun /* Reserve endpoints */
520*4882a593Smuzhiyun status = -ENODEV;
521*4882a593Smuzhiyun ep = usb_ep_autoconfig(gadget, &pn_fs_sink_desc);
522*4882a593Smuzhiyun if (!ep)
523*4882a593Smuzhiyun goto err;
524*4882a593Smuzhiyun fp->out_ep = ep;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun ep = usb_ep_autoconfig(gadget, &pn_fs_source_desc);
527*4882a593Smuzhiyun if (!ep)
528*4882a593Smuzhiyun goto err;
529*4882a593Smuzhiyun fp->in_ep = ep;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun pn_hs_sink_desc.bEndpointAddress = pn_fs_sink_desc.bEndpointAddress;
532*4882a593Smuzhiyun pn_hs_source_desc.bEndpointAddress = pn_fs_source_desc.bEndpointAddress;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun /* Do not try to bind Phonet twice... */
535*4882a593Smuzhiyun status = usb_assign_descriptors(f, fs_pn_function, hs_pn_function,
536*4882a593Smuzhiyun NULL, NULL);
537*4882a593Smuzhiyun if (status)
538*4882a593Smuzhiyun goto err;
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun /* Incoming USB requests */
541*4882a593Smuzhiyun status = -ENOMEM;
542*4882a593Smuzhiyun for (i = 0; i < phonet_rxq_size; i++) {
543*4882a593Smuzhiyun struct usb_request *req;
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun req = usb_ep_alloc_request(fp->out_ep, GFP_KERNEL);
546*4882a593Smuzhiyun if (!req)
547*4882a593Smuzhiyun goto err_req;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun req->complete = pn_rx_complete;
550*4882a593Smuzhiyun fp->out_reqv[i] = req;
551*4882a593Smuzhiyun }
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun /* Outgoing USB requests */
554*4882a593Smuzhiyun fp->in_req = usb_ep_alloc_request(fp->in_ep, GFP_KERNEL);
555*4882a593Smuzhiyun if (!fp->in_req)
556*4882a593Smuzhiyun goto err_req;
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun INFO(cdev, "USB CDC Phonet function\n");
559*4882a593Smuzhiyun INFO(cdev, "using %s, OUT %s, IN %s\n", cdev->gadget->name,
560*4882a593Smuzhiyun fp->out_ep->name, fp->in_ep->name);
561*4882a593Smuzhiyun return 0;
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun err_req:
564*4882a593Smuzhiyun for (i = 0; i < phonet_rxq_size && fp->out_reqv[i]; i++)
565*4882a593Smuzhiyun usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
566*4882a593Smuzhiyun usb_free_all_descriptors(f);
567*4882a593Smuzhiyun err:
568*4882a593Smuzhiyun ERROR(cdev, "USB CDC Phonet: cannot autoconfigure\n");
569*4882a593Smuzhiyun return status;
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun
to_f_phonet_opts(struct config_item * item)572*4882a593Smuzhiyun static inline struct f_phonet_opts *to_f_phonet_opts(struct config_item *item)
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun return container_of(to_config_group(item), struct f_phonet_opts,
575*4882a593Smuzhiyun func_inst.group);
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun
phonet_attr_release(struct config_item * item)578*4882a593Smuzhiyun static void phonet_attr_release(struct config_item *item)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun struct f_phonet_opts *opts = to_f_phonet_opts(item);
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun usb_put_function_instance(&opts->func_inst);
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun static struct configfs_item_operations phonet_item_ops = {
586*4882a593Smuzhiyun .release = phonet_attr_release,
587*4882a593Smuzhiyun };
588*4882a593Smuzhiyun
f_phonet_ifname_show(struct config_item * item,char * page)589*4882a593Smuzhiyun static ssize_t f_phonet_ifname_show(struct config_item *item, char *page)
590*4882a593Smuzhiyun {
591*4882a593Smuzhiyun return gether_get_ifname(to_f_phonet_opts(item)->net, page, PAGE_SIZE);
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun CONFIGFS_ATTR_RO(f_phonet_, ifname);
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun static struct configfs_attribute *phonet_attrs[] = {
597*4882a593Smuzhiyun &f_phonet_attr_ifname,
598*4882a593Smuzhiyun NULL,
599*4882a593Smuzhiyun };
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun static const struct config_item_type phonet_func_type = {
602*4882a593Smuzhiyun .ct_item_ops = &phonet_item_ops,
603*4882a593Smuzhiyun .ct_attrs = phonet_attrs,
604*4882a593Smuzhiyun .ct_owner = THIS_MODULE,
605*4882a593Smuzhiyun };
606*4882a593Smuzhiyun
phonet_free_inst(struct usb_function_instance * f)607*4882a593Smuzhiyun static void phonet_free_inst(struct usb_function_instance *f)
608*4882a593Smuzhiyun {
609*4882a593Smuzhiyun struct f_phonet_opts *opts;
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun opts = container_of(f, struct f_phonet_opts, func_inst);
612*4882a593Smuzhiyun if (opts->bound)
613*4882a593Smuzhiyun gphonet_cleanup(opts->net);
614*4882a593Smuzhiyun else
615*4882a593Smuzhiyun free_netdev(opts->net);
616*4882a593Smuzhiyun kfree(opts);
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun
phonet_alloc_inst(void)619*4882a593Smuzhiyun static struct usb_function_instance *phonet_alloc_inst(void)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun struct f_phonet_opts *opts;
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun opts = kzalloc(sizeof(*opts), GFP_KERNEL);
624*4882a593Smuzhiyun if (!opts)
625*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun opts->func_inst.free_func_inst = phonet_free_inst;
628*4882a593Smuzhiyun opts->net = gphonet_setup_default();
629*4882a593Smuzhiyun if (IS_ERR(opts->net)) {
630*4882a593Smuzhiyun struct net_device *net = opts->net;
631*4882a593Smuzhiyun kfree(opts);
632*4882a593Smuzhiyun return ERR_CAST(net);
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun config_group_init_type_name(&opts->func_inst.group, "",
636*4882a593Smuzhiyun &phonet_func_type);
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun return &opts->func_inst;
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun
phonet_free(struct usb_function * f)641*4882a593Smuzhiyun static void phonet_free(struct usb_function *f)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun struct f_phonet *phonet;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun phonet = func_to_pn(f);
646*4882a593Smuzhiyun kfree(phonet);
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun
pn_unbind(struct usb_configuration * c,struct usb_function * f)649*4882a593Smuzhiyun static void pn_unbind(struct usb_configuration *c, struct usb_function *f)
650*4882a593Smuzhiyun {
651*4882a593Smuzhiyun struct f_phonet *fp = func_to_pn(f);
652*4882a593Smuzhiyun int i;
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun /* We are already disconnected */
655*4882a593Smuzhiyun if (fp->in_req)
656*4882a593Smuzhiyun usb_ep_free_request(fp->in_ep, fp->in_req);
657*4882a593Smuzhiyun for (i = 0; i < phonet_rxq_size; i++)
658*4882a593Smuzhiyun if (fp->out_reqv[i])
659*4882a593Smuzhiyun usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun usb_free_all_descriptors(f);
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun
phonet_alloc(struct usb_function_instance * fi)664*4882a593Smuzhiyun static struct usb_function *phonet_alloc(struct usb_function_instance *fi)
665*4882a593Smuzhiyun {
666*4882a593Smuzhiyun struct f_phonet *fp;
667*4882a593Smuzhiyun struct f_phonet_opts *opts;
668*4882a593Smuzhiyun int size;
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun size = sizeof(*fp) + (phonet_rxq_size * sizeof(struct usb_request *));
671*4882a593Smuzhiyun fp = kzalloc(size, GFP_KERNEL);
672*4882a593Smuzhiyun if (!fp)
673*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun opts = container_of(fi, struct f_phonet_opts, func_inst);
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun fp->dev = opts->net;
678*4882a593Smuzhiyun fp->function.name = "phonet";
679*4882a593Smuzhiyun fp->function.bind = pn_bind;
680*4882a593Smuzhiyun fp->function.unbind = pn_unbind;
681*4882a593Smuzhiyun fp->function.set_alt = pn_set_alt;
682*4882a593Smuzhiyun fp->function.get_alt = pn_get_alt;
683*4882a593Smuzhiyun fp->function.disable = pn_disconnect;
684*4882a593Smuzhiyun fp->function.free_func = phonet_free;
685*4882a593Smuzhiyun spin_lock_init(&fp->rx.lock);
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun return &fp->function;
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun
gphonet_setup_default(void)690*4882a593Smuzhiyun struct net_device *gphonet_setup_default(void)
691*4882a593Smuzhiyun {
692*4882a593Smuzhiyun struct net_device *dev;
693*4882a593Smuzhiyun struct phonet_port *port;
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun /* Create net device */
696*4882a593Smuzhiyun dev = alloc_netdev(sizeof(*port), "upnlink%d", NET_NAME_UNKNOWN,
697*4882a593Smuzhiyun pn_net_setup);
698*4882a593Smuzhiyun if (!dev)
699*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun port = netdev_priv(dev);
702*4882a593Smuzhiyun spin_lock_init(&port->lock);
703*4882a593Smuzhiyun netif_carrier_off(dev);
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun return dev;
706*4882a593Smuzhiyun }
707*4882a593Smuzhiyun
gphonet_set_gadget(struct net_device * net,struct usb_gadget * g)708*4882a593Smuzhiyun void gphonet_set_gadget(struct net_device *net, struct usb_gadget *g)
709*4882a593Smuzhiyun {
710*4882a593Smuzhiyun SET_NETDEV_DEV(net, &g->dev);
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun
gphonet_register_netdev(struct net_device * net)713*4882a593Smuzhiyun int gphonet_register_netdev(struct net_device *net)
714*4882a593Smuzhiyun {
715*4882a593Smuzhiyun int status;
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun status = register_netdev(net);
718*4882a593Smuzhiyun if (status)
719*4882a593Smuzhiyun free_netdev(net);
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun return status;
722*4882a593Smuzhiyun }
723*4882a593Smuzhiyun
gphonet_cleanup(struct net_device * dev)724*4882a593Smuzhiyun void gphonet_cleanup(struct net_device *dev)
725*4882a593Smuzhiyun {
726*4882a593Smuzhiyun unregister_netdev(dev);
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun DECLARE_USB_FUNCTION_INIT(phonet, phonet_alloc_inst, phonet_alloc);
730*4882a593Smuzhiyun MODULE_AUTHOR("Rémi Denis-Courmont");
731*4882a593Smuzhiyun MODULE_LICENSE("GPL");
732