Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / staging / rtl8712 / rtl871x_io.c
1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  * rtl871x_io.c
4  *
5  * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
6  * Linux device driver for RTL8192SU
7  *
8  * Modifications for inclusion into the Linux staging tree are
9  * Copyright(c) 2010 Larry Finger. All rights reserved.
10  *
11  * Contact information:
12  * WLAN FAE <wlanfae@realtek.com>
13  * Larry Finger <Larry.Finger@lwfinger.net>
14  *
15  ******************************************************************************/
16 /*
17  *
18  * The purpose of rtl871x_io.c
19  *
20  * a. provides the API
21  * b. provides the protocol engine
22  * c. provides the software interface between caller and the hardware interface
23  *
24  * For r8712u, both sync/async operations are provided.
25  *
26  * Only sync read/write_mem operations are provided.
27  *
28  */
29
30 #define _RTL871X_IO_C_
31
32 #include "osdep_service.h"
33 #include "drv_types.h"
34 #include "rtl871x_io.h"
35 #include "osdep_intf.h"
36 #include "usb_ops.h"
37
38 static uint _init_intf_hdl(struct _adapter *padapter,
39                            struct intf_hdl *pintf_hdl)
40 {
41         struct  intf_priv       *pintf_priv;
42         void (*set_intf_option)(u32 *poption) = NULL;
43         void (*set_intf_funs)(struct intf_hdl *pintf_hdl);
44         void (*set_intf_ops)(struct _io_ops     *pops);
45         uint (*init_intf_priv)(struct intf_priv *pintfpriv);
46
47         set_intf_option = &(r8712_usb_set_intf_option);
48         set_intf_funs = &(r8712_usb_set_intf_funs);
49         set_intf_ops = &r8712_usb_set_intf_ops;
50         init_intf_priv = &r8712_usb_init_intf_priv;
51         pintf_priv = pintf_hdl->pintfpriv = kmalloc(sizeof(struct intf_priv),
52                                                     GFP_ATOMIC);
53         if (pintf_priv == NULL)
54                 goto _init_intf_hdl_fail;
55         pintf_hdl->adapter = (u8 *)padapter;
56         set_intf_option(&pintf_hdl->intf_option);
57         set_intf_funs(pintf_hdl);
58         set_intf_ops(&pintf_hdl->io_ops);
59         pintf_priv->intf_dev = (u8 *)&padapter->dvobjpriv;
60         if (init_intf_priv(pintf_priv) == _FAIL)
61                 goto _init_intf_hdl_fail;
62         return _SUCCESS;
63 _init_intf_hdl_fail:
64         kfree(pintf_priv);
65         return _FAIL;
66 }
67
68 static void _unload_intf_hdl(struct intf_priv *pintfpriv)
69 {
70         void (*unload_intf_priv)(struct intf_priv *pintfpriv);
71
72         unload_intf_priv = &r8712_usb_unload_intf_priv;
73         unload_intf_priv(pintfpriv);
74         kfree(pintfpriv);
75 }
76
77 static uint register_intf_hdl(u8 *dev, struct intf_hdl *pintfhdl)
78 {
79         struct _adapter *adapter = (struct _adapter *)dev;
80
81         pintfhdl->intf_option = 0;
82         pintfhdl->adapter = dev;
83         pintfhdl->intf_dev = (u8 *)&adapter->dvobjpriv;
84         if (!_init_intf_hdl(adapter, pintfhdl))
85                 goto register_intf_hdl_fail;
86         return _SUCCESS;
87 register_intf_hdl_fail:
88         return false;
89 }
90
91 static  void unregister_intf_hdl(struct intf_hdl *pintfhdl)
92 {
93         _unload_intf_hdl(pintfhdl->pintfpriv);
94         memset((u8 *)pintfhdl, 0, sizeof(struct intf_hdl));
95 }
96
97 uint r8712_alloc_io_queue(struct _adapter *adapter)
98 {
99         u32 i;
100         struct io_queue *pio_queue;
101         struct io_req *pio_req;
102
103         pio_queue = kmalloc(sizeof(*pio_queue), GFP_ATOMIC);
104         if (!pio_queue)
105                 goto alloc_io_queue_fail;
106         INIT_LIST_HEAD(&pio_queue->free_ioreqs);
107         INIT_LIST_HEAD(&pio_queue->processing);
108         INIT_LIST_HEAD(&pio_queue->pending);
109         spin_lock_init(&pio_queue->lock);
110         pio_queue->pallocated_free_ioreqs_buf = kzalloc(NUM_IOREQ *
111                                                 (sizeof(struct io_req)) + 4,
112                                                 GFP_ATOMIC);
113         if ((pio_queue->pallocated_free_ioreqs_buf) == NULL)
114                 goto alloc_io_queue_fail;
115         pio_queue->free_ioreqs_buf = pio_queue->pallocated_free_ioreqs_buf + 4
116                         - ((addr_t)(pio_queue->pallocated_free_ioreqs_buf)
117                         & 3);
118         pio_req = (struct io_req *)(pio_queue->free_ioreqs_buf);
119         for (i = 0; i < NUM_IOREQ; i++) {
120                 INIT_LIST_HEAD(&pio_req->list);
121                 list_add_tail(&pio_req->list, &pio_queue->free_ioreqs);
122                 pio_req++;
123         }
124         if ((register_intf_hdl((u8 *)adapter, &pio_queue->intf)) == _FAIL)
125                 goto alloc_io_queue_fail;
126         adapter->pio_queue = pio_queue;
127         return _SUCCESS;
128 alloc_io_queue_fail:
129         if (pio_queue) {
130                 kfree(pio_queue->pallocated_free_ioreqs_buf);
131                 kfree(pio_queue);
132         }
133         adapter->pio_queue = NULL;
134         return _FAIL;
135 }
136
137 void r8712_free_io_queue(struct _adapter *adapter)
138 {
139         struct io_queue *pio_queue = adapter->pio_queue;
140
141         if (pio_queue) {
142                 kfree(pio_queue->pallocated_free_ioreqs_buf);
143                 adapter->pio_queue = NULL;
144                 unregister_intf_hdl(&pio_queue->intf);
145                 kfree(pio_queue);
146         }
147 }