You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dp83820flash.c 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /*
  2. Kernel module for the dp83820 flash write utility. This code was written
  3. by Dave Ashley for NXTV, Inc.
  4. Copyright 2004 by NXTV, Inc.
  5. Written 20040219 by Dave Ashley.
  6. This code is released under the terms of the GPL. No warranty.
  7. THEORY: The dp83820 bootrom interface is flawed in that you can't
  8. read or write a single byte at a time, and this is required in order
  9. to write to flash devices like the AT29C512. So the workaround is
  10. to use the chips ability to map into memory the bootrom, then the cpu
  11. can directly do byte accesses.
  12. The problem is that a "feature" of the dp83820 is that when you map
  13. in the bootrom, you conveniently lose access to the PCI registers.
  14. So we need to do this in kernel space and wrap every access to the
  15. bootrom within interrupt_disable/restore, in case a network interrupt
  16. were to come in.
  17. This kernel module is very simple, it just creates a proc file
  18. /proc/dp83820
  19. If you write 3 bytes to this file you are doing a write to the flashrom:
  20. Byte 1 2 3
  21. ALOW AHIGH DATA
  22. If you write 2 bytes to this file you are doing a read from the flashrom:
  23. Byte 1 2
  24. ALOW AHIGH
  25. Then the next read from the file will return a single byte of what
  26. was at that location.
  27. You only get one shot at accessing the proc file, you need to then
  28. close/open if you want to do another access. This could probably be
  29. cleaned up pretty easily so more accesses can be done without having
  30. to close/open the file.
  31. */
  32. #include <linux/config.h>
  33. #include <linux/kernel.h>
  34. #include <linux/sched.h>
  35. #include <linux/errno.h>
  36. #include <linux/ioport.h>
  37. #include <linux/interrupt.h>
  38. #include <linux/pci.h>
  39. #include <linux/spinlock.h>
  40. #include <linux/proc_fs.h>
  41. #include <linux/module.h>
  42. #define PROCNAME "dp83820"
  43. struct pci_dev *mydev=0;
  44. unsigned long loc;
  45. unsigned char *addr=0;
  46. unsigned char lastread;
  47. int my_read_proc(char *buf, char **start,off_t offset,int count, int *eof,void *data)
  48. {
  49. int retval=0;
  50. if(count>0)
  51. {
  52. buf[0]=lastread;
  53. retval=1;
  54. }
  55. *eof=1;
  56. return retval;
  57. }
  58. int my_write_proc(struct file *file, const char *buffer, unsigned long count,
  59. void *data)
  60. {
  61. unsigned char *msg;
  62. unsigned long flags;
  63. msg=(void *)buffer;
  64. save_flags(flags);
  65. cli();
  66. pci_write_config_dword(mydev, 0x30, loc | 1);
  67. switch(count)
  68. {
  69. case 2:
  70. lastread=addr[msg[0] | (msg[1]<<8)];
  71. break;
  72. case 3:
  73. addr[msg[0] | (msg[1]<<8)] = msg[2];
  74. break;
  75. }
  76. pci_write_config_dword(mydev, 0x30, loc);
  77. restore_flags(flags);
  78. return count;
  79. }
  80. struct proc_dir_entry *de=0;
  81. int __init init_module(void)
  82. {
  83. int found=0;
  84. mydev=0;
  85. pci_for_each_dev(mydev)
  86. {
  87. if(mydev->vendor==0x100b && mydev->device==0x0022)
  88. {
  89. found=1;
  90. break;
  91. }
  92. }
  93. if(!found)
  94. {
  95. printk("Could not find DP83820 network device\n");
  96. return ENODEV;
  97. }
  98. de=create_proc_entry(PROCNAME,0,0);
  99. if(!de)
  100. return -1;
  101. de->data=0;
  102. de->read_proc=my_read_proc;
  103. de->write_proc=my_write_proc;
  104. loc=mydev->resource[PCI_ROM_RESOURCE].start;
  105. addr=ioremap_nocache(loc,0x10000);
  106. return 0;
  107. }
  108. void cleanup_module(void)
  109. {
  110. if(de)
  111. {
  112. remove_proc_entry(PROCNAME,0);
  113. de=0;
  114. }
  115. if(addr)
  116. {
  117. iounmap(addr);
  118. addr=0;
  119. }
  120. }