emuadxmg.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /*
  2. **********************************************************************
  3. * emuadxmg.c - Address space manager for emu10k1 driver
  4. * Copyright 1999, 2000 Creative Labs, Inc.
  5. *
  6. **********************************************************************
  7. *
  8. * Date Author Summary of changes
  9. * ---- ------ ------------------
  10. * October 20, 1999 Bertrand Lee base code release
  11. *
  12. **********************************************************************
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License as
  16. * published by the Free Software Foundation; either version 2 of
  17. * the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public
  25. * License along with this program; if not, write to the Free
  26. * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
  27. * USA.
  28. *
  29. **********************************************************************
  30. */
  31. #include "hwaccess.h"
  32. /* Allocates emu address space */
  33. int emu10k1_addxmgr_alloc(u32 size, struct emu10k1_card *card)
  34. {
  35. u16 *pagetable = card->emupagetable;
  36. u16 index = 0;
  37. u16 numpages;
  38. unsigned long flags;
  39. /* Convert bytes to pages */
  40. numpages = (size / EMUPAGESIZE) + ((size % EMUPAGESIZE) ? 1 : 0);
  41. spin_lock_irqsave(&card->lock, flags);
  42. while (index < (MAXPAGES - 1)) {
  43. if (pagetable[index] & 0x8000) {
  44. /* This block of pages is in use, jump to the start of the next block. */
  45. index += (pagetable[index] & 0x7fff);
  46. } else {
  47. /* Found free block */
  48. if (pagetable[index] >= numpages) {
  49. /* Block is large enough */
  50. /* If free block is larger than the block requested
  51. * then adjust the size of the block remaining */
  52. if (pagetable[index] > numpages)
  53. pagetable[index + numpages] = pagetable[index] - numpages;
  54. pagetable[index] = (numpages | 0x8000); /* Mark block as used */
  55. spin_unlock_irqrestore(&card->lock, flags);
  56. return index;
  57. } else {
  58. /* Block too small, jump to the start of the next block */
  59. index += pagetable[index];
  60. }
  61. }
  62. }
  63. spin_unlock_irqrestore(&card->lock, flags);
  64. return -1;
  65. }
  66. /* Frees a previously allocated emu address space. */
  67. void emu10k1_addxmgr_free(struct emu10k1_card *card, int index)
  68. {
  69. u16 *pagetable = card->emupagetable;
  70. u16 origsize = 0;
  71. unsigned long flags;
  72. spin_lock_irqsave(&card->lock, flags);
  73. if (pagetable[index] & 0x8000) {
  74. /* Block is allocated - mark block as free */
  75. origsize = pagetable[index] & 0x7fff;
  76. pagetable[index] = origsize;
  77. /* If next block is free, we concat both blocks */
  78. if (!(pagetable[index + origsize] & 0x8000))
  79. pagetable[index] += pagetable[index + origsize] & 0x7fff;
  80. }
  81. spin_unlock_irqrestore(&card->lock, flags);
  82. return;
  83. }