12865d42cSLarry Finger /******************************************************************************
22865d42cSLarry Finger  * rtl871x_io.c
32865d42cSLarry Finger  *
42865d42cSLarry Finger  * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
52865d42cSLarry Finger  * Linux device driver for RTL8192SU
62865d42cSLarry Finger  *
72865d42cSLarry Finger  * This program is free software; you can redistribute it and/or modify it
82865d42cSLarry Finger  * under the terms of version 2 of the GNU General Public License as
92865d42cSLarry Finger  * published by the Free Software Foundation.
102865d42cSLarry Finger  *
112865d42cSLarry Finger  * This program is distributed in the hope that it will be useful, but WITHOUT
122865d42cSLarry Finger  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
132865d42cSLarry Finger  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
142865d42cSLarry Finger  * more details.
152865d42cSLarry Finger  *
162865d42cSLarry Finger  * You should have received a copy of the GNU General Public License along with
172865d42cSLarry Finger  * this program; if not, write to the Free Software Foundation, Inc.,
182865d42cSLarry Finger  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
192865d42cSLarry Finger  *
202865d42cSLarry Finger  * Modifications for inclusion into the Linux staging tree are
212865d42cSLarry Finger  * Copyright(c) 2010 Larry Finger. All rights reserved.
222865d42cSLarry Finger  *
232865d42cSLarry Finger  * Contact information:
242865d42cSLarry Finger  * WLAN FAE <wlanfae@realtek.com>
252865d42cSLarry Finger  * Larry Finger <Larry.Finger@lwfinger.net>
262865d42cSLarry Finger  *
272865d42cSLarry Finger  ******************************************************************************/
282865d42cSLarry Finger /*
292865d42cSLarry Finger  *
302865d42cSLarry Finger  * The purpose of rtl871x_io.c
312865d42cSLarry Finger  *
322865d42cSLarry Finger  * a. provides the API
332865d42cSLarry Finger  * b. provides the protocol engine
342865d42cSLarry Finger  * c. provides the software interface between caller and the hardware interface
352865d42cSLarry Finger  *
362865d42cSLarry Finger  * For r8712u, both sync/async operations are provided.
372865d42cSLarry Finger  *
382865d42cSLarry Finger  * Only sync read/write_mem operations are provided.
392865d42cSLarry Finger  *
402865d42cSLarry Finger  */
412865d42cSLarry Finger 
422865d42cSLarry Finger #define _RTL871X_IO_C_
432865d42cSLarry Finger 
442865d42cSLarry Finger #include "osdep_service.h"
452865d42cSLarry Finger #include "drv_types.h"
462865d42cSLarry Finger #include "rtl871x_io.h"
472865d42cSLarry Finger #include "osdep_intf.h"
482865d42cSLarry Finger #include "usb_ops.h"
492865d42cSLarry Finger 
502865d42cSLarry Finger static uint _init_intf_hdl(struct _adapter *padapter,
512865d42cSLarry Finger 			   struct intf_hdl *pintf_hdl)
522865d42cSLarry Finger {
532865d42cSLarry Finger 	struct	intf_priv	*pintf_priv;
542865d42cSLarry Finger 	void (*set_intf_option)(u32 *poption) = NULL;
552865d42cSLarry Finger 	void (*set_intf_funs)(struct intf_hdl *pintf_hdl);
562865d42cSLarry Finger 	void (*set_intf_ops)(struct _io_ops	*pops);
572865d42cSLarry Finger 	uint (*init_intf_priv)(struct intf_priv *pintfpriv);
582865d42cSLarry Finger 
592865d42cSLarry Finger 	set_intf_option = &(r8712_usb_set_intf_option);
602865d42cSLarry Finger 	set_intf_funs = &(r8712_usb_set_intf_funs);
612865d42cSLarry Finger 	set_intf_ops = &r8712_usb_set_intf_ops;
622865d42cSLarry Finger 	init_intf_priv = &r8712_usb_init_intf_priv;
6391d435feSVitaly Osipov 	pintf_priv = pintf_hdl->pintfpriv = kmalloc(sizeof(struct intf_priv),
6491d435feSVitaly Osipov 						    GFP_ATOMIC);
652865d42cSLarry Finger 	if (pintf_priv == NULL)
662865d42cSLarry Finger 		goto _init_intf_hdl_fail;
672865d42cSLarry Finger 	pintf_hdl->adapter = (u8 *)padapter;
682865d42cSLarry Finger 	set_intf_option(&pintf_hdl->intf_option);
692865d42cSLarry Finger 	set_intf_funs(pintf_hdl);
702865d42cSLarry Finger 	set_intf_ops(&pintf_hdl->io_ops);
712865d42cSLarry Finger 	pintf_priv->intf_dev = (u8 *)&(padapter->dvobjpriv);
722865d42cSLarry Finger 	if (init_intf_priv(pintf_priv) == _FAIL)
732865d42cSLarry Finger 		goto _init_intf_hdl_fail;
742865d42cSLarry Finger 	return _SUCCESS;
752865d42cSLarry Finger _init_intf_hdl_fail:
7640083865SAlexander Beregalov 	kfree(pintf_priv);
772865d42cSLarry Finger 	return _FAIL;
782865d42cSLarry Finger }
792865d42cSLarry Finger 
802865d42cSLarry Finger static void _unload_intf_hdl(struct intf_priv *pintfpriv)
812865d42cSLarry Finger {
822865d42cSLarry Finger 	void (*unload_intf_priv)(struct intf_priv *pintfpriv);
832865d42cSLarry Finger 
842865d42cSLarry Finger 	unload_intf_priv = &r8712_usb_unload_intf_priv;
852865d42cSLarry Finger 	unload_intf_priv(pintfpriv);
8640083865SAlexander Beregalov 	kfree(pintfpriv);
872865d42cSLarry Finger }
882865d42cSLarry Finger 
892865d42cSLarry Finger static uint register_intf_hdl(u8 *dev, struct intf_hdl *pintfhdl)
902865d42cSLarry Finger {
912865d42cSLarry Finger 	struct _adapter *adapter = (struct _adapter *)dev;
922865d42cSLarry Finger 
932865d42cSLarry Finger 	pintfhdl->intf_option = 0;
942865d42cSLarry Finger 	pintfhdl->adapter = dev;
952865d42cSLarry Finger 	pintfhdl->intf_dev = (u8 *)&(adapter->dvobjpriv);
962865d42cSLarry Finger 	if (_init_intf_hdl(adapter, pintfhdl) == false)
972865d42cSLarry Finger 		goto register_intf_hdl_fail;
982865d42cSLarry Finger 	return _SUCCESS;
992865d42cSLarry Finger register_intf_hdl_fail:
1002865d42cSLarry Finger 	return false;
1012865d42cSLarry Finger }
1022865d42cSLarry Finger 
1032865d42cSLarry Finger static  void unregister_intf_hdl(struct intf_hdl *pintfhdl)
1042865d42cSLarry Finger {
1052865d42cSLarry Finger 	_unload_intf_hdl(pintfhdl->pintfpriv);
1062865d42cSLarry Finger 	memset((u8 *)pintfhdl, 0, sizeof(struct intf_hdl));
1072865d42cSLarry Finger }
1082865d42cSLarry Finger 
1092865d42cSLarry Finger uint r8712_alloc_io_queue(struct _adapter *adapter)
1102865d42cSLarry Finger {
1112865d42cSLarry Finger 	u32 i;
1122865d42cSLarry Finger 	struct io_queue *pio_queue;
1132865d42cSLarry Finger 	struct io_req *pio_req;
1142865d42cSLarry Finger 
115bd9dc62cSVitaly Osipov 	pio_queue = kmalloc(sizeof(*pio_queue), GFP_ATOMIC);
1162865d42cSLarry Finger 	if (pio_queue == NULL)
1172865d42cSLarry Finger 		goto alloc_io_queue_fail;
1182865d42cSLarry Finger 	_init_listhead(&pio_queue->free_ioreqs);
1192865d42cSLarry Finger 	_init_listhead(&pio_queue->processing);
1202865d42cSLarry Finger 	_init_listhead(&pio_queue->pending);
1212865d42cSLarry Finger 	spin_lock_init(&pio_queue->lock);
12291d435feSVitaly Osipov 	pio_queue->pallocated_free_ioreqs_buf = kmalloc(NUM_IOREQ *
12391d435feSVitaly Osipov 							(sizeof(struct io_req)) + 4,
12491d435feSVitaly Osipov 							GFP_ATOMIC);
1252865d42cSLarry Finger 	if ((pio_queue->pallocated_free_ioreqs_buf) == NULL)
1262865d42cSLarry Finger 		goto alloc_io_queue_fail;
1272865d42cSLarry Finger 	memset(pio_queue->pallocated_free_ioreqs_buf, 0,
1282865d42cSLarry Finger 			(NUM_IOREQ * (sizeof(struct io_req)) + 4));
1292865d42cSLarry Finger 	pio_queue->free_ioreqs_buf = pio_queue->pallocated_free_ioreqs_buf + 4
1302865d42cSLarry Finger 			- ((addr_t)(pio_queue->pallocated_free_ioreqs_buf)
1312865d42cSLarry Finger 			& 3);
1322865d42cSLarry Finger 	pio_req = (struct io_req *)(pio_queue->free_ioreqs_buf);
1332865d42cSLarry Finger 	for (i = 0; i < NUM_IOREQ; i++) {
1342865d42cSLarry Finger 		_init_listhead(&pio_req->list);
1352865d42cSLarry Finger 		list_insert_tail(&pio_req->list, &pio_queue->free_ioreqs);
1362865d42cSLarry Finger 		pio_req++;
1372865d42cSLarry Finger 	}
1382865d42cSLarry Finger 	if ((register_intf_hdl((u8 *)adapter, &(pio_queue->intf))) == _FAIL)
1392865d42cSLarry Finger 		goto alloc_io_queue_fail;
1402865d42cSLarry Finger 	adapter->pio_queue = pio_queue;
1412865d42cSLarry Finger 	return _SUCCESS;
1422865d42cSLarry Finger alloc_io_queue_fail:
1432865d42cSLarry Finger 	if (pio_queue) {
1442865d42cSLarry Finger 		kfree(pio_queue->pallocated_free_ioreqs_buf);
1452865d42cSLarry Finger 		kfree((u8 *)pio_queue);
1462865d42cSLarry Finger 	}
1472865d42cSLarry Finger 	adapter->pio_queue = NULL;
1482865d42cSLarry Finger 	return _FAIL;
1492865d42cSLarry Finger }
1502865d42cSLarry Finger 
1512865d42cSLarry Finger void r8712_free_io_queue(struct _adapter *adapter)
1522865d42cSLarry Finger {
1532865d42cSLarry Finger 	struct io_queue *pio_queue = (struct io_queue *)(adapter->pio_queue);
1542865d42cSLarry Finger 
1552865d42cSLarry Finger 	if (pio_queue) {
1562865d42cSLarry Finger 		kfree(pio_queue->pallocated_free_ioreqs_buf);
1572865d42cSLarry Finger 		adapter->pio_queue = NULL;
1582865d42cSLarry Finger 		unregister_intf_hdl(&pio_queue->intf);
1592865d42cSLarry Finger 		kfree((u8 *)pio_queue);
1602865d42cSLarry Finger 	}
1612865d42cSLarry Finger }
162