📄 memory_cs.c
字号:
/*====================================================================== A general driver for accessing PCMCIA card memory via Bulk Memory Services. This driver provides the equivalent of /dev/mem for a PCMCIA card's attribute and common memory. It includes character and block device support. memory_cs.c 1.87 2002/06/29 06:27:37 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The initial developer of the original code is David A. Hinds <dahinds@users.sourceforge.net>. Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the terms of the GNU General Public License version 2 (the "GPL"), in which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the GPL. ======================================================================*/#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/major.h>#include <linux/fs.h>#include <linux/ioctl.h>#include <linux/blkpg.h>#include <asm/io.h>#include <asm/system.h>#include <stdarg.h>#include <pcmcia/version.h>#include <pcmcia/cs_types.h>#include <pcmcia/cs.h>#include <pcmcia/bulkmem.h>#include <pcmcia/cistpl.h>#include <pcmcia/ds.h>#include <pcmcia/memory.h>#include <pcmcia/mem_op.h>/* Major device #'s for memory device */static int major_dev = 0;/* Funky stuff for setting up a block device */#define MAJOR_NR major_dev#define DEVICE_NAME "memory"#define DEVICE_REQUEST do_memory_request#define DEVICE_ON(device)#define DEVICE_OFF(device)#define DEVICE_NR(minor) ((minor)>>4)#define IS_DIRECT(minor) (((minor)&8)>>3)#define REGION_AM(minor) (((minor)&4)>>2)#define REGION_NR(minor) ((minor)&7)#define MINOR_NR(dev,dir,attr,rgn) \(((dev)<<4)+((dir)<<3)+((attr)<<2)+(rgn))#include <linux/blk.h>/*====================================================================*//* Module parameters */MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");MODULE_DESCRIPTION("PCMCIA memory card driver");MODULE_LICENSE("Dual MPL/GPL");#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")INT_MODULE_PARM(word_width, 1); /* 1 = 16-bit, 0 = 8-bit */INT_MODULE_PARM(mem_speed, 0); /* access speed, in ns */INT_MODULE_PARM(force_size, 0); /* force SRAM card size? */#ifdef PCMCIA_DEBUGINT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)static char *version ="memory_cs.c 1.87 2002/06/29 06:27:37 (David Hinds)";#else#define DEBUG(n, args...)#endif/*====================================================================*//* Maximum number of separate memory devices we'll allow */#define MAX_DEV 4/* Maximum number of partitions per memory space */#define MAX_PART 4/* Maximum number of outstanding erase requests per socket */#define MAX_ERASE 8/* Sector size -- shouldn't need to change */#define SECTOR_SIZE 512/* Size of the PCMCIA address space: 26 bits = 64 MB */#define HIGH_ADDR 0x4000000static void memory_config(dev_link_t *link);static void memory_release(u_long arg);static int memory_event(event_t event, int priority, event_callback_args_t *args);static dev_link_t *memory_attach(void);static void memory_detach(dev_link_t *);/* Each memory region corresponds to a minor device */typedef struct minor_dev_t { /* For normal regions */ region_info_t region; memory_handle_t handle; int open; u_int offset;} minor_dev_t;typedef struct direct_dev_t { /* For direct access */ int flags; int open; caddr_t Base; u_int Size; u_int cardsize; u_int offset;} direct_dev_t;typedef struct memory_dev_t { dev_link_t link; dev_node_t node; eraseq_handle_t eraseq_handle; eraseq_entry_t eraseq[MAX_ERASE]; wait_queue_head_t erase_pending; direct_dev_t direct; minor_dev_t minor[2*MAX_PART];} memory_dev_t;#define MEM_WRPROT 1static dev_info_t dev_info = "memory_cs";static dev_link_t *dev_table[MAX_DEV] = { NULL, /* ... */ };static int memory_blocksizes[MINOR_NR(MAX_DEV, 0, 0, 0)] ={ 0, /* ... */ }; /*====================================================================*/static int memory_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg);static ssize_t memory_read FOPS(struct inode *inode, struct file *file, char *buf, size_t count, loff_t *ppos);static ssize_t memory_write FOPS(struct inode *inode, struct file *file, const char *buf, size_t count, loff_t *ppos);static int memory_open(struct inode *inode, struct file *file);static FS_RELEASE_T memory_close(struct inode *inode, struct file *file);static FS_RELEASE_T memory_blk_close(struct inode *inode, struct file *file);static struct file_operations memory_chr_fops = { open: memory_open, release: memory_close, read: memory_read, write: memory_write, ioctl: memory_ioctl,};static struct block_device_operations memory_blk_fops = { open: memory_open, release: memory_blk_close, ioctl: memory_ioctl,#ifdef block_device_operations read: block_read, write: block_write, fsync: block_fsync#endif};/*====================================================================*/static void cs_error(client_handle_t handle, int func, int ret){ error_info_t err = { func, ret }; CardServices(ReportError, handle, &err);}/*====================================================================== memory_attach() creates an "instance" of the driver, allocating local data structures for one device. The device is registered with Card Services.======================================================================*/static dev_link_t *memory_attach(void){ memory_dev_t *dev; dev_link_t *link; client_reg_t client_reg; eraseq_hdr_t eraseq_hdr; int i, ret; DEBUG(0, "memory_attach()\n"); for (i = 0; i < MAX_DEV; i++) if (dev_table[i] == NULL) break; if (i == MAX_DEV) { printk(KERN_NOTICE "memory_cs: no devices available\n"); return NULL; } /* Create new memory card device */ dev = kmalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return NULL; memset(dev, 0, sizeof(*dev)); link = &dev->link; link->priv = dev; link->release.function = &memory_release; link->release.data = (u_long)link; dev_table[i] = link; init_waitqueue_head(&dev->erase_pending); /* Register with Card Services */ client_reg.dev_info = &dev_info; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.event_handler = &memory_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = CardServices(RegisterClient, &link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); memory_detach(link); return NULL; } for (i = 0; i < MAX_ERASE; i++) dev->eraseq[i].State = ERASE_IDLE; eraseq_hdr.QueueEntryCnt = MAX_ERASE; eraseq_hdr.QueueEntryArray = dev->eraseq; dev->eraseq_handle = (void *)link->handle; ret = CardServices(RegisterEraseQueue, &dev->eraseq_handle, &eraseq_hdr); if (ret != 0) { cs_error(link->handle, RegisterEraseQueue, ret); dev->eraseq_handle = NULL; memory_detach(link); return NULL; } return link;} /* memory_attach *//*====================================================================== This deletes a driver "instance". The device is de-registered with Card Services. If it has been released, all local data structures are freed. Otherwise, the structures will be freed when the device is released.======================================================================*/static void memory_detach(dev_link_t *link){ memory_dev_t *dev = link->priv; int nd; DEBUG(0, "memory_detach(0x%p)\n", link); /* Verify device address */ for (nd = 0; nd < MAX_DEV; nd++) if (dev_table[nd] == link) break; if (nd == MAX_DEV) return; del_timer(&link->release); if (link->state & DEV_CONFIG) { memory_release((u_long)link); if (link->state & DEV_STALE_CONFIG) { link->state |= DEV_STALE_LINK; return; } } if (dev->eraseq_handle) CardServices(DeregisterEraseQueue, dev->eraseq_handle); if (link->handle) CardServices(DeregisterClient, link->handle); /* Unlink device structure, free bits */ dev_table[nd] = NULL; kfree(dev); } /* memory_detach *//*====================================================================== Figure out the size of a simple SRAM card ======================================================================*/#define WIN_TYPE(a) ((a) ? WIN_MEMORY_TYPE_AM : WIN_MEMORY_TYPE_CM)#define WIN_WIDTH(w) ((w) ? WIN_DATA_WIDTH_16 : WIN_DATA_WIDTH_8)static u_int get_size(dev_link_t *link, direct_dev_t *direct){ modwin_t mod; memreq_t mem; u_char b0, b1; int s, ret; mod.Attributes = WIN_ENABLE | WIN_MEMORY_TYPE_CM; mod.AccessSpeed = mem_speed; ret = CardServices(ModifyWindow, link->win, &mod); if (ret != CS_SUCCESS) cs_error(link->handle, ModifyWindow, ret); /* Look for wrap-around or dead end */ mem.Page = mem.CardOffset = 0; CardServices(MapMemPage, link->win, &mem); b0 = readb(direct->Base); for (s = 12; s < 26; s++) { mem.CardOffset = 1<<s; CardServices(MapMemPage, link->win, &mem); b1 = readb(direct->Base); writeb(~b1, direct->Base); mem.CardOffset = 0; CardServices(MapMemPage, link->win, &mem); if (readb(direct->Base) != b0) { writeb(b0, direct->Base); break; } mem.CardOffset = 1<<s; CardServices(MapMemPage, link->win, &mem); if (readb(direct->Base) != (0xff & ~b1)) break; writeb(b1, direct->Base); } return (s > 15) ? (1<<s) : 0;} /* get_size */static void print_size(u_int sz){ if (sz & 0x03ff) printk("%d bytes", sz); else if (sz & 0x0fffff) printk("%d kb", sz >> 10); else printk("%d mb", sz >> 20);}/*====================================================================== memory_config() is scheduled to run after a CARD_INSERTION event is received, to configure the PCMCIA socket, and to make the ethernet device available to the system. ======================================================================*/#define CS_CHECK(fn, args...) \while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failedstatic void memory_config(dev_link_t *link){ memory_dev_t *dev = link->priv; minor_dev_t *minor; region_info_t region; cs_status_t status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -