📄 alauda.c
字号:
}static int popcount8(u8 c){ int ret = 0; for ( ; c; c>>=1) ret += c & 1; return ret;}static int alauda_isbad(struct mtd_info *mtd, loff_t ofs){ u8 oob[16]; int err; err = alauda_read_oob(mtd, ofs, oob); if (err) return err; /* A block is marked bad if two or more bits are zero */ return popcount8(oob[5]) >= 7 ? 0 : 1;}static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ struct alauda *al = mtd->priv; void *bounce_buf; int err, corrected=0, uncorrected=0; bounce_buf = kmalloc(mtd->writesize, GFP_KERNEL); if (!bounce_buf) return -ENOMEM; *retlen = len; while (len) { u8 oob[16]; size_t byte = from & al->bytemask; size_t cplen = min(len, mtd->writesize - byte); err = alauda_read_page(mtd, from, bounce_buf, oob, &corrected, &uncorrected); if (err) goto out; memcpy(buf, bounce_buf + byte, cplen); buf += cplen; from += cplen; len -= cplen; } err = 0; if (corrected) err = -EUCLEAN; if (uncorrected) err = -EBADMSG;out: kfree(bounce_buf); return err;}static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ struct alauda *al = mtd->priv; int err, corrected=0, uncorrected=0; if ((from & al->bytemask) || (len & al->bytemask)) return alauda_bounce_read(mtd, from, len, retlen, buf); *retlen = len; while (len) { u8 oob[16]; err = alauda_read_page(mtd, from, buf, oob, &corrected, &uncorrected); if (err) return err; buf += mtd->writesize; from += mtd->writesize; len -= mtd->writesize; } err = 0; if (corrected) err = -EUCLEAN; if (uncorrected) err = -EBADMSG; return err;}static int alauda_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf){ struct alauda *al = mtd->priv; int err; if ((to & al->bytemask) || (len & al->bytemask)) return -EINVAL; *retlen = len; while (len) { u32 page = (to >> al->card->pageshift) & al->pagemask; u8 oob[16] = { 'h', 'e', 'l', 'l', 'o', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; /* don't write to bad blocks */ if (page == 0) { err = alauda_isbad(mtd, to); if (err) { return -EIO; } } nand_calculate_ecc(mtd, buf, &oob[13]); nand_calculate_ecc(mtd, buf+256, &oob[8]); err = alauda_write_page(mtd, to, (void*)buf, oob); if (err) return err; buf += mtd->writesize; to += mtd->writesize; len -= mtd->writesize; } return 0;}static int __alauda_erase(struct mtd_info *mtd, struct erase_info *instr){ struct alauda *al = mtd->priv; u32 ofs = instr->addr; u32 len = instr->len; int err; if ((ofs & al->blockmask) || (len & al->blockmask)) return -EINVAL; while (len) { /* don't erase bad blocks */ err = alauda_isbad(mtd, ofs); if (err > 0) err = -EIO; if (err < 0) return err; err = alauda_erase_block(mtd, ofs); if (err < 0) return err; ofs += mtd->erasesize; len -= mtd->erasesize; } return 0;}static int alauda_erase(struct mtd_info *mtd, struct erase_info *instr){ int err; err = __alauda_erase(mtd, instr); instr->state = err ? MTD_ERASE_FAILED : MTD_ERASE_DONE; mtd_erase_callback(instr); return err;}static int alauda_init_media(struct alauda *al){ u8 buf[4], *b0=buf, *b1=buf+1; struct alauda_card *card; struct mtd_info *mtd; int err; mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); if (!mtd) return -ENOMEM; for (;;) { err = alauda_get_media_status(al, buf); if (err < 0) goto error; if (*b0 & 0x10) break; msleep(20); } err = alauda_ack_media(al); if (err) goto error; msleep(10); err = alauda_get_media_status(al, buf); if (err < 0) goto error; if (*b0 != 0x14) { /* media not ready */ err = -EIO; goto error; } err = alauda_get_media_signatures(al, buf); if (err < 0) goto error; card = get_card(*b1); if (!card) { printk(KERN_ERR"Alauda: unknown card id %02x\n", *b1); err = -EIO; goto error; } printk(KERN_INFO"pagesize=%x\nerasesize=%x\nsize=%xMiB\n", 1<<card->pageshift, 1<<card->blockshift, 1<<(card->chipshift-20)); al->card = card; al->pagemask = (1 << (card->blockshift - card->pageshift)) - 1; al->bytemask = (1 << card->pageshift) - 1; al->blockmask = (1 << card->blockshift) - 1; mtd->name = "alauda"; mtd->size = 1<<card->chipshift; mtd->erasesize = 1<<card->blockshift; mtd->writesize = 1<<card->pageshift; mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; mtd->read = alauda_read; mtd->write = alauda_write; mtd->erase = alauda_erase; mtd->block_isbad = alauda_isbad; mtd->priv = al; mtd->owner = THIS_MODULE; err = add_mtd_device(mtd); if (err) { err = -ENFILE; goto error; } al->mtd = mtd; alauda_reset(al); /* no clue whether this is necessary */ return 0;error: kfree(mtd); return err;}static int alauda_check_media(struct alauda *al){ u8 buf[2], *b0 = buf, *b1 = buf+1; int err; err = alauda_get_media_status(al, buf); if (err < 0) return err; if ((*b1 & 0x01) == 0) { /* door open */ return -EIO; } if ((*b0 & 0x80) || ((*b0 & 0x1F) == 0x10)) { /* no media ? */ return -EIO; } if (*b0 & 0x08) { /* media change ? */ return alauda_init_media(al); } return 0;}static int alauda_probe(struct usb_interface *interface, const struct usb_device_id *id){ struct alauda *al; struct usb_host_interface *iface; struct usb_endpoint_descriptor *ep, *ep_in=NULL, *ep_out=NULL, *ep_wr=NULL; int i, err = -ENOMEM; al = kzalloc(2*sizeof(*al), GFP_KERNEL); if (!al) goto error; kref_init(&al->kref); usb_set_intfdata(interface, al); al->dev = usb_get_dev(interface_to_usbdev(interface)); al->interface = interface; iface = interface->cur_altsetting; for (i = 0; i < iface->desc.bNumEndpoints; ++i) { ep = &iface->endpoint[i].desc; if (usb_endpoint_is_bulk_in(ep)) { ep_in = ep; } else if (usb_endpoint_is_bulk_out(ep)) { if (i==0) ep_wr = ep; else ep_out = ep; } } err = -EIO; if (!ep_wr || !ep_in || !ep_out) goto error; al->write_out = usb_sndbulkpipe(al->dev, ep_wr->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); al->bulk_in = usb_rcvbulkpipe(al->dev, ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); al->bulk_out = usb_sndbulkpipe(al->dev, ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); /* second device is identical up to now */ memcpy(al+1, al, sizeof(*al)); mutex_init(&al[0].card_mutex); mutex_init(&al[1].card_mutex); al[0].port = ALAUDA_PORT_XD; al[1].port = ALAUDA_PORT_SM; dev_info(&interface->dev, "alauda probed\n"); alauda_check_media(al); alauda_check_media(al+1); return 0;error: if (al) kref_put(&al->kref, alauda_delete); return err;}static void alauda_disconnect(struct usb_interface *interface){ struct alauda *al; al = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); /* FIXME: prevent more I/O from starting */ /* decrement our usage count */ if (al) kref_put(&al->kref, alauda_delete); dev_info(&interface->dev, "alauda gone");}static struct usb_driver alauda_driver = { .name = "alauda", .probe = alauda_probe, .disconnect = alauda_disconnect, .id_table = alauda_table,};static int __init alauda_init(void){ return usb_register(&alauda_driver);}static void __exit alauda_exit(void){ usb_deregister(&alauda_driver);}module_init(alauda_init);module_exit(alauda_exit);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -