Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * Wireless Host Controller (WHC) initialization.
  3  *
  4  * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
  5  *
  6  * This program is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU General Public License version
  8  * 2 as published by the Free Software Foundation.
  9  *
 10  * This program is distributed in the hope that it will be useful,
 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13  * GNU General Public License for more details.
 14  *
 15  * You should have received a copy of the GNU General Public License
 16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 17  */
 18 #include <linux/kernel.h>
 19 #include <linux/dma-mapping.h>
 20 #include <linux/uwb/umc.h>
 21 
 22 #include "../../wusbcore/wusbhc.h"
 23 
 24 #include "whcd.h"
 25 
 26 /*
 27  * Reset the host controller.
 28  */
 29 static void whc_hw_reset(struct whc *whc)
 30 {
 31         le_writel(WUSBCMD_WHCRESET, whc->base + WUSBCMD);
 32         whci_wait_for(&whc->umc->dev, whc->base + WUSBCMD, WUSBCMD_WHCRESET, 0,
 33                       100, "reset");
 34 }
 35 
 36 static void whc_hw_init_di_buf(struct whc *whc)
 37 {
 38         int d;
 39 
 40         /* Disable all entries in the Device Information buffer. */
 41         for (d = 0; d < whc->n_devices; d++)
 42                 whc->di_buf[d].addr_sec_info = WHC_DI_DISABLE;
 43 
 44         le_writeq(whc->di_buf_dma, whc->base + WUSBDEVICEINFOADDR);
 45 }
 46 
 47 static void whc_hw_init_dn_buf(struct whc *whc)
 48 {
 49         /* Clear the Device Notification buffer to ensure the V (valid)
 50          * bits are clear.  */
 51         memset(whc->dn_buf, 0, 4096);
 52 
 53         le_writeq(whc->dn_buf_dma, whc->base + WUSBDNTSBUFADDR);
 54 }
 55 
 56 int whc_init(struct whc *whc)
 57 {
 58         u32 whcsparams;
 59         int ret, i;
 60         resource_size_t start, len;
 61 
 62         spin_lock_init(&whc->lock);
 63         mutex_init(&whc->mutex);
 64         init_waitqueue_head(&whc->cmd_wq);
 65         init_waitqueue_head(&whc->async_list_wq);
 66         init_waitqueue_head(&whc->periodic_list_wq);
 67         whc->workqueue = create_singlethread_workqueue(dev_name(&whc->umc->dev));
 68         if (whc->workqueue == NULL) {
 69                 ret = -ENOMEM;
 70                 goto error;
 71         }
 72         INIT_WORK(&whc->dn_work, whc_dn_work);
 73 
 74         INIT_WORK(&whc->async_work, scan_async_work);
 75         INIT_LIST_HEAD(&whc->async_list);
 76         INIT_LIST_HEAD(&whc->async_removed_list);
 77 
 78         INIT_WORK(&whc->periodic_work, scan_periodic_work);
 79         for (i = 0; i < 5; i++)
 80                 INIT_LIST_HEAD(&whc->periodic_list[i]);
 81         INIT_LIST_HEAD(&whc->periodic_removed_list);
 82 
 83         /* Map HC registers. */
 84         start = whc->umc->resource.start;
 85         len   = whc->umc->resource.end - start + 1;
 86         if (!request_mem_region(start, len, "whci-hc")) {
 87                 dev_err(&whc->umc->dev, "can't request HC region\n");
 88                 ret = -EBUSY;
 89                 goto error;
 90         }
 91         whc->base_phys = start;
 92         whc->base = ioremap(start, len);
 93         if (!whc->base) {
 94                 dev_err(&whc->umc->dev, "ioremap\n");
 95                 ret = -ENOMEM;
 96                 goto error;
 97         }
 98 
 99         whc_hw_reset(whc);
100 
101         /* Read maximum number of devices, keys and MMC IEs. */
102         whcsparams = le_readl(whc->base + WHCSPARAMS);
103         whc->n_devices = WHCSPARAMS_TO_N_DEVICES(whcsparams);
104         whc->n_keys    = WHCSPARAMS_TO_N_KEYS(whcsparams);
105         whc->n_mmc_ies = WHCSPARAMS_TO_N_MMC_IES(whcsparams);
106 
107         dev_dbg(&whc->umc->dev, "N_DEVICES = %d, N_KEYS = %d, N_MMC_IES = %d\n",
108                 whc->n_devices, whc->n_keys, whc->n_mmc_ies);
109 
110         whc->qset_pool = dma_pool_create("qset", &whc->umc->dev,
111                                          sizeof(struct whc_qset), 64, 0);
112         if (whc->qset_pool == NULL) {
113                 ret = -ENOMEM;
114                 goto error;
115         }
116 
117         ret = asl_init(whc);
118         if (ret < 0)
119                 goto error;
120         ret = pzl_init(whc);
121         if (ret < 0)
122                 goto error;
123 
124         /* Allocate and initialize a buffer for generic commands, the
125            Device Information buffer, and the Device Notification
126            buffer. */
127 
128         whc->gen_cmd_buf = dma_alloc_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
129                                               &whc->gen_cmd_buf_dma, GFP_KERNEL);
130         if (whc->gen_cmd_buf == NULL) {
131                 ret = -ENOMEM;
132                 goto error;
133         }
134 
135         whc->dn_buf = dma_alloc_coherent(&whc->umc->dev,
136                                          sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
137                                          &whc->dn_buf_dma, GFP_KERNEL);
138         if (!whc->dn_buf) {
139                 ret = -ENOMEM;
140                 goto error;
141         }
142         whc_hw_init_dn_buf(whc);
143 
144         whc->di_buf = dma_alloc_coherent(&whc->umc->dev,
145                                          sizeof(struct di_buf_entry) * whc->n_devices,
146                                          &whc->di_buf_dma, GFP_KERNEL);
147         if (!whc->di_buf) {
148                 ret = -ENOMEM;
149                 goto error;
150         }
151         whc_hw_init_di_buf(whc);
152 
153         return 0;
154 
155 error:
156         whc_clean_up(whc);
157         return ret;
158 }
159 
160 void whc_clean_up(struct whc *whc)
161 {
162         resource_size_t len;
163 
164         if (whc->di_buf)
165                 dma_free_coherent(&whc->umc->dev, sizeof(struct di_buf_entry) * whc->n_devices,
166                                   whc->di_buf, whc->di_buf_dma);
167         if (whc->dn_buf)
168                 dma_free_coherent(&whc->umc->dev, sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
169                                   whc->dn_buf, whc->dn_buf_dma);
170         if (whc->gen_cmd_buf)
171                 dma_free_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
172                                   whc->gen_cmd_buf, whc->gen_cmd_buf_dma);
173 
174         pzl_clean_up(whc);
175         asl_clean_up(whc);
176 
177         if (whc->qset_pool)
178                 dma_pool_destroy(whc->qset_pool);
179 
180         len   = whc->umc->resource.end - whc->umc->resource.start + 1;
181         if (whc->base)
182                 iounmap(whc->base);
183         if (whc->base_phys)
184                 release_mem_region(whc->base_phys, len);
185 
186         if (whc->workqueue)
187                 destroy_workqueue(whc->workqueue);
188 }
189 
  This page was automatically generated by the LXR engine.