ohci-mem.c

来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 247 行

C
247
字号
/* * OHCI HCD (Host Controller Driver) for USB. *  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> *  * This file is licenced under the GPL. * $Id: ohci-mem.c,v 1.3 2002/03/22 16:04:54 dbrownell Exp $ *//*-------------------------------------------------------------------------*//* * There's basically three types of memory: *	- data used only by the HCD ... kmalloc is fine *	- async and periodic schedules, shared by HC and HCD ... these *	  need to use pci_pool or pci_alloc_consistent *	- driver buffers, read/written by HC ... single shot DMA mapped  * * There's also PCI "register" data, which is memory mapped. * No memory seen by this driver is pagable. *//*-------------------------------------------------------------------------*/static struct usb_hcd *ohci_hcd_alloc (void){	struct ohci_hcd *ohci;	ohci = (struct ohci_hcd *) kmalloc (sizeof *ohci, GFP_KERNEL);	if (ohci != 0) {		memset (ohci, 0, sizeof (struct ohci_hcd));		return &ohci->hcd;	}	return 0;}static void ohci_hcd_free (struct usb_hcd *hcd){	kfree (hcd_to_ohci (hcd));}/*-------------------------------------------------------------------------*/#ifndef CONFIG_PCI#	error "usb-ohci currently requires PCI-based controllers"	/* to support non-PCI OHCIs, you need custom bus/mem/... glue */#endif/* Recover a TD/ED using its collision chain */static inline void *dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma){	struct hash_t * scan = entry->head;	while (scan && scan->dma != dma)		scan = scan->next;	return scan->virt;}static struct ed *dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma){	return (struct ed *) dma_to_ed_td(&(hc->ed_hash [ED_HASH_FUNC(ed_dma)]),				      ed_dma);}static struct td *dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma){	td_dma &= TD_MASK;	return (struct td *) dma_to_ed_td(&(hc->td_hash [TD_HASH_FUNC(td_dma)]),				      td_dma);}// FIXME:  when updating the hashtables this way, mem_flags is unusable.../* Add a hash entry for a TD/ED; return true on success */static inthash_add_ed_td (	struct hash_list_t *entry,	void *virt,	dma_addr_t dma,	int mem_flags){	struct hash_t * scan;		scan = (struct hash_t *) kmalloc (sizeof *scan, mem_flags);	if (!scan)		return 0;		if (!entry->tail) {		entry->head = entry->tail = scan;	} else {		entry->tail->next = scan;		entry->tail = scan;	}		scan->virt = virt;	scan->dma = dma;	scan->next = NULL;	return 1;}static inline inthash_add_ed (struct ohci_hcd *hc, struct ed *ed, int mem_flags){	return hash_add_ed_td (&(hc->ed_hash [ED_HASH_FUNC (ed->dma)]),			ed, ed->dma, mem_flags);}static inline inthash_add_td (struct ohci_hcd *hc, struct td *td, int mem_flags){	return hash_add_ed_td (&(hc->td_hash [TD_HASH_FUNC (td->td_dma)]),			td, td->td_dma, mem_flags);}static voidhash_free_ed_td (struct hash_list_t *entry, void *virt){	struct hash_t *scan, *prev;	scan = prev = entry->head;	// Find and unlink hash entry	while (scan && scan->virt != virt) {		prev = scan;		scan = scan->next;	}	if (scan) {		if (scan == entry->head) {			if (entry->head == entry->tail)				entry->head = entry->tail = NULL;			else				entry->head = scan->next;		} else if (scan == entry->tail) {			entry->tail = prev;			prev->next = NULL;		} else			prev->next = scan->next;		kfree(scan);	}}static inline voidhash_free_ed (struct ohci_hcd *hc, struct ed * ed){	hash_free_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]), ed);}static inline voidhash_free_td (struct ohci_hcd *hc, struct td * td){	hash_free_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]), td);}static int ohci_mem_init (struct ohci_hcd *ohci){	ohci->td_cache = pci_pool_create ("ohci_td", ohci->hcd.pdev,		sizeof (struct td),		32 /* byte alignment */,		0 /* no page-crossing issues */,		GFP_KERNEL);	if (!ohci->td_cache)		return -ENOMEM;	ohci->ed_cache = pci_pool_create ("ohci_ed", ohci->hcd.pdev,		sizeof (struct ed),		16 /* byte alignment */,		0 /* no page-crossing issues */,		GFP_KERNEL);	if (!ohci->ed_cache) {		pci_pool_destroy (ohci->td_cache);		return -ENOMEM;	}	return 0;}static void ohci_mem_cleanup (struct ohci_hcd *ohci){	if (ohci->td_cache) {		pci_pool_destroy (ohci->td_cache);		ohci->td_cache = 0;	}	if (ohci->ed_cache) {		pci_pool_destroy (ohci->ed_cache);		ohci->ed_cache = 0;	}}/* TDs ... */static struct td *td_alloc (struct ohci_hcd *hc, int mem_flags){	dma_addr_t	dma;	struct td	*td;	td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);	if (td) {		td->td_dma = dma;		/* hash it for later reverse mapping */		if (!hash_add_td (hc, td, mem_flags)) {			pci_pool_free (hc->td_cache, td, dma);			return NULL;		}	}	return td;}static voidtd_free (struct ohci_hcd *hc, struct td *td){	hash_free_td (hc, td);	pci_pool_free (hc->td_cache, td, td->td_dma);}/* EDs ... */static struct ed *ed_alloc (struct ohci_hcd *hc, int mem_flags){	dma_addr_t	dma;	struct ed	*ed;	ed = pci_pool_alloc (hc->ed_cache, mem_flags, &dma);	if (ed) {		memset (ed, 0, sizeof (*ed));		ed->dma = dma;		/* hash it for later reverse mapping */		if (!hash_add_ed (hc, ed, mem_flags)) {			pci_pool_free (hc->ed_cache, ed, dma);			return NULL;		}	}	return ed;}static voided_free (struct ohci_hcd *hc, struct ed *ed){	hash_free_ed (hc, ed);	pci_pool_free (hc->ed_cache, ed, ed->dma);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?